Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

xenserver/CI-44 #1072

Merged
merged 9 commits into from

3 participants

@zli
Collaborator

This is a partial solution to the CI-44 issue. It does so by grouping sessions based on their auth_user_name and originator and assigning session quota to each group independently. It is based on some previous patches from Thomas Sanders.

@zli
Collaborator

The change on parameters of Session.login_with_password is an incompatible change, hence will break client code that makes use of the OCaml XAPI client (e.g. rrdd plugin, v6d). Dynamically typed language binding should be fine, as the new parameter is set to be optional.

zli added some commits
@zli zli CI-44: Add an extra field "originator" to session object.
This is a key string used for distinguishing different API users sharing the same login name.

Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
076cc6d
@zli zli CI-44: Add the originator param to XAPI session creation
Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
b173b50
@zli zli CI-44: update internal uses of login_with_password with the originato…
…r param

Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
95555c6
@zli zli CI-44: update external components and tests with the new originator p…
…aram

Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
65479d1
@zli zli CI-44: Add max_sessions_per_originator config
Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
024a07c
@zli zli CI-44: update session create/destory rbac audit functions
Based on some previous patches from Thomas Sanders.

Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
1516777
@zli zli CI-44: it seems making better sense to expire tasks before sessions
Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
0d8839f
@zli zli CI-44: add max_sessions_per_user_name config variable
Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
6a1669d
@zli zli CI-44: expire sessions based on username/originator specific quota
Based on some previous patches by Thomas Sanders.

The current algorithm is implemented as follows:

  * For sessions with their own auth_user_name (other than "root"/""), they will use their independent session quota (Xapi_globs.max_sessions_per_user_name) grouped by their auth_user_name. This can happen in following cases:
    - The session creator uses an external authentication method where the username is not the default
    - The session creator is logged in as local super user (hence no username/password authentication required) but still chooses to pass an independent username argument in purpose (e.g. vmpr, sm)

  * Sessions without independent auth_user_name (e.g. without RBAC, most external API users will have to share the same super user login) can still distiguish themselves using the new "originator" param during session creation. For sessions created with the optional "originator" argument, they will use their independent session quota (Xapi_globs.max_sessions_per_originator) grouped by their originator key.

  * All the rest sessions are in the common session pool, as before, sharing the default session quota (Xapi_globs.max_sessions). Among them, internal sessions will have higher prioirty than the external ones.

Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
a8733d3
@robhoes robhoes was assigned
@jonludlam
Owner

Assigning to @robhoes for review

@jonludlam
Owner

test this please

@robhoes
Owner

test this please

@robhoes
Owner

Looks good! It's going in...

@robhoes robhoes merged commit dfb54af into xapi-project:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 13, 2013
  1. @zli

    CI-44: Add an extra field "originator" to session object.

    zli authored
    This is a key string used for distinguishing different API users sharing the same login name.
    
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
  2. @zli

    CI-44: Add the originator param to XAPI session creation

    zli authored
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
  3. @zli

    CI-44: update internal uses of login_with_password with the originato…

    zli authored
    …r param
    
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
  4. @zli

    CI-44: update external components and tests with the new originator p…

    zli authored
    …aram
    
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
  5. @zli

    CI-44: Add max_sessions_per_originator config

    zli authored
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
  6. @zli

    CI-44: update session create/destory rbac audit functions

    zli authored
    Based on some previous patches from Thomas Sanders.
    
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
  7. @zli

    CI-44: it seems making better sense to expire tasks before sessions

    zli authored
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
  8. @zli

    CI-44: add max_sessions_per_user_name config variable

    zli authored
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
  9. @zli

    CI-44: expire sessions based on username/originator specific quota

    zli authored
    Based on some previous patches by Thomas Sanders.
    
    The current algorithm is implemented as follows:
    
      * For sessions with their own auth_user_name (other than "root"/""), they will use their independent session quota (Xapi_globs.max_sessions_per_user_name) grouped by their auth_user_name. This can happen in following cases:
        - The session creator uses an external authentication method where the username is not the default
        - The session creator is logged in as local super user (hence no username/password authentication required) but still chooses to pass an independent username argument in purpose (e.g. vmpr, sm)
    
      * Sessions without independent auth_user_name (e.g. without RBAC, most external API users will have to share the same super user login) can still distiguish themselves using the new "originator" param during session creation. For sessions created with the optional "originator" argument, they will use their independent session quota (Xapi_globs.max_sessions_per_originator) grouped by their originator key.
    
      * All the rest sessions are in the common session pool, as before, sharing the default session quota (Xapi_globs.max_sessions). Among them, internal sessions will have higher prioirty than the external ones.
    
    Signed-off-by: Zheng Li <zheng.li@eu.citrix.com>
