Skip to content

Commit 527e124

Browse files
authored
CP-50537: TGroup library to manage the priority and classify xapi execution threads. (#6076)
This is the follow up to #6020 The initial phase is to classify the threads between Internal and External. - External is the default (for now), - Internal are threads that process internal requests coming from smapi. BVT + BST: 207007 (Dev Run)
2 parents a8f9bc6 + efaf3f0 commit 527e124

File tree

18 files changed

+366
-8
lines changed

18 files changed

+366
-8
lines changed

dune-project

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@
3737
)
3838
)
3939

40+
(package
41+
(name tgroup)
42+
(depends
43+
xapi-log
44+
xapi-stdext-unix)
45+
)
46+
4047
(package
4148
(name xml-light2)
4249
)
@@ -373,6 +380,7 @@
373380
tar
374381
tar-unix
375382
uri
383+
tgroup
376384
(uuid (= :version))
377385
uutf
378386
uuidm
@@ -585,6 +593,7 @@ This package provides an Lwt compatible interface to the library.")
585593
(safe-resources(= :version))
586594
sha
587595
(stunnel (= :version))
596+
tgroup
588597
uri
589598
(uuid (= :version))
590599
xapi-backtrace

http-lib.opam

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ depends: [
2222
"safe-resources" {= version}
2323
"sha"
2424
"stunnel" {= version}
25+
"tgroup"
2526
"uri"
2627
"uuid" {= version}
2728
"xapi-backtrace"

ocaml/libs/http-lib/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
http_lib
4545
ipaddr
4646
polly
47+
tgroup
4748
threads.posix
4849
tracing
4950
uri

ocaml/libs/http-lib/http.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ module Hdr = struct
132132

133133
let location = "location"
134134

135+
let originator = "originator"
136+
135137
let traceparent = "traceparent"
136138

137139
let hsts = "strict-transport-security"
@@ -688,6 +690,14 @@ module Request = struct
688690
let frame_header = if x.frame then make_frame_header headers else "" in
689691
frame_header ^ headers ^ body
690692

693+
let with_originator_of req f =
694+
Option.iter
695+
(fun req ->
696+
let originator = List.assoc_opt Hdr.originator req.additional_headers in
697+
f originator
698+
)
699+
req
700+
691701
let traceparent_of req =
692702
let open Tracing in
693703
let ( let* ) = Option.bind in

ocaml/libs/http-lib/http.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ module Request : sig
129129
val to_wire_string : t -> string
130130
(** [to_wire_string t] returns a string which could be sent to a server *)
131131

132+
val with_originator_of : t option -> (string option -> unit) -> unit
133+
132134
val traceparent_of : t -> Tracing.Span.t option
133135

134136
val with_tracing :

ocaml/libs/http-lib/http_svr.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,8 @@ let handle_connection ~header_read_timeout ~header_total_timeout
561561
~max_length:max_header_length ss
562562
in
563563

564+
Http.Request.with_originator_of req Tgroup.of_req_originator ;
565+
564566
(* 2. now we attempt to process the request *)
565567
let finished =
566568
Option.fold ~none:true

ocaml/libs/tgroup/dune

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
(library
2+
(name tgroup)
3+
(public_name tgroup)
4+
(libraries xapi-log xapi-stdext-unix))

ocaml/libs/tgroup/tgroup.ml

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
(*
2+
* Copyright (C) Cloud Software Group
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published
6+
* by the Free Software Foundation; version 2.1 only. with the special
7+
* exception on linking described in file LICENSE.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*)
14+
15+
module D = Debug.Make (struct let name = __MODULE__ end)
16+
17+
open D
18+
19+
let ( // ) = Filename.concat
20+
21+
module Group = struct
22+
module Internal = struct
23+
type t
24+
25+
let name = "internal"
26+
end
27+
28+
module External = struct
29+
type t
30+
31+
let name = "external"
32+
end
33+
34+
module Host = struct
35+
type t
36+
37+
let name = "host"
38+
end
39+
40+
module SM = struct
41+
type t
42+
43+
let name = "SM"
44+
end
45+
46+
type _ group =
47+
| Internal_Host_SM : (Internal.t * Host.t * SM.t) group
48+
| EXTERNAL : External.t group
49+
50+
type t = Group : 'a group -> t
51+
52+
let all = [Group Internal_Host_SM; Group EXTERNAL]
53+
54+
module Originator = struct
55+
type t = Internal_Host_SM | EXTERNAL
56+
57+
let of_string = function
58+
| s
59+
when String.equal
60+
(String.lowercase_ascii SM.name)
61+
(String.lowercase_ascii s) ->
62+
Internal_Host_SM
63+
| s
64+
when String.equal
65+
(String.lowercase_ascii External.name)
66+
(String.lowercase_ascii s) ->
67+
EXTERNAL
68+
| _ ->
69+
EXTERNAL
70+
71+
let to_string = function
72+
| Internal_Host_SM ->
73+
SM.name
74+
| EXTERNAL ->
75+
External.name
76+
end
77+
78+
module Creator = struct
79+
type t = {
80+
user: string option
81+
; endpoint: string option
82+
; originator: Originator.t
83+
}
84+
85+
let make ?user ?endpoint originator = {originator; user; endpoint}
86+
87+
let to_string c =
88+
Printf.sprintf "Creator -> user:%s endpoint:%s originator:%s"
89+
(Option.value c.user ~default:"")
90+
(Option.value c.endpoint ~default:"")
91+
(Originator.to_string c.originator)
92+
end
93+
94+
let of_originator = function
95+
| Originator.Internal_Host_SM ->
96+
Group Internal_Host_SM
97+
| Originator.EXTERNAL ->
98+
Group EXTERNAL
99+
100+
let get_originator = function
101+
| Group Internal_Host_SM ->
102+
Originator.Internal_Host_SM
103+
| Group EXTERNAL ->
104+
Originator.EXTERNAL
105+
106+
let of_creator creator = of_originator creator.Creator.originator
107+
108+
let to_cgroup : type a. a group -> string = function
109+
| Internal_Host_SM ->
110+
Internal.name // Host.name // SM.name
111+
| EXTERNAL ->
112+
External.name
113+
end
114+
115+
module Cgroup = struct
116+
type t = string
117+
118+
let cgroup_dir = Atomic.make None
119+
120+
let dir_of group : t option =
121+
match group with
122+
| Group.Group group ->
123+
Option.map
124+
(fun dir -> dir // Group.to_cgroup group)
125+
(Atomic.get cgroup_dir)
126+
127+
let write_cur_tid_to_cgroup_file filename =
128+
try
129+
let perms = 0o640 in
130+
let mode = [Unix.O_WRONLY; Unix.O_CREAT; Unix.O_TRUNC] in
131+
Xapi_stdext_unix.Unixext.with_file filename mode perms @@ fun fd ->
132+
(* Writing 0 to the task file will automatically transform in writing
133+
the current caller tid to the file.
134+
135+
Writing 0 to the processes file will automatically write the caller's
136+
pid to file. *)
137+
let buf = "0\n" in
138+
let len = String.length buf in
139+
if Unix.write fd (Bytes.unsafe_of_string buf) 0 len <> len then
140+
warn "writing current tid to %s failed" filename
141+
with exn ->
142+
warn "writing current tid to %s failed with exception: %s" filename
143+
(Printexc.to_string exn)
144+
145+
let attach_task group =
146+
Option.iter
147+
(fun dir ->
148+
let tasks_file = dir // "tasks" in
149+
write_cur_tid_to_cgroup_file tasks_file
150+
)
151+
(dir_of group)
152+
153+
let set_cur_cgroup ~originator =
154+
match originator with
155+
| Group.Originator.Internal_Host_SM ->
156+
attach_task (Group Internal_Host_SM)
157+
| Group.Originator.EXTERNAL ->
158+
attach_task (Group EXTERNAL)
159+
160+
let set_cgroup creator =
161+
set_cur_cgroup ~originator:creator.Group.Creator.originator
162+
163+
let init dir =
164+
let () = Atomic.set cgroup_dir (Some dir) in
165+
Group.all
166+
|> List.filter_map dir_of
167+
|> List.iter (fun dir -> Xapi_stdext_unix.Unixext.mkdir_rec dir 0o755) ;
168+
set_cur_cgroup ~originator:Group.Originator.EXTERNAL
169+
end
170+
171+
let of_originator originator =
172+
originator |> Group.Creator.make |> Cgroup.set_cgroup
173+
174+
let of_req_originator originator =
175+
Option.iter
176+
(fun _ ->
177+
try
178+
originator
179+
|> Option.value ~default:Group.Originator.(to_string EXTERNAL)
180+
|> Group.Originator.of_string
181+
|> of_originator
182+
with _ -> ()
183+
)
184+
(Atomic.get Cgroup.cgroup_dir)

ocaml/libs/tgroup/tgroup.mli

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
(*
2+
* Copyright (C) Cloud Software Group
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published
6+
* by the Free Software Foundation; version 2.1 only. with the special
7+
* exception on linking described in file LICENSE.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*)
14+
15+
(** [Group] module helps with the classification of different xapi execution
16+
threads.*)
17+
module Group : sig
18+
(** Abstract type that represents a group of execution threads in xapi. Each
19+
group corresponds to a Creator, and has a designated level of priority.*)
20+
type t
21+
22+
(** Generic representation of different xapi threads originators. *)
23+
module Originator : sig
24+
(** Type that represents different originators of xapi threads. *)
25+
type t = Internal_Host_SM | EXTERNAL
26+
27+
val of_string : string -> t
28+
(** [of_string s] creates an originator from a string [s].
29+
30+
e.g create an originator based on a http header. *)
31+
32+
val to_string : t -> string
33+
(** [to_string o] converts an originator [o] to its string representation.*)
34+
end
35+
36+
(** Generic representation of different xapi threads creators. *)
37+
module Creator : sig
38+
(** Abstract type that represents different creators of xapi threads.*)
39+
type t
40+
41+
val make : ?user:string -> ?endpoint:string -> Originator.t -> t
42+
(** [make o] creates a creator type based on a given originator [o].*)
43+
44+
val to_string : t -> string
45+
(** [to_string c] converts a creator [c] to its string representation.*)
46+
end
47+
48+
val get_originator : t -> Originator.t
49+
(** [get_originator group] returns the originator that maps to group [group].*)
50+
51+
val of_creator : Creator.t -> t
52+
(** [of_creator c] returns the corresponding group based on the creator [c].*)
53+
end
54+
55+
(** [Cgroup] module encapsulates different function for managing the cgroups
56+
corresponding with [Groups].*)
57+
module Cgroup : sig
58+
(** Represents one of the children of the cgroup directory.*)
59+
type t = string
60+
61+
val dir_of : Group.t -> t option
62+
(** [dir_of group] returns the full path of the cgroup directory corresponding
63+
to the group [group] as [Some dir].
64+
65+
Returns [None] if [init dir] has not been called. *)
66+
67+
val init : string -> unit
68+
(** [init dir] initializes the hierachy of cgroups associated to all [Group.t]
69+
types under the directory [dir].*)
70+
71+
val set_cgroup : Group.Creator.t -> unit
72+
(** [set_cgroup c] sets the current xapi thread in a cgroup based on the
73+
creator [c].*)
74+
end
75+
76+
val of_req_originator : string option -> unit
77+
(** [of_req_originator o] same as [of_originator] but it classifies based on the
78+
http request header.*)

ocaml/xapi/dune

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
tapctl
152152
tar
153153
tar-unix
154+
tgroup
154155
threads.posix
155156
tracing
156157
unixpwd
@@ -237,6 +238,7 @@
237238
rpclib.json
238239
rpclib.xml
239240
stunnel
241+
tgroup
240242
threads.posix
241243
tracing
242244
xapi-backtrace

ocaml/xapi/sm_exec.ml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ let with_dbg ~name ~dbg f =
3838
(*********************************************************************************************)
3939
(* Random utility functions *)
4040

41+
let env_vars =
42+
Array.concat
43+
[
44+
Forkhelpers.default_path_env_pair
45+
; Env_record.to_string_array [Env_record.pair ("ORIGINATOR", "SM")]
46+
]
47+
4148
type call = {
4249
(* All calls are performed by a specific Host with a special Session and device_config *)
4350
host_ref: API.ref_host
@@ -355,9 +362,9 @@ let exec_xmlrpc ~dbg ?context:_ ?(needs_session = true) (driver : string)
355362
let env, exe, args =
356363
match Xapi_observer_components.is_smapi_enabled () with
357364
| false ->
358-
(None, exe, args)
365+
(Some env_vars, exe, args)
359366
| true ->
360-
Xapi_observer_components.env_exe_args_of
367+
Xapi_observer_components.env_exe_args_of ~env_vars
361368
~component:Xapi_observer_components.SMApi ~exe ~args
362369
in
363370
Forkhelpers.execute_command_get_output ?tracing:di.tracing ?env

0 commit comments

Comments
 (0)