diff options
Diffstat (limited to 'src/session.ml')
-rw-r--r-- | src/session.ml | 132 |
1 files changed, 126 insertions, 6 deletions
diff --git a/src/session.ml b/src/session.ml index 602ab14..1ff9bae 100644 --- a/src/session.ml +++ b/src/session.ml @@ -1,7 +1,11 @@ module CT = Vyos1x.Config_tree +module IC = Vyos1x.Internal.Make(CT) +module CC = Commitd_client.Commit +module CD = Vyos1x.Config_diff module VT = Vyos1x.Vytree module RT = Vyos1x.Reference_tree module D = Directories +module FP = FilePath exception Session_error of string @@ -23,15 +27,17 @@ type session_data = { changeset: cfg_op list; client_app: string; user: string; + client_pid: int32; } -let make world client_app user = { +let make world client_app user pid = { proposed_config = world.running_config; modified = false; conf_mode = false; changeset = []; client_app = client_app; - user = user + user = user; + client_pid = pid; } let string_of_op op = @@ -69,6 +75,21 @@ let validate w _s path = RT.validate_path D.(w.dirs.validators) w.reference_tree path with RT.Validation_error x -> raise (Session_error x) +let validate_tree w' t = + let validate_path w out path = + let res = + try + RT.validate_path D.(w.dirs.validators) w.reference_tree path; + out + with RT.Validation_error x -> out ^ x + in res + in + let paths = CT.value_paths_of_tree t in + let out = List.fold_left (validate_path w') "" paths in + match out with + | "" -> () + | _ -> raise (Session_error out) + let split_path w _s path = RT.split_path w.reference_tree path @@ -79,19 +100,118 @@ let set w s path = let value_behaviour = if RT.is_multi w.reference_tree refpath then CT.AddValue else CT.ReplaceValue in let op = CfgSet (path, value, value_behaviour) in let config = - apply_cfg_op op s.proposed_config |> - (fun c -> RT.set_tag_data w.reference_tree c path) |> - (fun c -> RT.set_leaf_data w.reference_tree c path) + try + apply_cfg_op op s.proposed_config |> + (fun c -> RT.set_tag_data w.reference_tree c path) |> + (fun c -> RT.set_leaf_data w.reference_tree c path) + with + | CT.Useless_set -> + raise (Session_error (Printf.sprintf "Useless set, path: %s" (string_of_op op))) + | CT.Duplicate_value -> + raise (Session_error (Printf.sprintf "Duplicate value, path: %s" (string_of_op op))) + in {s with proposed_config=config; changeset=(op :: s.changeset)} let delete w s path = - let _ = validate w s path in let path, value = split_path w s path in let op = CfgDelete (path, value) in let config = apply_cfg_op op s.proposed_config in {s with proposed_config=config; changeset=(op :: s.changeset)} +let discard w s = + {s with proposed_config=w.running_config} + +let session_changed w s = + (* structural equality test requires consistent ordering, which is + * practised, but may be unreliable; test actual difference + *) + let diff = CD.diff_tree [] w.running_config s.proposed_config in + let add_tree = CT.get_subtree diff ["add"] in + let del_tree = CT.get_subtree diff ["del"] in + (del_tree <> CT.default) || (add_tree <> CT.default) + +let load w s file cached = + let ct = + if cached then + try + Ok (IC.read_internal file) + with Vyos1x.Internal.Read_error e -> + Error e + else + Vyos1x.Config_file.load_config file + in + match ct with + | Error e -> raise (Session_error (Printf.sprintf "Error loading config: %s" e)) + | 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 + match res with + | Error e -> raise (Session_error (Printf.sprintf "Error saving config: %s" e)) + | Ok () -> s + +let prepare_commit ?(dry_run=false) w s id = + let at = w.running_config in + let wt = s.proposed_config in + let rt = w.reference_tree in + let vc = w.vyconf_config in + let () = + try + IC.write_internal at (FP.concat vc.session_dir vc.running_cache) + with + Vyos1x.Internal.Write_error msg -> raise (Session_error msg) + in + let () = + try + IC.write_internal wt (FP.concat vc.session_dir vc.session_cache) + with + Vyos1x.Internal.Write_error msg -> raise (Session_error msg) + in + CC.make_commit_data ~dry_run:dry_run rt at wt id + +let get_config w s id = + let at = w.running_config in + let wt = s.proposed_config 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 + let () = + try + IC.write_internal at (FP.concat vc.session_dir running_cache) + with + Vyos1x.Internal.Write_error msg -> raise (Session_error msg) + in + let () = + try + IC.write_internal wt (FP.concat vc.session_dir session_cache) + with + Vyos1x.Internal.Write_error msg -> raise (Session_error msg) + 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 + remove_file (FP.concat vc.session_dir running_cache); + remove_file (FP.concat vc.session_dir session_cache) + let get_value w s path = if not (VT.exists s.proposed_config path) then raise (Session_error ("Config path does not exist")) |