diff options
| author | John Estabrook <jestabro@vyos.io> | 2025-12-18 12:36:56 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-18 12:36:56 -0600 |
| commit | 0f36d5a2650238d3bbd2b5837ec51fc0c01962aa (patch) | |
| tree | c1c340dc190d2595cc1e1ec8447f163ce56610b2 /src | |
| parent | f6c35930530cc72794a3f7c7488422ccb604b7fd (diff) | |
| parent | f58bfaa3487ef821466e35fbd2bb073732e889dd (diff) | |
| download | vyconf-0f36d5a2650238d3bbd2b5837ec51fc0c01962aa.tar.gz vyconf-0f36d5a2650238d3bbd2b5837ec51fc0c01962aa.zip | |
Merge pull request #39 from jestabro/vyconf-completion-env
T8061: Add requests of analogues of cli-shell-api completion functions
Diffstat (limited to 'src')
| -rw-r--r-- | src/session.ml | 20 | ||||
| -rw-r--r-- | src/session.mli | 6 | ||||
| -rw-r--r-- | src/vyconf_cli_compat.ml | 15 | ||||
| -rw-r--r-- | src/vyconf_client.ml | 25 | ||||
| -rw-r--r-- | src/vyconf_client.mli | 6 | ||||
| -rw-r--r-- | src/vyconf_pbt.ml | 200 | ||||
| -rw-r--r-- | src/vyconf_pbt.mli | 64 | ||||
| -rw-r--r-- | src/vyconfd.ml | 30 |
8 files changed, 365 insertions, 1 deletions
diff --git a/src/session.ml b/src/session.ml index 478c423..0bd3d95 100644 --- a/src/session.ml +++ b/src/session.ml @@ -391,6 +391,26 @@ let config_unsaved w s file id = with Session_error _ -> true (* false positive on unlikely error *) in remove_file tmp_save; res +let reference_path_exists w _s path = + RT.reference_path_exists w.reference_tree path + +let get_path_type ?(legacy_format=false) w _s path = + RT.get_path_type_str ~legacy_format w.reference_tree path + +let get_completion_env ?(legacy_format=false) w s path = + let op, path = + match path with + | [] -> raise (Session_error "Missing op and path") + | h :: tl -> (h, tl) + in + let config = get_proposed_config w s in + let res = + Vyos1x.Completion.get_completion_env_str ~legacy_format w.reference_tree config op path + in + match res with + | Ok env -> env + | Error e -> raise (Session_error e) + let write_running_cache w = (* alert exn Internal.write_internal: [Internal.Write_error] caught diff --git a/src/session.mli b/src/session.mli index cb49bf6..9711402 100644 --- a/src/session.mli +++ b/src/session.mli @@ -94,3 +94,9 @@ val get_config : world -> session_data -> string -> string val cleanup_config : world -> string -> unit val show_config : world -> session_data -> string list -> string + +val reference_path_exists : world -> session_data -> string list -> bool + +val get_path_type : ?legacy_format:bool -> world -> session_data -> string list -> string + +val get_completion_env : ?legacy_format:bool -> world -> session_data -> string list -> string diff --git a/src/vyconf_cli_compat.ml b/src/vyconf_cli_compat.ml index 6ebd1f1..eb14136 100644 --- a/src/vyconf_cli_compat.ml +++ b/src/vyconf_cli_compat.ml @@ -10,6 +10,9 @@ type op_t = | OpShowConfig | OpSessionChanged | OpConfigUnsaved + | OpReferencePathExists + | OpGetPathType + | OpGetCompletionEnv let op_of_arg s = match s with @@ -21,6 +24,9 @@ let op_of_arg s = | "showCfg" -> OpShowConfig | "sessionChanged" -> OpSessionChanged | "sessionUnsaved" -> OpConfigUnsaved + | "validateTmplPath" -> OpReferencePathExists + | "getNodeType" -> OpGetPathType + | "getCompletionEnv" -> OpGetCompletionEnv | _ -> failwith (Printf.sprintf "Unknown operation %s" s) let in_cli_config_session () = @@ -91,6 +97,9 @@ let main op path = | OpShowConfig -> show_config c path | OpSessionChanged -> session_changed c | OpConfigUnsaved -> config_unsaved c None + | OpReferencePathExists -> reference_path_exists c path + | OpGetPathType -> get_path_type c path + | OpGetCompletionEnv -> get_completion_env c path end | Error e -> Error e |> Lwt.return in @@ -128,7 +137,11 @@ let () = with Failure msg -> let () = print_endline msg in exit 1 in match op, path_list with - | OpSetEditLevel, [] -> + | OpSetEditLevel, [] + | OpReferencePathExists, [] + | OpGetPathType, [] -> let () = print_endline "Must specify config path" in exit 1 + | OpGetCompletionEnv, [] | OpGetCompletionEnv, [_] -> + let () = print_endline "Must specify command and at least one component" in exit 1 | _, _ -> let result = Lwt_main.run (main op path_list) in exit result diff --git a/src/vyconf_client.ml b/src/vyconf_client.ml index 76b6680..6b6c6f1 100644 --- a/src/vyconf_client.ml +++ b/src/vyconf_client.ml @@ -229,3 +229,28 @@ let config_unsaved client file = | Success -> Lwt.return (Ok "") | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return + +let reference_path_exists client path = + let req = Reference_path_exists {path=path;} 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 + +let get_path_type client path = + let req = Get_path_type {path=path; legacy_format=true;} 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_completion_env client path = + let req = Get_completion_env {path=path; legacy_format=true;} in + let%lwt resp = do_request client req in + match resp.status with + | Success -> unwrap resp.output |> Lwt.return + (* legacy getCompletionEnv is silent on error *) + | Fail -> Error "" |> Lwt.return + | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return diff --git a/src/vyconf_client.mli b/src/vyconf_client.mli index a3744d7..3ee1083 100644 --- a/src/vyconf_client.mli +++ b/src/vyconf_client.mli @@ -49,3 +49,9 @@ 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 + +val reference_path_exists : t -> string list -> (string, string) result Lwt.t + +val get_path_type : t -> string list -> (string, string) result Lwt.t + +val get_completion_env : t -> string list -> (string, string) result Lwt.t diff --git a/src/vyconf_pbt.ml b/src/vyconf_pbt.ml index 85eb4e3..939af0c 100644 --- a/src/vyconf_pbt.ml +++ b/src/vyconf_pbt.ml @@ -183,6 +183,20 @@ type request_config_unsaved = { file : string option; } +type request_reference_path_exists = { + path : string list; +} + +type request_get_path_type = { + path : string list; + legacy_format : bool; +} + +type request_get_completion_env = { + path : string list; + legacy_format : bool; +} + type request = | Prompt | Setup_session of request_setup_session @@ -222,6 +236,9 @@ type request = | Get_edit_level of request_get_edit_level | Edit_level_root of request_edit_level_root | Config_unsaved of request_config_unsaved + | Reference_path_exists of request_reference_path_exists + | Get_path_type of request_get_path_type + | Get_completion_env of request_get_completion_env type request_envelope = { token : string option; @@ -525,6 +542,28 @@ let rec default_request_config_unsaved file; } +let rec default_request_reference_path_exists + ?path:((path:string list) = []) + () : request_reference_path_exists = { + path; +} + +let rec default_request_get_path_type + ?path:((path:string list) = []) + ?legacy_format:((legacy_format:bool) = false) + () : request_get_path_type = { + path; + legacy_format; +} + +let rec default_request_get_completion_env + ?path:((path:string list) = []) + ?legacy_format:((legacy_format:bool) = false) + () : request_get_completion_env = { + path; + legacy_format; +} + let rec default_request (): request = Prompt let rec default_request_envelope @@ -887,6 +926,34 @@ let default_request_config_unsaved_mutable () : request_config_unsaved_mutable = file = None; } +type request_reference_path_exists_mutable = { + mutable path : string list; +} + +let default_request_reference_path_exists_mutable () : request_reference_path_exists_mutable = { + path = []; +} + +type request_get_path_type_mutable = { + mutable path : string list; + mutable legacy_format : bool; +} + +let default_request_get_path_type_mutable () : request_get_path_type_mutable = { + path = []; + legacy_format = false; +} + +type request_get_completion_env_mutable = { + mutable path : string list; + mutable legacy_format : bool; +} + +let default_request_get_completion_env_mutable () : request_get_completion_env_mutable = { + path = []; + legacy_format = false; +} + type request_envelope_mutable = { mutable token : string option; mutable request : request; @@ -1182,6 +1249,26 @@ let rec pp_request_config_unsaved fmt (v:request_config_unsaved) = in Pbrt.Pp.pp_brk pp_i fmt () +let rec pp_request_reference_path_exists fmt (v:request_reference_path_exists) = + 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_get_path_type fmt (v:request_get_path_type) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "path" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.path; + Pbrt.Pp.pp_record_field ~first:false "legacy_format" Pbrt.Pp.pp_bool fmt v.legacy_format; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_request_get_completion_env fmt (v:request_get_completion_env) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "path" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.path; + Pbrt.Pp.pp_record_field ~first:false "legacy_format" Pbrt.Pp.pp_bool fmt v.legacy_format; + in + Pbrt.Pp.pp_brk pp_i fmt () + let rec pp_request fmt (v:request) = match v with | Prompt -> Format.fprintf fmt "Prompt" @@ -1222,6 +1309,9 @@ let rec pp_request fmt (v:request) = | Get_edit_level x -> Format.fprintf fmt "@[<hv2>Get_edit_level(@,%a)@]" pp_request_get_edit_level x | Edit_level_root x -> Format.fprintf fmt "@[<hv2>Edit_level_root(@,%a)@]" pp_request_edit_level_root x | Config_unsaved x -> Format.fprintf fmt "@[<hv2>Config_unsaved(@,%a)@]" pp_request_config_unsaved x + | Reference_path_exists x -> Format.fprintf fmt "@[<hv2>Reference_path_exists(@,%a)@]" pp_request_reference_path_exists x + | Get_path_type x -> Format.fprintf fmt "@[<hv2>Get_path_type(@,%a)@]" pp_request_get_path_type x + | Get_completion_env x -> Format.fprintf fmt "@[<hv2>Get_completion_env(@,%a)@]" pp_request_get_completion_env x let rec pp_request_envelope fmt (v:request_envelope) = let pp_i fmt () = @@ -1658,6 +1748,31 @@ let rec encode_pb_request_config_unsaved (v:request_config_unsaved) encoder = end; () +let rec encode_pb_request_reference_path_exists (v:request_reference_path_exists) 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_get_path_type (v:request_get_path_type) 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; + Pbrt.Encoder.bool v.legacy_format encoder; + Pbrt.Encoder.key 2 Pbrt.Varint encoder; + () + +let rec encode_pb_request_get_completion_env (v:request_get_completion_env) 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; + Pbrt.Encoder.bool v.legacy_format encoder; + Pbrt.Encoder.key 2 Pbrt.Varint encoder; + () + let rec encode_pb_request (v:request) encoder = begin match v with | Prompt -> @@ -1774,6 +1889,15 @@ let rec encode_pb_request (v:request) encoder = | Config_unsaved x -> Pbrt.Encoder.nested encode_pb_request_config_unsaved x encoder; Pbrt.Encoder.key 38 Pbrt.Bytes encoder; + | Reference_path_exists x -> + Pbrt.Encoder.nested encode_pb_request_reference_path_exists x encoder; + Pbrt.Encoder.key 39 Pbrt.Bytes encoder; + | Get_path_type x -> + Pbrt.Encoder.nested encode_pb_request_get_path_type x encoder; + Pbrt.Encoder.key 40 Pbrt.Bytes encoder; + | Get_completion_env x -> + Pbrt.Encoder.nested encode_pb_request_get_completion_env x encoder; + Pbrt.Encoder.key 41 Pbrt.Bytes encoder; end let rec encode_pb_request_envelope (v:request_envelope) encoder = @@ -2714,6 +2838,79 @@ let rec decode_pb_request_config_unsaved d = file = v.file; } : request_config_unsaved) +let rec decode_pb_request_reference_path_exists d = + let v = default_request_reference_path_exists_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_reference_path_exists), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + path = v.path; + } : request_reference_path_exists) + +let rec decode_pb_request_get_path_type d = + let v = default_request_get_path_type_mutable () in + let continue__= ref true in + let legacy_format_is_set = ref false 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_get_path_type), field(1)" pk + | Some (2, Pbrt.Varint) -> begin + v.legacy_format <- Pbrt.Decoder.bool d; legacy_format_is_set := true; + end + | Some (2, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_get_path_type), field(2)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + begin if not !legacy_format_is_set then Pbrt.Decoder.missing_field "legacy_format" end; + ({ + path = v.path; + legacy_format = v.legacy_format; + } : request_get_path_type) + +let rec decode_pb_request_get_completion_env d = + let v = default_request_get_completion_env_mutable () in + let continue__= ref true in + let legacy_format_is_set = ref false 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_get_completion_env), field(1)" pk + | Some (2, Pbrt.Varint) -> begin + v.legacy_format <- Pbrt.Decoder.bool d; legacy_format_is_set := true; + end + | Some (2, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_get_completion_env), field(2)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + begin if not !legacy_format_is_set then Pbrt.Decoder.missing_field "legacy_format" end; + ({ + path = v.path; + legacy_format = v.legacy_format; + } : request_get_completion_env) + let rec decode_pb_request d = let rec loop () = let ret:request = match Pbrt.Decoder.key d with @@ -2765,6 +2962,9 @@ let rec decode_pb_request d = | 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 (39, _) -> (Reference_path_exists (decode_pb_request_reference_path_exists (Pbrt.Decoder.nested d)) : request) + | Some (40, _) -> (Get_path_type (decode_pb_request_get_path_type (Pbrt.Decoder.nested d)) : request) + | Some (41, _) -> (Get_completion_env (decode_pb_request_get_completion_env (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 285abfb..2558dc0 100644 --- a/src/vyconf_pbt.mli +++ b/src/vyconf_pbt.mli @@ -190,6 +190,20 @@ type request_config_unsaved = { file : string option; } +type request_reference_path_exists = { + path : string list; +} + +type request_get_path_type = { + path : string list; + legacy_format : bool; +} + +type request_get_completion_env = { + path : string list; + legacy_format : bool; +} + type request = | Prompt | Setup_session of request_setup_session @@ -229,6 +243,9 @@ type request = | Get_edit_level of request_get_edit_level | Edit_level_root of request_edit_level_root | Config_unsaved of request_config_unsaved + | Reference_path_exists of request_reference_path_exists + | Get_path_type of request_get_path_type + | Get_completion_env of request_get_completion_env type request_envelope = { token : string option; @@ -511,6 +528,26 @@ val default_request_config_unsaved : request_config_unsaved (** [default_request_config_unsaved ()] is the default value for type [request_config_unsaved] *) +val default_request_reference_path_exists : + ?path:string list -> + unit -> + request_reference_path_exists +(** [default_request_reference_path_exists ()] is the default value for type [request_reference_path_exists] *) + +val default_request_get_path_type : + ?path:string list -> + ?legacy_format:bool -> + unit -> + request_get_path_type +(** [default_request_get_path_type ()] is the default value for type [request_get_path_type] *) + +val default_request_get_completion_env : + ?path:string list -> + ?legacy_format:bool -> + unit -> + request_get_completion_env +(** [default_request_get_completion_env ()] is the default value for type [request_get_completion_env] *) + val default_request : unit -> request (** [default_request ()] is the default value for type [request] *) @@ -656,6 +693,15 @@ val pp_request_edit_level_root : Format.formatter -> request_edit_level_root -> val pp_request_config_unsaved : Format.formatter -> request_config_unsaved -> unit (** [pp_request_config_unsaved v] formats v *) +val pp_request_reference_path_exists : Format.formatter -> request_reference_path_exists -> unit +(** [pp_request_reference_path_exists v] formats v *) + +val pp_request_get_path_type : Format.formatter -> request_get_path_type -> unit +(** [pp_request_get_path_type v] formats v *) + +val pp_request_get_completion_env : Format.formatter -> request_get_completion_env -> unit +(** [pp_request_get_completion_env v] formats v *) + val pp_request : Format.formatter -> request -> unit (** [pp_request v] formats v *) @@ -791,6 +837,15 @@ val encode_pb_request_edit_level_root : request_edit_level_root -> Pbrt.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_reference_path_exists : request_reference_path_exists -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_reference_path_exists v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_request_get_path_type : request_get_path_type -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_get_path_type v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_request_get_completion_env : request_get_completion_env -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_get_completion_env 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] *) @@ -926,6 +981,15 @@ val decode_pb_request_edit_level_root : Pbrt.Decoder.t -> request_edit_level_roo 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_reference_path_exists : Pbrt.Decoder.t -> request_reference_path_exists +(** [decode_pb_request_reference_path_exists decoder] decodes a [request_reference_path_exists] binary value from [decoder] *) + +val decode_pb_request_get_path_type : Pbrt.Decoder.t -> request_get_path_type +(** [decode_pb_request_get_path_type decoder] decodes a [request_get_path_type] binary value from [decoder] *) + +val decode_pb_request_get_completion_env : Pbrt.Decoder.t -> request_get_completion_env +(** [decode_pb_request_get_completion_env decoder] decodes a [request_get_completion_env] binary value from [decoder] *) + val decode_pb_request : Pbrt.Decoder.t -> request (** [decode_pb_request decoder] decodes a [request] binary value from [decoder] *) diff --git a/src/vyconfd.ml b/src/vyconfd.ml index dc302e5..d34deab 100644 --- a/src/vyconfd.ml +++ b/src/vyconfd.ml @@ -417,6 +417,33 @@ let config_unsaved world token (req: request_config_unsaved) = then response_tmpl else {response_tmpl with status=Fail} +let reference_path_exists world token (req: request_reference_path_exists) = + let path = req.path in + if Session.reference_path_exists world (find_session token) path + then response_tmpl + else {response_tmpl with status=Fail} + +let get_path_type world token (req: request_get_path_type) = + let s = find_session token in + try + let node_type = + Session.get_path_type ~legacy_format:req.legacy_format world s req.path + in + {response_tmpl with output=(Some node_type)} + with Session.Session_error msg -> + {response_tmpl with status=Fail; error=(Some msg)} + +let get_completion_env world token (req: request_get_completion_env) = + let s = find_session token in + try + let node_type = + Session.get_completion_env + ~legacy_format:req.legacy_format world s req.path + in + {response_tmpl with output=(Some node_type)} + with Session.Session_error msg -> + {response_tmpl with status=Fail; error=(Some msg)} + let send_response oc resp = let enc = Pbrt.Encoder.create () in let%lwt () = encode_pb_response resp enc |> return in @@ -474,6 +501,9 @@ let rec handle_connection world ic oc () = | 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 + | Some t, Reference_path_exists r -> reference_path_exists world t r + | Some t, Get_path_type r -> get_path_type world t r + | Some t, Get_completion_env r -> get_completion_env world t r | _ -> failwith "Unimplemented" ) |> Lwt.return end |