This page is out of date. Refresh to see the latest.
Showing with 96 additions and 69 deletions.
  1. +1 −1  ocaml/events/event_listen.ml
  2. +1 −1  ocaml/graph/graph.ml
  3. +4 −1 ocaml/idl/datamodel.ml
  4. +16 −11 ocaml/idl/ocaml_backend/rbac_audit.ml
  5. +1 −1  ocaml/lvhdrt/lvhdrt.ml
  6. +2 −2 ocaml/lvhdrt/utils.ml
  7. +1 −1  ocaml/mpathalert/mpathalert.ml
  8. +1 −1  ocaml/multipathrt/alert_utils.ml
  9. +1 −1  ocaml/multipathrt/iscsi_utils.ml
  10. +1 −1  ocaml/multipathrt/multipathrt.ml
  11. +1 −1  ocaml/network/network_monitor_thread.ml
  12. +1 −1  ocaml/perftest/apiperf.ml
  13. +3 −3 ocaml/perftest/createpool.ml
  14. +2 −2 ocaml/perftest/perftest.ml
  15. +2 −2 ocaml/sm-cli/test.ml
  16. +1 −1  ocaml/toplevel/toplevelhelper.ml
  17. +1 −1  ocaml/vncproxy/vncproxy.ml
  18. +1 −1  ocaml/xapi/cancel_tests.ml
  19. +1 −1  ocaml/xapi/cli_operations.ml
  20. +1 −1  ocaml/xapi/create_storage_main.ml
  21. +26 −15 ocaml/xapi/db_gc.ml
  22. +1 −1  ocaml/xapi/quicktest_common.ml
  23. +1 −1  ocaml/xapi/xapi_cli.ml
  24. +6 −0 ocaml/xapi/xapi_globs.ml
  25. +2 −2 ocaml/xapi/xapi_http.ml
  26. +1 −1  ocaml/xapi/xapi_pool.ml
  27. +14 −12 ocaml/xapi/xapi_session.ml
  28. +1 −1  ocaml/xapi/xapi_session.mli
  29. +1 −1  ocaml/xe-cli/import_main.ml
