# HG changeset patch # User Thomas Gazagnaire # Date 1260283362 0 # Node ID 2acddc1fa6a2fb77b1534a1089b28e4ba4412520 # Parent 1f49f00797faf725de371513be573e0ca0badb26 CA-34933: For each host, cache the session used communicating within the pool. Signed-off-by: Thomas Gazagnaire diff -r 1f49f00797fa -r 2acddc1fa6a2 ocaml/idl/ocaml_backend/context.ml --- a/ocaml/idl/ocaml_backend/context.ml Fri Dec 04 16:04:36 2009 +0000 +++ b/ocaml/idl/ocaml_backend/context.ml Tue Dec 08 14:42:42 2009 +0000 @@ -45,6 +45,11 @@ match x.session_id with | None -> failwith "Could not find a session_id" | Some x -> x + +let has_session_id x = + match x.session_id with + | None -> false + | Some _ -> true let forwarded_task ctx = ctx.forwarded_task diff -r 1f49f00797fa -r 2acddc1fa6a2 ocaml/idl/ocaml_backend/context.mli --- a/ocaml/idl/ocaml_backend/context.mli Fri Dec 04 16:04:36 2009 +0000 +++ b/ocaml/idl/ocaml_backend/context.mli Tue Dec 08 14:42:42 2009 +0000 @@ -48,6 +48,7 @@ (** [session_of_t __context] returns the session id stored in [__context]. In case there is no session id in this context, it fails with [Failure "Could not find a session_id"]. *) val get_session_id : t -> API.ref_session +val has_session_id : t -> bool (** [get_task_id __context] returns the task id stored in [__context]. Such a task can be either a task stored in database or a tempory task (also called dummy). *) diff -r 1f49f00797fa -r 2acddc1fa6a2 ocaml/xapi/helpers.ml --- a/ocaml/xapi/helpers.ml Fri Dec 04 16:04:36 2009 +0000 +++ b/ocaml/xapi/helpers.ml Tue Dec 08 14:42:42 2009 +0000 @@ -94,47 +94,43 @@ (* Slave has to go back to master via network *) Xmlrpcclient.do_secure_xml_rpc ~subtask_of - ~use_stunnel_cache:true + ~use_stunnel_cache:true ~version:"1.1" ~host:(Pool_role.get_master_address ()) ~port:!Xapi_globs.https_port ~path:"/" xml (* No auth needed over unix domain socket *) +let do_internal_login ~__context = + let login = + if Pool_role.is_master () then + (fun () -> + if Context.has_session_id __context && Db.Session.get_pool ~__context ~self:(Context.get_session_id __context) then + Context.get_session_id __context + else begin + let rpc = make_rpc ~__context in + let session_id = Client.Client.Session.slave_login rpc (get_localhost ~__context) !Xapi_globs.pool_secret in + debug "local login done"; + session_id + end) + else + (fun () -> + let rpc = make_rpc ~__context in + let session_id = Client.Client.Session.slave_login rpc (get_localhost ~__context) !Xapi_globs.pool_secret in + debug "slave login done"; + session_id) in + Xapi_globs.get_internal_session login + +let with_cached_session ~__context fn = + try fn (do_internal_login ~__context) + with Api_errors.Server_error (error,_) as e when error = Api_errors.session_authentication_failed -> + Xapi_globs.reset_internal_session_cache (); + debug "remote client call finished with exception %s; cleaning the session cache" (Printexc.to_string e); + raise e + (** Log into pool master using the client code, call a function passing it the rpc function and session id, logout when finished. *) let call_api_functions ~__context f = - let rpc = make_rpc ~__context in - let () = debug "logging into master" in - (* If we're the master then our existing session may be a client one without 'pool' flag set, so - we consider making a new one. If we're a slave then our existing session (if we have one) must - have the 'pool' flag set because it would have been created for us in the message forwarding layer - in the master, so we just re-use it. [If we haven't got an existing session in our context then - we always make a new one *) - let require_explicit_logout = ref false in - let do_master_login () = - let session = Client.Client.Session.slave_login rpc (get_localhost ~__context) !Xapi_globs.pool_secret in - require_explicit_logout := true; - session - in - let session_id = - try - if Pool_role.is_master() then - begin - let session_id = Context.get_session_id __context in - if Db.Session.get_pool ~__context ~self:session_id - then session_id - else do_master_login () - end - else Context.get_session_id __context - with _ -> - do_master_login () - in - let () = debug "login done" in - finally - (fun () -> f rpc session_id) - (fun () -> - debug "remote client call finished; logging out"; - if !require_explicit_logout - then Client.Client.Session.logout rpc session_id) + let rpc = make_rpc ~__context in + with_cached_session ~__context (fun session_id -> f rpc session_id) let call_emergency_mode_functions hostname f = let rpc xml = Xmlrpcclient.do_secure_xml_rpc ~version:"1.0" ~host:hostname diff -r 1f49f00797fa -r 2acddc1fa6a2 ocaml/xapi/message_forwarding.ml --- a/ocaml/xapi/message_forwarding.ml Fri Dec 04 16:04:36 2009 +0000 +++ b/ocaml/xapi/message_forwarding.ml Tue Dec 08 14:42:42 2009 +0000 @@ -191,11 +191,8 @@ ~port:!Xapi_globs.https_port ~path:"/" xml let call_slave_with_session remote_rpc_fn __context host (task_opt: API.ref_task option) f = - let session_id = Xapi_session.login_no_password ~__context ~uname:None ~host ~pool:true ~is_local_superuser:true ~subject:(Ref.null) ~auth_user_sid:"" ~rbac_permissions:[] in let hostname = Db.Host.get_address ~__context ~self:host in - Pervasiveext.finally - (fun ()->f session_id (remote_rpc_fn __context hostname task_opt)) - (fun ()->Server_helpers.exec_with_new_task ~session_id "local logout in message forwarder" (fun __context -> Xapi_session.logout ~__context)) + Helpers.with_cached_session ~__context (fun session_id -> f session_id (remote_rpc_fn __context hostname task_opt)) let call_slave_with_local_session remote_rpc_fn __context host (task_opt: API.ref_task option) f = let hostname = Db.Host.get_address ~__context ~self:host in diff -r 1f49f00797fa -r 2acddc1fa6a2 ocaml/xapi/xapi.ml --- a/ocaml/xapi/xapi.ml Fri Dec 04 16:04:36 2009 +0000 +++ b/ocaml/xapi/xapi.ml Tue Dec 08 14:42:42 2009 +0000 @@ -394,8 +394,7 @@ debug "Master claims he has no record of us being a slave"; Xapi_host.set_emergency_mode_error Api_errors.host_unknown_to_master [ localhost_uuid ]; Some Permanent - | `ok -> - None + | `ok -> None ) with | Api_errors.Server_error(code, params) when code = Api_errors.session_authentication_failed -> diff -r 1f49f00797fa -r 2acddc1fa6a2 ocaml/xapi/xapi_globs.ml --- a/ocaml/xapi/xapi_globs.ml Fri Dec 04 16:04:36 2009 +0000 +++ b/ocaml/xapi/xapi_globs.ml Tue Dec 08 14:42:42 2009 +0000 @@ -15,6 +15,7 @@ (** A central location for settings related to xapi *) open Stringext +open Threadext open Printf (* xapi process returns this code on exit when it wants to be restarted *) @@ -22,6 +23,19 @@ let pool_secret_path = "/etc/xensource/ptoken" let pool_secret = ref "" +let internal_session : [`session] Ref.t option ref = ref None + +let internal_session_mutex = Mutex.create () +let get_internal_session login_fn = + Mutex.execute internal_session_mutex (fun () -> + match !internal_session with + | None -> + let session = login_fn () in + internal_session := Some session; + session + | Some session -> session) +let reset_internal_session_cache () = + Mutex.execute internal_session_mutex (fun () -> internal_session := None) let localhost_ref : [`host] Ref.t ref = ref Ref.null