summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2025-06-24 07:07:09 -0500
committerJohn Estabrook <jestabro@vyos.io>2025-07-06 18:27:40 -0500
commit59ebae9198439ddd1e9bbdec61d163f638e1071a (patch)
tree119133764b05a6cd1a5a182c555044b2170f4a17
parent1e4f661b8c29edf0b03eac4adf032735d6a885a7 (diff)
downloadvyconf-59ebae9198439ddd1e9bbdec61d163f638e1071a.tar.gz
vyconf-59ebae9198439ddd1e9bbdec61d163f638e1071a.zip
T7499: use direct request to vyconfd to avoid re-validating paths
Merging before passing to the backend results in re-validation of existing paths in the proposed config; this is unavoidable with the legacy backend. For vyconf, send the merge proposal with the request, so validation is only required on new paths.
-rw-r--r--data/vyconf.proto3
-rw-r--r--src/session.ml10
-rw-r--r--src/session.mli2
-rw-r--r--src/vyconf_pbt.ml20
-rw-r--r--src/vyconf_pbt.mli2
-rw-r--r--src/vyconfd.ml9
6 files changed, 43 insertions, 3 deletions
diff --git a/data/vyconf.proto b/data/vyconf.proto
index 4466837..30f95aa 100644
--- a/data/vyconf.proto
+++ b/data/vyconf.proto
@@ -91,7 +91,8 @@ message Request {
message Merge {
required string Location = 1;
- optional ConfigFormat format = 2;
+ required bool destructive = 2;
+ optional ConfigFormat format = 3;
}
message Save {
diff --git a/src/session.ml b/src/session.ml
index 72e766d..5e276c2 100644
--- a/src/session.ml
+++ b/src/session.ml
@@ -142,6 +142,16 @@ let load w s file cached =
| Ok config ->
validate_tree w config; {s with proposed_config=config;}
+let merge w s file destructive =
+ let ct = Vyos1x.Config_file.load_config file in
+ match ct with
+ | Error e -> raise (Session_error (Printf.sprintf "Error loading config: %s" e))
+ | Ok config ->
+ let () = validate_tree w config in
+ let merged = CD.tree_merge ~destructive:destructive s.proposed_config config
+ in
+ {s with proposed_config=merged;}
+
let save w s file =
let ct = w.running_config in
let res = Vyos1x.Config_file.save_config ct file in
diff --git a/src/session.mli b/src/session.mli
index 0398bb1..1a9b79f 100644
--- a/src/session.mli
+++ b/src/session.mli
@@ -39,6 +39,8 @@ val session_changed : world -> session_data -> bool
val load : world -> session_data -> string -> bool -> session_data
+val merge : world -> session_data -> string -> bool -> session_data
+
val save : world -> session_data -> string -> session_data
val get_value : world -> session_data -> string list -> string
diff --git a/src/vyconf_pbt.ml b/src/vyconf_pbt.ml
index facf9f5..913fcea 100644
--- a/src/vyconf_pbt.ml
+++ b/src/vyconf_pbt.ml
@@ -89,6 +89,7 @@ type request_load = {
type request_merge = {
location : string;
+ destructive : bool;
format : request_config_format option;
}
@@ -324,9 +325,11 @@ let rec default_request_load
let rec default_request_merge
?location:((location:string) = "")
+ ?destructive:((destructive:bool) = false)
?format:((format:request_config_format option) = None)
() : request_merge = {
location;
+ destructive;
format;
}
@@ -582,11 +585,13 @@ let default_request_load_mutable () : request_load_mutable = {
type request_merge_mutable = {
mutable location : string;
+ mutable destructive : bool;
mutable format : request_config_format option;
}
let default_request_merge_mutable () : request_merge_mutable = {
location = "";
+ destructive = false;
format = None;
}
@@ -832,6 +837,7 @@ let rec pp_request_load fmt (v:request_load) =
let rec pp_request_merge fmt (v:request_merge) =
let pp_i fmt () =
Pbrt.Pp.pp_record_field ~first:true "location" Pbrt.Pp.pp_string fmt v.location;
+ Pbrt.Pp.pp_record_field ~first:false "destructive" Pbrt.Pp.pp_bool fmt v.destructive;
Pbrt.Pp.pp_record_field ~first:false "format" (Pbrt.Pp.pp_option pp_request_config_format) fmt v.format;
in
Pbrt.Pp.pp_brk pp_i fmt ()
@@ -1156,10 +1162,12 @@ let rec encode_pb_request_load (v:request_load) encoder =
let rec encode_pb_request_merge (v:request_merge) encoder =
Pbrt.Encoder.string v.location encoder;
Pbrt.Encoder.key 1 Pbrt.Bytes encoder;
+ Pbrt.Encoder.bool v.destructive encoder;
+ Pbrt.Encoder.key 2 Pbrt.Varint encoder;
begin match v.format with
| Some x ->
encode_pb_request_config_format x encoder;
- Pbrt.Encoder.key 2 Pbrt.Varint encoder;
+ Pbrt.Encoder.key 3 Pbrt.Varint encoder;
| None -> ();
end;
()
@@ -1826,6 +1834,7 @@ let rec decode_pb_request_load d =
let rec decode_pb_request_merge d =
let v = default_request_merge_mutable () in
let continue__= ref true in
+ let destructive_is_set = ref false in
let location_is_set = ref false in
while !continue__ do
match Pbrt.Decoder.key d with
@@ -1837,15 +1846,22 @@ let rec decode_pb_request_merge d =
| Some (1, pk) ->
Pbrt.Decoder.unexpected_payload "Message(request_merge), field(1)" pk
| Some (2, Pbrt.Varint) -> begin
- v.format <- Some (decode_pb_request_config_format d);
+ v.destructive <- Pbrt.Decoder.bool d; destructive_is_set := true;
end
| Some (2, pk) ->
Pbrt.Decoder.unexpected_payload "Message(request_merge), field(2)" pk
+ | Some (3, Pbrt.Varint) -> begin
+ v.format <- Some (decode_pb_request_config_format d);
+ end
+ | Some (3, pk) ->
+ Pbrt.Decoder.unexpected_payload "Message(request_merge), field(3)" pk
| Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind
done;
+ begin if not !destructive_is_set then Pbrt.Decoder.missing_field "destructive" end;
begin if not !location_is_set then Pbrt.Decoder.missing_field "location" end;
({
location = v.location;
+ destructive = v.destructive;
format = v.format;
} : request_merge)
diff --git a/src/vyconf_pbt.mli b/src/vyconf_pbt.mli
index 42a4af6..c9a7530 100644
--- a/src/vyconf_pbt.mli
+++ b/src/vyconf_pbt.mli
@@ -96,6 +96,7 @@ type request_load = {
type request_merge = {
location : string;
+ destructive : bool;
format : request_config_format option;
}
@@ -324,6 +325,7 @@ val default_request_load :
val default_request_merge :
?location:string ->
+ ?destructive:bool ->
?format:request_config_format option ->
unit ->
request_merge
diff --git a/src/vyconfd.ml b/src/vyconfd.ml
index 379a55e..a0be019 100644
--- a/src/vyconfd.ml
+++ b/src/vyconfd.ml
@@ -223,6 +223,14 @@ let load world token (req: request_load) =
response_tmpl
with Session.Session_error msg -> {response_tmpl with status=Fail; error=(Some msg)}
+let merge world token (req: request_merge) =
+ try
+ let session = Session.merge world (find_session token) req.location req.destructive
+ in
+ Hashtbl.replace sessions token session;
+ response_tmpl
+ with Session.Session_error msg -> {response_tmpl with status=Fail; error=(Some msg)}
+
let save world token (req: request_save) =
try
let _ = Session.save world (find_session token) req.location
@@ -319,6 +327,7 @@ let rec handle_connection world ic oc () =
| Some t, Session_changed r -> session_changed world t r
| Some t, Get_config r -> get_config world t r
| Some t, Load r -> load world t r
+ | Some t, Merge r -> merge world t r
| Some t, Save r -> save world t r
| _ -> failwith "Unimplemented"
) |> Lwt.return