View
2  ocaml/events/event_listen.ml
@@ -41,7 +41,7 @@ let _ =
Printf.printf "Connecting to Host: %s; Port: %d; Username: %s" !host !port !username;
(* Interesting event stuff starts here: *)
- let session_id = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.2" in
+ let session_id = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.2" ~originator:"event_listen" in
Client.Event.register ~rpc ~session_id ~classes:["*"];
while true do
let events = events_of_rpc (Client.Event.next ~rpc ~session_id) in
View
2  ocaml/graph/graph.ml
@@ -146,7 +146,7 @@ let _ =
"Display an object graph";
(* Interesting event stuff starts here: *)
- let session_id = Client.Session.login_with_password ~rpc:newrpc ~uname:!username ~pwd:!password ~version:"1.2" in
+ let session_id = Client.Session.login_with_password ~rpc:newrpc ~uname:!username ~pwd:!password ~version:"1.2" ~originator:"graph" in
let classes = List.filter (fun x -> List.mem x Datamodel.expose_get_all_messages_for) all_classes in
List.iter (fun x -> if not(List.mem x classes) then failwith (Printf.sprintf "Class %s not available" x)) !wanted;
View
5 ocaml/idl/datamodel.ml
@@ -1181,7 +1181,9 @@ let session_login = call ~flags:[]
~versioned_params:
[{param_type=String; param_name="uname"; param_doc="Username for login."; param_release=rio_release; param_default=None};
{param_type=String; param_name="pwd"; param_doc="Password for login."; param_release=rio_release; param_default=None};
- {param_type=String; param_name="version"; param_doc="Client API version."; param_release=miami_release; param_default=Some (VString "1.1")}]
+ {param_type=String; param_name="version"; param_doc="Client API version."; param_release=miami_release; param_default=Some (VString "1.1")};
+ {param_type=String; param_name="originator"; param_doc="Key string for distinguishing different API users sharing the same login name."; param_release=clearwater_release; param_default=Some (VString "")}
+ ]
~errs:[Api_errors.session_authentication_failed]
~secret:true
~allowed_roles:_R_ALL (*any static role can try to create a user session*)
@@ -3327,6 +3329,7 @@ let session =
field ~in_product_since:rel_midnight_ride ~qualifier:StaticRO ~default_value:(Some(VSet [])) ~ty:(Set(String)) "rbac_permissions" "list with all RBAC permissions for this session";
field ~in_product_since:rel_midnight_ride ~qualifier:DynamicRO ~ty:(Set(Ref _task)) "tasks" "list of tasks created using the current session";
field ~in_product_since:rel_midnight_ride ~qualifier:StaticRO ~default_value:(Some (VRef (Ref.string_of Ref.null))) ~ty:(Ref _session) "parent" "references the parent session that created this session";
+ field ~in_product_since:rel_clearwater ~qualifier:DynamicRO ~default_value:(Some(VString(""))) ~ty:String "originator" "a key string provided by a API user to distinguish itself from other users sharing the same login name";
]
()
View
27 ocaml/idl/ocaml_backend/rbac_audit.ml
@@ -521,27 +521,32 @@ let denied ~__context ~session_id ~action ~permission ?args () =
audit_line_of __context session_id "DENIED" "" "" action permission ?args ()
)
-let session_destroy ~__context ~session_id =
-(*
- (* this is currently only creating spam in the audit log *)
- let action="session.destroy" in
- allowed_ok ~__context ~session_id ~action ~permission:action ()
-*)
- ()
-
-let session_create ~__context ~session_id ~uname =
+let session_create_or_destroy ~create ~__context ~session_id ~uname =
wrap (fun () ->
let session_rec = DB_Action.Session.get_record ~__context ~self:session_id in
let s_is_intrapool = session_rec.API.session_pool in
let s_is_lsu = session_rec.API.session_is_local_superuser in
(* filters out intra-pool logins to avoid spamming the audit log *)
if (not s_is_intrapool) && (not s_is_lsu) then (
- let action="session.create" in
+ let action = (if create then "session.create" else "session.destroy") in
+ let originator = session_rec.API.session_originator in
let sexpr_of_args =
- (get_sexpr_arg "uname" (match uname with None->""|Some u->u) "" "")::
+ (get_sexpr_arg "originator" originator "" "")::
[]
in
+ let sexpr_of_args =
+ if create then
+ (get_sexpr_arg "uname" (match uname with None->""|Some u->u) "" "")::
+ sexpr_of_args
+ else
+ sexpr_of_args
+ in
allowed_post_fn_ok ~__context ~session_id ~action ~sexpr_of_args ~permission:action ()
)
)
+let session_destroy ~__context ~session_id =
+ session_create_or_destroy ~uname:None ~create:false ~__context ~session_id
+
+let session_create ~__context ~session_id ~uname =
+ session_create_or_destroy ~create:true ~__context ~session_id ~uname
View
2  ocaml/lvhdrt/lvhdrt.ml
@@ -39,7 +39,7 @@ let _ =
(* Get a session *)
let rpc = rpc_of_hostname !hostname in
- let session = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.4" in
+ let session = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.4" ~originator:"lvhdrt" in
try
begin
View
4 ocaml/lvhdrt/utils.ml
@@ -334,7 +334,7 @@ let create_vdi_tree rpc session sr name_label size ?resize ?(pattern_type=1) pat
let wait_for_fist rpc session sr ?(delay=90.0) fist =
- let session2 = Client.Session.login_with_password rpc !Globs.username !Globs.password "1.4" in
+ let session2 = Client.Session.login_with_password rpc !Globs.username !Globs.password "1.4" "lvhdrt" in
Client.Event.register rpc session2 ["sr"];
@@ -373,7 +373,7 @@ let wait_for_fist rpc session sr ?(delay=90.0) fist =
* delay will be used if at least one VDI is not deleted (e.g. because it didn't
* exist. *)
let wait_for_vdi_deletion rpc session sr ?(delay=90.0) vdis =
- let session2 = Client.Session.login_with_password rpc !Globs.username !Globs.password "1.4" in
+ let session2 = Client.Session.login_with_password rpc !Globs.username !Globs.password "1.4" "lvhdrt" in
Client.Event.register rpc session2 ["vdi"];
debug "Registered for vdi events";
View
2  ocaml/mpathalert/mpathalert.ml
@@ -67,7 +67,7 @@ let to_string alert =
let rec retry_with_session f rpc x =
let session =
let rec aux () =
- try Client.Session.login_with_password ~rpc ~uname:"" ~pwd:"" ~version:"1.4"
+ try Client.Session.login_with_password ~rpc ~uname:"" ~pwd:"" ~version:"1.4" ~originator:"mpathalert"
with _ -> Thread.delay !delay; aux () in
aux () in
try
View
2  ocaml/multipathrt/alert_utils.ml
@@ -104,7 +104,7 @@ let check_path_counts entry max_paths current_paths =
(* For all messages m matching the check_message predicate, execute f m *)
let wait_for_alert rpc session ?(delay=180.0) check_message f =
- let session2 = Client.Session.login_with_password rpc !Globs.username !Globs.password "1.4" in
+ let session2 = Client.Session.login_with_password rpc !Globs.username !Globs.password "1.4" "multipathrt"in
Client.Event.register rpc session2 ["message"];
let finished = ref false in
View
2  ocaml/multipathrt/iscsi_utils.ml
@@ -160,7 +160,7 @@ let setup_iscsi_sr rpc session host iscsi_vm =
(scsiid, sr)
let wait_for_vm_to_run rpc session ?(delay=60.0) vm =
- let session2 = Client.Session.login_with_password rpc !Globs.username !Globs.password "1.4" in
+ let session2 = Client.Session.login_with_password rpc !Globs.username !Globs.password "1.4" "multipathrt" in
Client.Event.register rpc session2 ["vm"];
let finished = ref false in
View
2  ocaml/multipathrt/multipathrt.ml
@@ -37,7 +37,7 @@ let _ =
(* Get a session *)
let rpc = rpc_of_hostname !hostname in
- let session = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.4" in
+ let session = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.4" ~originator:"multipathrt" in
try
begin
match !tc with
View
2  ocaml/network/network_monitor_thread.ml
@@ -34,7 +34,7 @@ let send_bond_change_alert dev interfaces message =
let ifaces = String.concat "+" (List.sort String.compare interfaces) in
let module XenAPI = Client.Client in
let session_id = XenAPI.Session.login_with_password
- ~rpc:xapi_rpc ~uname:"" ~pwd:"" ~version:"1.4" in
+ ~rpc:xapi_rpc ~uname:"" ~pwd:"" ~version:"1.4" ~originator:"networkd" in
Pervasiveext.finally
(fun _ ->
let obj_uuid = Util_inventory.lookup Util_inventory._installation_uuid in
View
2  ocaml/perftest/apiperf.ml
@@ -153,7 +153,7 @@ let _ =
if not !master && !slave_limit = 0 then failwith "Must provide either -master or -slaves argument";
- let session = Client.Session.login_with_password rpc "root" "xenroot" "1.2" in
+ let session = Client.Session.login_with_password rpc "root" "xenroot" "1.2" "perftest" in
finally
(fun () ->
let hosts = Client.Host.get_all rpc session in
View
6 ocaml/perftest/createpool.ml
@@ -248,7 +248,7 @@ let create_sdk_pool session_id sdkname pool_name key ipbase =
if firstboot.(i) then true else begin
let rpc = remoterpc ip in
try
- let s = Client.Session.login_with_password rpc "root" "xensource" "1.1" in
+ let s = Client.Session.login_with_password rpc "root" "xensource" "1.1" "perftest" in
finally
(fun () ->
let host = List.hd (Client.Host.get_all rpc s) in (* only one host because it hasn't joined the pool yet *)
@@ -282,7 +282,7 @@ let create_sdk_pool session_id sdkname pool_name key ipbase =
let host_uuids = Array.mapi (fun i vm ->
let n = i + 1 in
let rpc = remoterpc (Printf.sprintf "192.168.%d.%d" pool.ipbase n) in
- let s = Client.Session.login_with_password rpc "root" "xensource" "1.1" in
+ let s = Client.Session.login_with_password rpc "root" "xensource" "1.1" "perftest" in
let h = List.hd (Client.Host.get_all rpc s) in
let u = Client.Host.get_uuid rpc s h in
debug "Setting name of host %d" n;
@@ -295,7 +295,7 @@ let create_sdk_pool session_id sdkname pool_name key ipbase =
) hosts in
let poolrpc = remoterpc (Printf.sprintf "192.168.%d.1" pool.ipbase) in
- let poolses = Client.Session.login_with_password poolrpc "root" "xensource" "1.1" in
+ let poolses = Client.Session.login_with_password poolrpc "root" "xensource" "1.1" "perftest" in
let vpool=List.hd (Client.Pool.get_all poolrpc poolses) in
Client.Pool.add_to_other_config poolrpc poolses vpool "scenario" pool_name;
View
4 ocaml/perftest/perftest.ml
@@ -95,7 +95,7 @@ let _ =
List.iter (fun x -> debug "* %s" x) lines
| _ ->
- let session = Client.Session.login_with_password rpc "root" "xenroot" "1.2" in
+ let session = Client.Session.login_with_password rpc "root" "xenroot" "1.2" "perftest" in
let (_: API.string_to_string_map) = get_metadata rpc session in
finally
(fun () ->
@@ -111,7 +111,7 @@ let _ =
debug ~out:stderr "Not yet implemented ... ";
| "run" ->
let newrpc = if pool.Scenario.sdk then remoterpc (Printf.sprintf "192.168.%d.1" !ipbase) else rpc in
- let session = if pool.Scenario.sdk then Client.Session.login_with_password newrpc "root" "xensource" "1.2" else session in
+ let session = if pool.Scenario.sdk then Client.Session.login_with_password newrpc "root" "xensource" "1.2" "perftest" else session in
finally
(fun () -> marshall pool (get_metadata newrpc session) (Tests.run newrpc session !key !run_all !iter))
(fun () -> if pool.Scenario.sdk then Client.Session.logout newrpc session)
View
4 ocaml/sm-cli/test.ml
@@ -342,10 +342,10 @@ let _ =
rxtransport := (TCP (!host2, 80));
rtransport := (TCP (!host2, 80));
- let localsession = XapiClient.Session.login_with_password xrpc !username !password "1.0" in
+ let localsession = XapiClient.Session.login_with_password xrpc !username !password "1.0" "sm-cli" in
session := Ref.string_of localsession;
- let remotesession = XapiClient.Session.login_with_password rxrpc !username !password "1.0" in
+ let remotesession = XapiClient.Session.login_with_password rxrpc !username !password "1.0" "sm-cli" in
rsession := Ref.string_of remotesession;
let url = Printf.sprintf "http://%s/services/SM?session_id=%s" !host !session in
View
2  ocaml/toplevel/toplevelhelper.ml
@@ -24,4 +24,4 @@ let rpc xml =
open Client
let init_session username password =
- Client.Session.login_with_password ~rpc ~uname:username ~pwd:password ~version:"1.2"
+ Client.Session.login_with_password ~rpc ~uname:username ~pwd:password ~version:"1.2" ~originator:"toplevel"
View
2  ocaml/vncproxy/vncproxy.ml
@@ -73,7 +73,7 @@ let _ =
with _ ->
List.hd (Client.VM.get_by_name_label rpc session_id vm) in
- let session_id = Client.Session.login_with_password rpc !username !password "1.1" in
+ let session_id = Client.Session.login_with_password rpc !username !password "1.1" "vncproxy" in
finally
(fun () ->
let vm = find_vm rpc session_id !vm in
View
2  ocaml/xapi/cancel_tests.ml
@@ -402,7 +402,7 @@ let _ =
"Test VM lifecycle cancellation leaves the system in a valid state";
let rpc = make_rpc () in
- let session_id = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.2" in
+ let session_id = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.2" ~originator:"cancel_tests" in
finally
(fun () ->
match Client.VM.get_by_name_label ~rpc ~session_id ~label:!vm with
View
2  ocaml/xapi/cli_operations.ml
@@ -2492,7 +2492,7 @@ let vm_migrate printer rpc session_id params =
XMLRPC_protocol.rpc ~srcstr:"cli" ~dststr:"dst_xapi" ~transport:(SSL(SSL.make ~use_fork_exec_helper:false (), ip, 443)) ~http xml in
let username = List.assoc "remote-username" params in
let password = List.assoc "remote-password" params in
- let remote_session = Client.Session.login_with_password remote_rpc username password "1.3" in
+ let remote_session = Client.Session.login_with_password remote_rpc username password "1.3" "" in
finally
(fun () ->
let host, host_record =
View
2  ocaml/xapi/create_storage_main.ml
@@ -31,6 +31,6 @@ let _ =
let http = xmlrpc ~version:"1.0" "/" in
let rpc xml = XML_protocol.rpc ~transport:(TCP(!host, !port)) ~http xml in
let session_id = Client.Session.login_with_password ~rpc
- ~uname:!username ~pwd:!password ~version:Xapi_globs.api_version_string in
+ ~uname:!username ~pwd:!password ~version:Xapi_globs.api_version_string ~originator:"" in
create_storage_localhost rpc session_id;
Client.Session.logout ~rpc ~session_id
View
41 ocaml/xapi/db_gc.ml
@@ -221,7 +221,7 @@ let check_host_liveness ~__context =
let task_status_is_completed task_status =
(task_status=`success) || (task_status=`failure) || (task_status=`cancelled)
-let timeout_sessions_common ~__context sessions =
+let timeout_sessions_common ~__context sessions limit session_group =
let unused_sessions = List.filter
(fun (x, _) ->
let rec is_session_unused s =
@@ -243,19 +243,18 @@ let timeout_sessions_common ~__context sessions =
)
sessions
in
- let disposable_sessions = unused_sessions in
(* Only keep a list of (ref, last_active, uuid) *)
- let disposable_sessions = List.map (fun (x, y) -> x, Date.to_float y.Db_actions.session_last_active, y.Db_actions.session_uuid) disposable_sessions in
+ let disposable_sessions = List.map (fun (x, y) -> x, Date.to_float y.Db_actions.session_last_active, y.Db_actions.session_uuid) unused_sessions in
(* Definitely invalidate sessions last used long ago *)
let threshold_time = Unix.time () -. !Xapi_globs.inactive_session_timeout in
let young, old = List.partition (fun (_, y, _) -> y > threshold_time) disposable_sessions in
(* If there are too many young sessions then we need to delete the oldest *)
let lucky, unlucky =
- if List.length young <= Xapi_globs.max_sessions
+ if List.length young <= limit
then young, [] (* keep them all *)
else
(* Need to reverse sort by last active and drop the oldest *)
- List.chop Xapi_globs.max_sessions (List.sort (fun (_,a, _) (_,b, _) -> compare b a) young) in
+ List.chop limit (List.sort (fun (_,a, _) (_,b, _) -> compare b a) young) in
let cancel doc sessions =
List.iter
(fun (s, active, uuid) ->
@@ -264,19 +263,31 @@ let timeout_sessions_common ~__context sessions =
) sessions in
(* Only the 'lucky' survive: the 'old' and 'unlucky' are destroyed *)
if unlucky <> []
- then debug "Number of disposable sessions in database (%d/%d) exceeds limit (%d): will delete the oldest" (List.length disposable_sessions) (List.length sessions) Xapi_globs.max_sessions;
+ then debug "Number of disposable sessions in database (%d/%d) exceeds limit (%d): will delete the oldest" (List.length disposable_sessions) (List.length sessions) limit;
cancel "Timed out session because of its age" old;
cancel "Timed out session because max number of sessions was exceeded" unlucky
let timeout_sessions ~__context =
- let all_sessions =
- Db.Session.get_internal_records_where ~__context ~expr:Db_filter_types.True
- in
- let (intrapool_sessions, normal_sessions) =
- List.partition (fun (_, y) -> y.Db_actions.session_pool) all_sessions
- in begin
- timeout_sessions_common ~__context normal_sessions;
- timeout_sessions_common ~__context intrapool_sessions;
+ let all_sessions = Db.Session.get_internal_records_where ~__context ~expr:Db_filter_types.True in
+ let pool_sessions, nonpool_sessions = List.partition (fun (_, s) -> s.Db_actions.session_pool) all_sessions in
+ let use_root_auth_name s = s.Db_actions.session_auth_user_name = "" || s.Db_actions.session_auth_user_name = "root" in
+ let anon_sessions, named_sessions = List.partition (fun (_, s) -> s.Db_actions.session_originator = "" && use_root_auth_name s) nonpool_sessions in
+ let session_groups = Hashtbl.create 37 in
+ List.iter (function (_, s) as rs ->
+ let key = if use_root_auth_name s then `Orig s.Db_actions.session_originator else `Name s.Db_actions.session_auth_user_name in
+ let current_sessions =
+ try Hashtbl.find session_groups key
+ with Not_found -> [] in
+ Hashtbl.replace session_groups key (rs :: current_sessions)
+ ) named_sessions;
+ begin
+ Hashtbl.iter
+ (fun key ss -> match key with
+ | `Orig orig -> timeout_sessions_common ~__context ss Xapi_globs.max_sessions_per_originator ("originator:"^orig)
+ | `Name name -> timeout_sessions_common ~__context ss Xapi_globs.max_sessions_per_user_name ("username:"^name))
+ session_groups;
+ timeout_sessions_common ~__context anon_sessions Xapi_globs.max_sessions "external";
+ timeout_sessions_common ~__context pool_sessions Xapi_globs.max_sessions "internal";
end
let probation_pending_tasks = Hashtbl.create 53
@@ -470,8 +481,8 @@ let single_pass () =
"PGPUs", gc_PGPUs;
"Host patches", gc_Host_patches;
"Host CPUs", gc_host_cpus;
- "Sessions", timeout_sessions;
"Tasks", timeout_tasks;
+ "Sessions", timeout_sessions;
"Messages", gc_messages;
(* timeout_alerts; *)
(* CA-29253: wake up all blocked clients *)
View
2  ocaml/xapi/quicktest_common.ml
@@ -156,7 +156,7 @@ let rpc = ref rpc_unix_domain
let using_unix_domain_socket = ref true
let init_session username password =
- Client.Session.login_with_password ~rpc:!rpc ~uname:username ~pwd:password ~version:Xapi_globs.api_version_string
+ Client.Session.login_with_password ~rpc:!rpc ~uname:username ~pwd:password ~version:Xapi_globs.api_version_string ~originator:"quick_test"
let get_pool session_id =
let pool = Client.Pool.get_all !rpc session_id in
View
2  ocaml/xapi/xapi_cli.ml
@@ -68,7 +68,7 @@ let with_session ~local rpc u p session f =
let session, logout =
match local, session with
| false, None ->
- Client.Client.Session.login_with_password ~rpc ~uname:u ~pwd:p ~version:Xapi_globs.api_version_string, true
+ Client.Client.Session.login_with_password ~rpc ~uname:u ~pwd:p ~version:Xapi_globs.api_version_string ~originator:"cli", true
| true, None ->
Client.Client.Session.slave_local_login_with_password ~rpc ~uname:u ~pwd:p, true
| _, Some session -> session, false in
View
6 ocaml/xapi/xapi_globs.ml
@@ -234,6 +234,12 @@ let max_tasks = 200
(* We must allow for more sessions than running tasks *)
let max_sessions = max_tasks * 2
+(* For sessions with specified originator, their session limits are counted independently. *)
+let max_sessions_per_originator = 50
+
+(* For sessions with specifiied user name (non-root), their session limit are counted independently *)
+let max_sessions_per_user_name = 50
+
(* The Unix.time that represents the maximum time in the future that a 32 bit time can cope with *)
let the_future = 2147483647.0
View
4 ocaml/xapi/xapi_http.ml
@@ -144,7 +144,7 @@ let assert_credentials_ok realm ?(http_action=realm) ?(fn=Rbac.nofn) (req: Reque
| Some (Http.Basic(username, password)) ->
begin
let session_id = try
- Client.Session.login_with_password inet_rpc username password Xapi_globs.api_version_string
+ Client.Session.login_with_password inet_rpc username password Xapi_globs.api_version_string ""
with _ -> raise (Http.Unauthorised realm)
in
Pervasiveext.finally
@@ -181,7 +181,7 @@ let with_context ?(dummy=false) label (req: Request.t) (s: Unix.file_descr) f =
| Some (Http.Basic(username, password)) ->
begin
try
- Client.Session.login_with_password inet_rpc username password Xapi_globs.api_version_string, true
+ Client.Session.login_with_password inet_rpc username password Xapi_globs.api_version_string "", true
with Api_errors.Server_error(code, params) when code = Api_errors.session_authentication_failed ->
raise (Http.Unauthorised label)
end
View
2  ocaml/xapi/xapi_pool.ml
@@ -667,7 +667,7 @@ let join_common ~__context ~master_address ~master_username ~master_password ~fo
a host that does not support pooling then an error will be thrown at this stage *)
let rpc = rpc master_address in
let session_id =
- try Client.Session.login_with_password rpc master_username master_password Xapi_globs.api_version_string
+ try Client.Session.login_with_password rpc master_username master_password Xapi_globs.api_version_string ""
with Http_client.Http_request_rejected _ | Http_client.Http_error _ ->
raise (Api_errors.Server_error(Api_errors.pool_joining_host_service_failed, [])) in
View
26 ocaml/xapi/xapi_session.ml
@@ -266,9 +266,7 @@ let revalidate_all_sessions ~__context =
)with e -> (*unexpected exception: we absorb it and print out a debug line *)
debug "Unexpected exception while revalidating external sessions: %s" (ExnHelper.string_of_exn e)
-(* XXX: only used internally by the code which grants the guest access to the API.
- Needs to be protected by a proper access control system *)
-let login_no_password ~__context ~uname ~host ~pool ~is_local_superuser ~subject ~auth_user_sid ~auth_user_name ~rbac_permissions =
+let login_no_password_common ~__context ~uname ~originator ~host ~pool ~is_local_superuser ~subject ~auth_user_sid ~auth_user_name ~rbac_permissions =
let session_id = Ref.make () in
let uuid = Uuid.to_string (Uuid.make_uuid ()) in
let user = Ref.null in (* always return a null reference to the deprecated user object *)
@@ -282,22 +280,26 @@ let login_no_password ~__context ~uname ~host ~pool ~is_local_superuser ~subject
(* see also task creation in context.ml *)
(* CP-982: promote tracking debug line to info status *)
(* CP-982: create tracking id in log files to link username to actions *)
- info "Session.create %s pool=%b uname=%s is_local_superuser=%b auth_user_sid=%s parent=%s"
- (trackid session_id) pool (match uname with None->""|Some u->u) is_local_superuser auth_user_sid (trackid parent);
+ info "Session.create %s pool=%b uname=%s originator=%s is_local_superuser=%b auth_user_sid=%s parent=%s"
+ (trackid session_id) pool (match uname with None->""|Some u->u) originator is_local_superuser auth_user_sid (trackid parent);
Db.Session.create ~__context ~ref:session_id ~uuid
~this_user:user ~this_host:host ~pool:pool
~last_active:(Date.of_float (Unix.time ())) ~other_config:[]
~subject:subject ~is_local_superuser:is_local_superuser
~auth_user_sid ~validation_time:(Date.of_float (Unix.time ()))
- ~auth_user_name ~rbac_permissions ~parent;
+ ~auth_user_name ~rbac_permissions ~parent ~originator;
Rbac_audit.session_create ~__context ~session_id ~uname;
(* At this point, the session is created, but with an incorrect time *)
(* Force the time to be updated by calling an API function with this session *)
let rpc = Helpers.make_rpc ~__context in
ignore(Client.Session.get_uuid rpc session_id session_id);
-
session_id
+(* XXX: only used internally by the code which grants the guest access to the API.
+ Needs to be protected by a proper access control system *)
+let login_no_password ~__context ~uname ~host ~pool ~is_local_superuser ~subject ~auth_user_sid ~auth_user_name ~rbac_permissions =
+ login_no_password_common ~__context ~uname ~originator:"" ~host ~pool ~is_local_superuser ~subject ~auth_user_sid ~auth_user_name ~rbac_permissions
+
(** Cause the master to update the session last_active every 30s or so *)
let consider_touching_session rpc session_id =
let time = ref (Unix.gettimeofday ()) in
@@ -354,13 +356,13 @@ let slave_local_login_with_password ~__context ~uname ~pwd = wipe_params_after_f
- try and authenticate remotely, passing the supplied username/password to the external auth/directory service. (Note: see below for definition of 'authenticate remotely')
2. otherwise, Session.login_with_password will only attempt to authenticate against the local superuser credentials
*)
-let login_with_password ~__context ~uname ~pwd ~version = wipe_params_after_fn [pwd] (fun () ->
+let login_with_password ~__context ~uname ~pwd ~version ~originator = wipe_params_after_fn [pwd] (fun () ->
(* !!! Do something with the version number *)
if (Context.preauth ~__context) then
begin
(* in this case, the context origin of this login request is a unix socket bound locally to a filename *)
(* we trust requests from local unix filename sockets, so no need to authenticate them before login *)
- login_no_password ~__context ~uname:(Some uname) ~host:(Helpers.get_localhost ~__context)
+ login_no_password_common ~__context ~uname:(Some uname) ~originator ~host:(Helpers.get_localhost ~__context)
~pool:false ~is_local_superuser:true ~subject:(Ref.null)
~auth_user_sid:"" ~auth_user_name:uname ~rbac_permissions:[]
end
@@ -372,7 +374,7 @@ let login_with_password ~__context ~uname ~pwd ~version = wipe_params_after_fn [
else begin
do_local_auth uname pwd;
debug "Successful local authentication user %s from %s" uname (Context.get_origin __context);
- login_no_password ~__context ~uname:(Some uname) ~host:(Helpers.get_localhost ~__context)
+ login_no_password_common ~__context ~uname:(Some uname) ~originator ~host:(Helpers.get_localhost ~__context)
~pool:false ~is_local_superuser:true ~subject:(Ref.null) ~auth_user_sid:"" ~auth_user_name:uname
~rbac_permissions:[]
end
@@ -529,8 +531,8 @@ let login_with_password ~__context ~uname ~pwd ~version = wipe_params_after_fn [
debug "%s" msg;
thread_delay_and_raise_error uname msg
end
- ) in
- login_no_password ~__context ~uname:(Some uname) ~host:(Helpers.get_localhost ~__context)
+ ) in
+ login_no_password_common ~__context ~uname:(Some uname) ~originator ~host:(Helpers.get_localhost ~__context)
~pool:false ~is_local_superuser:false ~subject:subject ~auth_user_sid:subject_identifier ~auth_user_name:subject_name
~rbac_permissions
end
View
2  ocaml/xapi/xapi_session.mli
@@ -27,7 +27,7 @@ val consider_touching_session: (Rpc.call -> Rpc.response) -> API.ref_session ->
val slave_login: __context:Context.t -> host:[ `host ] Ref.t -> psecret:string -> [ `session ] Ref.t
val slave_local_login: __context:Context.t -> psecret:string -> API.ref_session
val slave_local_login_with_password: __context:Context.t -> uname:string -> pwd:string -> API.ref_session
-val login_with_password: __context:Context.t -> uname:string -> pwd:string -> version:'a -> [ `session ] Ref.t
+val login_with_password: __context:Context.t -> uname:string ->pwd:string -> version:'a -> originator:string -> [ `session ] Ref.t
val change_password: __context:Context.t -> old_pwd:string -> new_pwd:string -> unit
val logout: __context:Context.t -> unit
val local_logout: __context:Context.t -> unit
View
2  ocaml/xe-cli/import_main.ml
@@ -51,7 +51,7 @@ let _ =
let path = !path in
if path = "" then failwith "Must supply an XVA path (file or directory) as an argument";
- let session_id: API.ref_session = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password in
+ let session_id: API.ref_session = Client.Session.login_with_password ~rpc ~uname:!username ~pwd:!password ~version:"1.2" ~originator:"cli" in
let send_fn = match Import.classify path with
| Zurich -> stream_from_xva_dir path
Something went wrong with that request. Please try again.