summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/session.ml4
-rw-r--r--src/session.mli3
-rw-r--r--src/vyconf_client.ml16
-rw-r--r--src/vyconf_client.mli2
-rw-r--r--src/vyconf_pb.ml129
-rw-r--r--src/vyconf_pb.mli31
-rw-r--r--src/vyconfd.ml102
7 files changed, 240 insertions, 47 deletions
diff --git a/src/session.ml b/src/session.ml
index 02166c2..86374dd 100644
--- a/src/session.ml
+++ b/src/session.ml
@@ -9,7 +9,7 @@ type cfg_op =
| CfgDelete of string list * string option
type world = {
- mutable running_config: CT.t;
+ running_config: CT.t;
reference_tree: RT.t;
vyconf_config: Vyconf_config.t;
dirs: Directories.t
@@ -18,6 +18,7 @@ type world = {
type session_data = {
proposed_config : Config_tree.t;
modified: bool;
+ conf_mode: bool;
changeset: cfg_op list;
client_app: string;
user: string;
@@ -26,6 +27,7 @@ type session_data = {
let make world client_app user = {
proposed_config = world.running_config;
modified = false;
+ conf_mode = false;
changeset = [];
client_app = client_app;
user = user
diff --git a/src/session.mli b/src/session.mli
index 160cb72..dfe2967 100644
--- a/src/session.mli
+++ b/src/session.mli
@@ -3,7 +3,7 @@ type cfg_op =
| CfgDelete of string list * string option
type world = {
- mutable running_config: Config_tree.t;
+ running_config: Config_tree.t;
reference_tree: Reference_tree.t;
vyconf_config: Vyconf_config.t;
dirs: Directories.t
@@ -12,6 +12,7 @@ type world = {
type session_data = {
proposed_config : Config_tree.t;
modified: bool;
+ conf_mode: bool;
changeset: cfg_op list;
client_app: string;
user: string
diff --git a/src/vyconf_client.ml b/src/vyconf_client.ml
index 7db59ff..7528def 100644
--- a/src/vyconf_client.ml
+++ b/src/vyconf_client.ml
@@ -10,6 +10,11 @@ type t = {
closed: bool
}
+let substitute_default d o=
+ match o with
+ | None -> d
+ | Some v -> v
+
let create sockfile =
let open Lwt_unix in
let sock = socket PF_UNIX SOCK_STREAM 0 in
@@ -39,3 +44,14 @@ let get_status client =
let req = Status in
let%lwt resp = do_request client req in
Lwt.return resp
+
+let setup_session ?(on_behalf_of=None) client client_app =
+ let id = on_behalf_of |> (function None -> None | Some x -> (Some (Int32.of_int x))) in
+ let req = Setup_session {client_application=(Some client_app); on_behalf_of=id} in
+ let%lwt resp = do_request client req in
+ match resp.status with
+ | Success ->
+ (match resp.output with
+ | Some token -> Lwt.return (Ok token)
+ | None -> failwith "setup_session did not return a token!")
+ | _ -> Error (substitute_default "Unknown error" resp.error) |> Lwt.return
diff --git a/src/vyconf_client.mli b/src/vyconf_client.mli
index 87fffdd..ff48d86 100644
--- a/src/vyconf_client.mli
+++ b/src/vyconf_client.mli
@@ -24,3 +24,5 @@ val create : string -> t Lwt.t
val shutdown : t -> t Lwt.t
val get_status : t -> response Lwt.t
+
+val setup_session : ?on_behalf_of:(int option) -> t -> string -> (string, string) result Lwt.t
diff --git a/src/vyconf_pb.ml b/src/vyconf_pb.ml
index ef36473..b2937cd 100644
--- a/src/vyconf_pb.ml
+++ b/src/vyconf_pb.ml
@@ -167,13 +167,13 @@ and request_run_op_mode_mutable = {
}
type request_enter_configuration_mode = {
- exclusive : bool option;
- override_exclusive : bool option;
+ exclusive : bool;
+ override_exclusive : bool;
}
and request_enter_configuration_mode_mutable = {
- mutable exclusive : bool option;
- mutable override_exclusive : bool option;
+ mutable exclusive : bool;
+ mutable override_exclusive : bool;
}
type request =
@@ -196,6 +196,18 @@ type request =
| Run_op_mode of request_run_op_mode
| Confirm
| Configure of request_enter_configuration_mode
+ | Exit_configure
+ | Teardown of string
+
+type request_envelope = {
+ token : string option;
+ request : request;
+}
+
+and request_envelope_mutable = {
+ mutable token : string option;
+ mutable request : request;
+}
type status =
| Success
@@ -434,20 +446,33 @@ and default_request_run_op_mode_mutable () : request_run_op_mode_mutable = {
}
let rec default_request_enter_configuration_mode
- ?exclusive:((exclusive:bool option) = None)
- ?override_exclusive:((override_exclusive:bool option) = None)
+ ?exclusive:((exclusive:bool) = false)
+ ?override_exclusive:((override_exclusive:bool) = false)
() : request_enter_configuration_mode = {
exclusive;
override_exclusive;
}
and default_request_enter_configuration_mode_mutable () : request_enter_configuration_mode_mutable = {
- exclusive = None;
- override_exclusive = None;
+ exclusive = false;
+ override_exclusive = false;
}
let rec default_request (): request = Status
+let rec default_request_envelope
+ ?token:((token:string option) = None)
+ ?request:((request:request) = default_request ())
+ () : request_envelope = {
+ token;
+ request;
+}
+
+and default_request_envelope_mutable () : request_envelope_mutable = {
+ token = None;
+ request = default_request ();
+}
+
let rec default_status () = (Success:status)
let rec default_response
@@ -907,14 +932,14 @@ let rec decode_request_enter_configuration_mode d =
| None -> (
)
| Some (1, Pbrt.Varint) -> (
- v.exclusive <- Some (Pbrt.Decoder.bool d);
+ v.exclusive <- Pbrt.Decoder.bool d;
loop ()
)
| Some (1, pk) -> raise (
Protobuf.Decoder.Failure (Protobuf.Decoder.Unexpected_payload ("Message(request_enter_configuration_mode), field(1)", pk))
)
| Some (2, Pbrt.Varint) -> (
- v.override_exclusive <- Some (Pbrt.Decoder.bool d);
+ v.override_exclusive <- Pbrt.Decoder.bool d;
loop ()
)
| Some (2, pk) -> raise (
@@ -949,6 +974,8 @@ let rec decode_request d =
| Some (17, _) -> Run_op_mode (decode_request_run_op_mode (Pbrt.Decoder.nested d))
| Some (18, _) -> (Pbrt.Decoder.empty_nested d ; Confirm)
| Some (19, _) -> Configure (decode_request_enter_configuration_mode (Pbrt.Decoder.nested d))
+ | Some (20, _) -> (Pbrt.Decoder.empty_nested d ; Exit_configure)
+ | Some (21, _) -> Teardown (Pbrt.Decoder.string d)
| Some (n, payload_kind) -> (
Pbrt.Decoder.skip d payload_kind;
loop ()
@@ -958,6 +985,32 @@ let rec decode_request d =
in
loop ()
+let rec decode_request_envelope d =
+ let v = default_request_envelope_mutable () in
+ let rec loop () =
+ match Pbrt.Decoder.key d with
+ | None -> (
+ )
+ | Some (1, Pbrt.Bytes) -> (
+ v.token <- Some (Pbrt.Decoder.string d);
+ loop ()
+ )
+ | Some (1, pk) -> raise (
+ Protobuf.Decoder.Failure (Protobuf.Decoder.Unexpected_payload ("Message(request_envelope), field(1)", pk))
+ )
+ | Some (2, Pbrt.Bytes) -> (
+ v.request <- decode_request (Pbrt.Decoder.nested d);
+ loop ()
+ )
+ | Some (2, pk) -> raise (
+ Protobuf.Decoder.Failure (Protobuf.Decoder.Unexpected_payload ("Message(request_envelope), field(2)", pk))
+ )
+ | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind; loop ()
+ in
+ loop ();
+ let v:request_envelope = Obj.magic v in
+ v
+
let rec decode_status d =
match Pbrt.Decoder.int_as_varint d with
| 0 -> (Success:status)
@@ -1210,22 +1263,10 @@ let rec encode_request_run_op_mode (v:request_run_op_mode) encoder =
()
let rec encode_request_enter_configuration_mode (v:request_enter_configuration_mode) encoder =
- (
- match v.exclusive with
- | Some x -> (
- Pbrt.Encoder.key (1, Pbrt.Varint) encoder;
- Pbrt.Encoder.bool x encoder;
- )
- | None -> ();
- );
- (
- match v.override_exclusive with
- | Some x -> (
- Pbrt.Encoder.key (2, Pbrt.Varint) encoder;
- Pbrt.Encoder.bool x encoder;
- )
- | None -> ();
- );
+ Pbrt.Encoder.key (1, Pbrt.Varint) encoder;
+ Pbrt.Encoder.bool v.exclusive encoder;
+ Pbrt.Encoder.key (2, Pbrt.Varint) encoder;
+ Pbrt.Encoder.bool v.override_exclusive encoder;
()
let rec encode_request (v:request) encoder =
@@ -1306,6 +1347,27 @@ let rec encode_request (v:request) encoder =
Pbrt.Encoder.key (19, Pbrt.Bytes) encoder;
Pbrt.Encoder.nested (encode_request_enter_configuration_mode x) encoder;
)
+ | Exit_configure -> (
+ Pbrt.Encoder.key (20, Pbrt.Bytes) encoder;
+ Pbrt.Encoder.empty_nested encoder
+ )
+ | Teardown x -> (
+ Pbrt.Encoder.key (21, Pbrt.Bytes) encoder;
+ Pbrt.Encoder.string x encoder;
+ )
+
+let rec encode_request_envelope (v:request_envelope) encoder =
+ (
+ match v.token with
+ | Some x -> (
+ Pbrt.Encoder.key (1, Pbrt.Bytes) encoder;
+ Pbrt.Encoder.string x encoder;
+ )
+ | None -> ();
+ );
+ Pbrt.Encoder.key (2, Pbrt.Bytes) encoder;
+ Pbrt.Encoder.nested (encode_request v.request) encoder;
+ ()
let rec encode_status (v:status) encoder =
match v with
@@ -1505,8 +1567,8 @@ let rec pp_request_run_op_mode fmt (v:request_run_op_mode) =
let rec pp_request_enter_configuration_mode fmt (v:request_enter_configuration_mode) =
let pp_i fmt () =
Format.pp_open_vbox fmt 1;
- Pbrt.Pp.pp_record_field "exclusive" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.exclusive;
- Pbrt.Pp.pp_record_field "override_exclusive" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.override_exclusive;
+ Pbrt.Pp.pp_record_field "exclusive" Pbrt.Pp.pp_bool fmt v.exclusive;
+ Pbrt.Pp.pp_record_field "override_exclusive" Pbrt.Pp.pp_bool fmt v.override_exclusive;
Format.pp_close_box fmt ()
in
Pbrt.Pp.pp_brk pp_i fmt ()
@@ -1532,6 +1594,17 @@ let rec pp_request fmt (v:request) =
| Run_op_mode x -> Format.fprintf fmt "@[Run_op_mode(%a)@]" pp_request_run_op_mode x
| Confirm -> Format.fprintf fmt "Confirm"
| Configure x -> Format.fprintf fmt "@[Configure(%a)@]" pp_request_enter_configuration_mode x
+ | Exit_configure -> Format.fprintf fmt "Exit_configure"
+ | Teardown x -> Format.fprintf fmt "@[Teardown(%a)@]" Pbrt.Pp.pp_string x
+
+let rec pp_request_envelope fmt (v:request_envelope) =
+ let pp_i fmt () =
+ Format.pp_open_vbox fmt 1;
+ Pbrt.Pp.pp_record_field "token" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.token;
+ Pbrt.Pp.pp_record_field "request" pp_request fmt v.request;
+ Format.pp_close_box fmt ()
+ in
+ Pbrt.Pp.pp_brk pp_i fmt ()
let rec pp_status fmt (v:status) =
match v with
diff --git a/src/vyconf_pb.mli b/src/vyconf_pb.mli
index 49976b9..8205491 100644
--- a/src/vyconf_pb.mli
+++ b/src/vyconf_pb.mli
@@ -89,8 +89,8 @@ type request_run_op_mode = {
}
type request_enter_configuration_mode = {
- exclusive : bool option;
- override_exclusive : bool option;
+ exclusive : bool;
+ override_exclusive : bool;
}
type request =
@@ -113,6 +113,13 @@ type request =
| Run_op_mode of request_run_op_mode
| Confirm
| Configure of request_enter_configuration_mode
+ | Exit_configure
+ | Teardown of string
+
+type request_envelope = {
+ token : string option;
+ request : request;
+}
type status =
| Success
@@ -254,8 +261,8 @@ val default_request_run_op_mode :
(** [default_request_run_op_mode ()] is the default value for type [request_run_op_mode] *)
val default_request_enter_configuration_mode :
- ?exclusive:bool option ->
- ?override_exclusive:bool option ->
+ ?exclusive:bool ->
+ ?override_exclusive:bool ->
unit ->
request_enter_configuration_mode
(** [default_request_enter_configuration_mode ()] is the default value for type [request_enter_configuration_mode] *)
@@ -263,6 +270,13 @@ val default_request_enter_configuration_mode :
val default_request : unit -> request
(** [default_request ()] is the default value for type [request] *)
+val default_request_envelope :
+ ?token:string option ->
+ ?request:request ->
+ unit ->
+ request_envelope
+(** [default_request_envelope ()] is the default value for type [request_envelope] *)
+
val default_status : unit -> status
(** [default_status ()] is the default value for type [status] *)
@@ -338,6 +352,9 @@ val decode_request_enter_configuration_mode : Pbrt.Decoder.t -> request_enter_co
val decode_request : Pbrt.Decoder.t -> request
(** [decode_request decoder] decodes a [request] value from [decoder] *)
+val decode_request_envelope : Pbrt.Decoder.t -> request_envelope
+(** [decode_request_envelope decoder] decodes a [request_envelope] value from [decoder] *)
+
val decode_status : Pbrt.Decoder.t -> status
(** [decode_status decoder] decodes a [status] value from [decoder] *)
@@ -407,6 +424,9 @@ val encode_request_enter_configuration_mode : request_enter_configuration_mode -
val encode_request : request -> Pbrt.Encoder.t -> unit
(** [encode_request v encoder] encodes [v] with the given [encoder] *)
+val encode_request_envelope : request_envelope -> Pbrt.Encoder.t -> unit
+(** [encode_request_envelope v encoder] encodes [v] with the given [encoder] *)
+
val encode_status : status -> Pbrt.Encoder.t -> unit
(** [encode_status v encoder] encodes [v] with the given [encoder] *)
@@ -476,6 +496,9 @@ val pp_request_enter_configuration_mode : Format.formatter -> request_enter_conf
val pp_request : Format.formatter -> request -> unit
(** [pp_request v] formats v *)
+val pp_request_envelope : Format.formatter -> request_envelope -> unit
+(** [pp_request_envelope v] formats v *)
+
val pp_status : Format.formatter -> status -> unit
(** [pp_status v] formats v *)
diff --git a/src/vyconfd.ml b/src/vyconfd.ml
index 0e3340f..c07b1b3 100644
--- a/src/vyconfd.ml
+++ b/src/vyconfd.ml
@@ -1,6 +1,7 @@
open Lwt
open Defaults
open Vyconf_config
+open Vyconf_pb
(* On UNIX, self_init uses /dev/random for seed *)
let () = Random.self_init ()
@@ -13,7 +14,11 @@ let config_file = ref defaults.config_file
let log_file = ref None
(* Global data *)
+let sessions : (string, Session.session_data) Hashtbl.t = Hashtbl.create 10
+let commit_lock : string option ref = ref None
+
+let conf_mode_lock : string option ref = ref None
(* Command line arguments *)
let args = [
@@ -27,47 +32,118 @@ let args = [
]
let usage = "Usage: " ^ Sys.argv.(0) ^ " [options]"
+let response_tmpl = {status=Success; output=None; error=None; warning=None}
+
let make_session_token () =
Sha1.string (string_of_int (Random.bits ())) |> Sha1.to_hex
-let rec handle_connection ic oc () =
+let setup_session world req =
+ let token = make_session_token () in
+ let user = "unknown user" in
+ let client_app = Util.substitute_default req.client_application "unknown client" in
+ let () = Hashtbl.add sessions token (Session.make world client_app user) in
+ {response_tmpl with output=(Some token)}
+
+let enter_conf_mode req token =
+ let open Session in
+ let aux token session =
+ let open Session in
+ let session = {session with conf_mode=true} in
+ Hashtbl.replace sessions token session;
+ response_tmpl
+ in
+ let lock = !conf_mode_lock in
+ let session = Hashtbl.find sessions token in
+ match lock with
+ | Some user ->
+ if req.override_exclusive then aux token session
+ else
+ {response_tmpl with
+ status=Configuration_locked;
+ error=Some (Printf.sprintf "Configuration was locked by %s" user)}
+ | None ->
+ if req.exclusive then (conf_mode_lock := Some session.user; aux token session)
+ else aux token session
+
+let exit_conf_mode world token =
+ let open Session in
+ let session = Hashtbl.find sessions token in
+ let session = {session with
+ proposed_config=world.running_config;
+ changeset = [];
+ modified = false}
+ in Hashtbl.replace sessions token session;
+ response_tmpl
+
+let teardown_session token =
+ try
+ Hashtbl.remove sessions token;
+ response_tmpl
+ with Not_found ->
+ {response_tmpl with status=Fail; error=(Some "Session not found")}
+
+let rec handle_connection world ic oc () =
let open Vyconf_pb in
try%lwt
let%lwt req_msg = Message.read ic in
- let%lwt req = decode_request (Pbrt.Decoder.of_bytes req_msg) |> return in
+ let%lwt req =
+ let envelope = decode_request_envelope (Pbrt.Decoder.of_bytes req_msg) in
+ Lwt.return (envelope.token, envelope.request)
+ in
let%lwt resp =
(match req with
- | Status -> {status=Success; output=None; error=None; warning=(Some "None of the other functions are implemented though")}
+ | _, Status -> response_tmpl
+ | _, Setup_session r -> setup_session world r
+ | None, _ -> {response_tmpl with status=Fail; output=(Some "Operation requires session token")}
+ | Some t, Teardown _ -> teardown_session t
+ | Some t, Configure r -> enter_conf_mode r t
+ | Some t, Exit_configure -> exit_conf_mode world t
| _ -> failwith "Unimplemented") |> return
in
let enc = Pbrt.Encoder.create () in
let%lwt () = encode_response resp enc |> return in
let%lwt resp_msg = Pbrt.Encoder.to_bytes enc |> return in
let%lwt () = Message.write oc resp_msg in
- handle_connection ic oc ()
+ handle_connection world ic oc ()
with
- | Failure e -> Lwt_log.error e >>= handle_connection ic oc
+ | Failure e -> Lwt_log.error e >>= handle_connection world ic oc
| End_of_file -> Lwt_log.info "Connection closed" >>= return
-let accept_connection conn =
+let accept_connection world conn =
let fd, _ = conn in
let ic = Lwt_io.of_fd Lwt_io.Input fd in
let oc = Lwt_io.of_fd Lwt_io.Output fd in
- Lwt.on_failure (handle_connection ic oc ()) (fun e -> Lwt_log.ign_error (Printexc.to_string e));
+ Lwt.on_failure (handle_connection world ic oc ()) (fun e -> Lwt_log.ign_error (Printexc.to_string e));
Lwt_log.info "New connection" >>= return
-let main_loop config () =
- let%lwt () = Startup.setup_logger !daemonize !log_file config.log_template in
- let%lwt () = Lwt_log.notice @@ Printf.sprintf "Starting VyConf for %s" config.app_name in
- let%lwt sock = Startup.create_socket config.socket in
- let%lwt serve = Startup.create_server accept_connection sock () in
+let main_loop world () =
+ let open Session in
+ let%lwt () = Startup.setup_logger !daemonize !log_file world.vyconf_config.log_template in
+ let%lwt () = Lwt_log.notice @@ Printf.sprintf "Starting VyConf for %s" world.vyconf_config.app_name in
+ let%lwt sock = Startup.create_socket world.vyconf_config.socket in
+ let%lwt serve = Startup.create_server (accept_connection world) sock () in
serve ()
+let load_interface_definitions dir =
+ let open Session in
+ let reftree = Reference_tree.load_interface_definitions dir in
+ match reftree with
+ | Ok r -> r
+ | Error s -> Startup.panic s
+
+let make_world config dirs =
+ let open Directories in
+ let open Session in
+ let reftree = load_interface_definitions dirs.interface_definitions in
+ let running_config = Config_tree.make "root" in
+ {running_config=running_config; reference_tree=reftree; vyconf_config=config; dirs=dirs}
+
let () =
let () = Arg.parse args (fun f -> ()) usage in
let config = Startup.load_config !config_file in
let () = Lwt_log.load_rules ("* -> " ^ config.log_level) in
let dirs = Directories.make config in
Startup.check_dirs dirs;
- Lwt_main.run @@ main_loop config ()
+ let world = make_world config dirs in
+ Lwt_main.run @@ main_loop world ()