Skip to content

Commit 0b608d5

Browse files
authored
Merge SSH management Phase2 feature to next (#6500)
Merge feature branch `configure-ssh-phase2` to master
2 parents ee1e4c8 + 80b0d6f commit 0b608d5

17 files changed

+544
-28
lines changed

ocaml/idl/datamodel_errors.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2053,6 +2053,12 @@ let _ =
20532053
error Api_errors.disable_ssh_partially_failed ["hosts"]
20542054
~doc:"Some of hosts failed to disable SSH access." () ;
20552055

2056+
error Api_errors.set_ssh_timeout_partially_failed ["hosts"]
2057+
~doc:"Some hosts failed to set SSH timeout." () ;
2058+
2059+
error Api_errors.set_console_timeout_partially_failed ["hosts"]
2060+
~doc:"Some hosts failed to set console timeout." () ;
2061+
20562062
error Api_errors.host_driver_no_hardware ["driver variant"]
20572063
~doc:"No hardware present for this host driver variant" () ;
20582064

ocaml/idl/datamodel_host.ml

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,14 +1297,63 @@ let create_params =
12971297
; param_doc=
12981298
"The SHA256 checksum of updateinfo of the most recently applied update \
12991299
on the host"
1300-
; param_release= numbered_release "24.39.0-next"
1300+
; param_release= numbered_release "24.40.0"
13011301
; param_default= Some (VString "")
13021302
}
1303+
; {
1304+
param_type= Bool
1305+
; param_name= "ssh_enabled"
1306+
; param_doc= "True if SSH access is enabled for the host"
1307+
; param_release= numbered_release "25.20.0-next"
1308+
; param_default= Some (VBool Constants.default_ssh_enabled)
1309+
}
1310+
; {
1311+
param_type= Int
1312+
; param_name= "ssh_enabled_timeout"
1313+
; param_doc=
1314+
"The timeout in seconds after which SSH access will be automatically \
1315+
disabled (0 means never), this setting will be applied every time the \
1316+
SSH is enabled by XAPI"
1317+
; param_release= numbered_release "25.20.0-next"
1318+
; param_default= Some (VInt Constants.default_ssh_enabled_timeout)
1319+
}
1320+
; {
1321+
param_type= DateTime
1322+
; param_name= "ssh_expiry"
1323+
; param_doc=
1324+
"The time in UTC after which the SSH access will be automatically \
1325+
disabled"
1326+
; param_release= numbered_release "25.20.0-next"
1327+
; param_default= Some (VDateTime Date.epoch)
1328+
}
1329+
; {
1330+
param_type= Int
1331+
; param_name= "console_idle_timeout"
1332+
; param_doc=
1333+
"The timeout in seconds after which idle console will be automatically \
1334+
terminated (0 means never)"
1335+
; param_release= numbered_release "25.20.0-next"
1336+
; param_default= Some (VInt Constants.default_console_idle_timeout)
1337+
}
13031338
]
13041339

13051340
let create =
13061341
call ~name:"create" ~in_oss_since:None
1307-
~lifecycle:[(Published, rel_rio, "Create a new host record")]
1342+
~lifecycle:
1343+
[
1344+
(Published, rel_rio, "Create a new host record")
1345+
; ( Changed
1346+
, "24.40.0"
1347+
, "Added --last_update_hash option to allow last_update_hash to be \
1348+
kept for host joined a pool"
1349+
)
1350+
; ( Changed
1351+
, "25.20.0-next"
1352+
, "Added --ssh_enabled --ssh_enabled_timeout --ssh_expiry \
1353+
--console_idle_timeout options to allow them to be configured for \
1354+
new host"
1355+
)
1356+
]
13081357
~versioned_params:create_params ~doc:"Create a new host record"
13091358
~result:(Ref _host, "Reference to the newly created host object.")
13101359
~hide_from_docs:true ~allowed_roles:_R_POOL_OP ()
@@ -2368,6 +2417,29 @@ let disable_ssh =
23682417
~params:[(Ref _host, "self", "The host")]
23692418
~allowed_roles:_R_POOL_ADMIN ()
23702419

2420+
let set_ssh_enabled_timeout =
2421+
call ~name:"set_ssh_enabled_timeout" ~lifecycle:[]
2422+
~doc:"Set the SSH service enabled timeout for the host"
2423+
~params:
2424+
[
2425+
(Ref _host, "self", "The host")
2426+
; ( Int
2427+
, "value"
2428+
, "The SSH enabled timeout in seconds (0 means no timeout, max 2 days)"
2429+
)
2430+
]
2431+
~allowed_roles:_R_POOL_ADMIN ()
2432+
2433+
let set_console_idle_timeout =
2434+
call ~name:"set_console_idle_timeout" ~lifecycle:[]
2435+
~doc:"Set the console idle timeout for the host"
2436+
~params:
2437+
[
2438+
(Ref _host, "self", "The host")
2439+
; (Int, "value", "The console idle timeout in seconds")
2440+
]
2441+
~allowed_roles:_R_POOL_ADMIN ()
2442+
23712443
let latest_synced_updates_applied_state =
23722444
Enum
23732445
( "latest_synced_updates_applied_state"
@@ -2527,6 +2599,8 @@ let t =
25272599
; emergency_clear_mandatory_guidance
25282600
; enable_ssh
25292601
; disable_ssh
2602+
; set_ssh_enabled_timeout
2603+
; set_console_idle_timeout
25302604
]
25312605
~contents:
25322606
([
@@ -2964,6 +3038,24 @@ let t =
29643038
~default_value:(Some (VString "")) "last_update_hash"
29653039
"The SHA256 checksum of updateinfo of the most recently applied \
29663040
update on the host"
3041+
; field ~qualifier:DynamicRO ~lifecycle:[] ~ty:Bool
3042+
~default_value:(Some (VBool Constants.default_ssh_enabled))
3043+
"ssh_enabled" "True if SSH access is enabled for the host"
3044+
; field ~qualifier:DynamicRO ~lifecycle:[] ~ty:Int
3045+
~default_value:(Some (VInt Constants.default_ssh_enabled_timeout))
3046+
"ssh_enabled_timeout"
3047+
"The timeout in seconds after which SSH access will be \
3048+
automatically disabled (0 means never), this setting will be \
3049+
applied every time the SSH is enabled by XAPI"
3050+
; field ~qualifier:DynamicRO ~lifecycle:[] ~ty:DateTime
3051+
~default_value:(Some (VDateTime Date.epoch)) "ssh_expiry"
3052+
"The time in UTC after which the SSH access will be automatically \
3053+
disabled"
3054+
; field ~qualifier:DynamicRO ~lifecycle:[] ~ty:Int
3055+
~default_value:(Some (VInt Constants.default_console_idle_timeout))
3056+
"console_idle_timeout"
3057+
"The timeout in seconds after which idle console will be \
3058+
automatically terminated (0 means never)"
29673059
]
29683060
)
29693061
()

ocaml/idl/datamodel_pool.ml

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,15 @@ let remove_repository =
12491249

12501250
let sync_updates =
12511251
call ~name:"sync_updates"
1252-
~lifecycle:[(Published, "1.329.0", "")]
1252+
~lifecycle:
1253+
[
1254+
(Published, "1.329.0", "")
1255+
; ( Changed
1256+
, "25.7.0"
1257+
, "Added --username --password options to allow syncing updates from a \
1258+
remote_pool type repository"
1259+
)
1260+
]
12531261
~doc:"Sync with the enabled repository"
12541262
~versioned_params:
12551263
[
@@ -1286,14 +1294,14 @@ let sync_updates =
12861294
param_type= String
12871295
; param_name= "username"
12881296
; param_doc= "The username of the remote pool"
1289-
; param_release= numbered_release "25.6.0-next"
1297+
; param_release= numbered_release "25.7.0"
12901298
; param_default= Some (VString "")
12911299
}
12921300
; {
12931301
param_type= String
12941302
; param_name= "password"
12951303
; param_doc= "The password of the remote pool"
1296-
; param_release= numbered_release "25.6.0-next"
1304+
; param_release= numbered_release "25.7.0"
12971305
; param_default= Some (VString "")
12981306
}
12991307
]
@@ -1571,6 +1579,33 @@ let disable_ssh =
15711579
~params:[(Ref _pool, "self", "The pool")]
15721580
~allowed_roles:_R_POOL_ADMIN ()
15731581

1582+
let set_ssh_enabled_timeout =
1583+
call ~name:"set_ssh_enabled_timeout" ~lifecycle:[]
1584+
~doc:"Set the SSH enabled timeout for all hosts in the pool"
1585+
~params:
1586+
[
1587+
(Ref _pool, "self", "The pool")
1588+
; ( Int
1589+
, "value"
1590+
, "The SSH enabled timeout in seconds. (0 means no timeout, max 2 days)"
1591+
)
1592+
]
1593+
~allowed_roles:_R_POOL_ADMIN ()
1594+
1595+
let set_console_idle_timeout =
1596+
call ~name:"set_console_idle_timeout" ~lifecycle:[]
1597+
~doc:"Set the console idle timeout for all hosts in the pool"
1598+
~params:
1599+
[
1600+
(Ref _pool, "self", "The pool")
1601+
; ( Int
1602+
, "value"
1603+
, "The idle SSH/VNC session timeout in seconds. A value of 0 means no \
1604+
timeout."
1605+
)
1606+
]
1607+
~allowed_roles:_R_POOL_ADMIN ()
1608+
15741609
(** A pool class *)
15751610
let t =
15761611
create_obj ~in_db:true
@@ -1667,6 +1702,8 @@ let t =
16671702
; get_guest_secureboot_readiness
16681703
; enable_ssh
16691704
; disable_ssh
1705+
; set_ssh_enabled_timeout
1706+
; set_console_idle_timeout
16701707
]
16711708
~contents:
16721709
([

ocaml/idl/schematest.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ let hash x = Digest.string x |> Digest.to_hex
33
(* BEWARE: if this changes, check that schema has been bumped accordingly in
44
ocaml/idl/datamodel_common.ml, usually schema_minor_vsn *)
55

6-
let last_known_schema_hash = "2f80cd8fbfd0eedab4dfe345565bcb64"
6+
let last_known_schema_hash = "dc1ccf295f957509f7eac4a005d17965"
77

88
let current_schema_hash : string =
99
let open Datamodel_types in

ocaml/tests/common/test_common.ml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,16 @@ let make_host ~__context ?(uuid = make_uuid ()) ?(name_label = "host")
170170
?(external_auth_service_name = "") ?(external_auth_configuration = [])
171171
?(license_params = []) ?(edition = "free") ?(license_server = [])
172172
?(local_cache_sr = Ref.null) ?(chipset_info = []) ?(ssl_legacy = false)
173-
?(last_software_update = Date.epoch) ?(last_update_hash = "") () =
173+
?(last_software_update = Date.epoch) ?(last_update_hash = "")
174+
?(ssh_enabled = true) ?(ssh_enabled_timeout = 0L) ?(ssh_expiry = Date.epoch)
175+
?(console_idle_timeout = 0L) () =
174176
let host =
175177
Xapi_host.create ~__context ~uuid ~name_label ~name_description ~hostname
176178
~address ~external_auth_type ~external_auth_service_name
177179
~external_auth_configuration ~license_params ~edition ~license_server
178180
~local_cache_sr ~chipset_info ~ssl_legacy ~last_software_update
179-
~last_update_hash
181+
~last_update_hash ~ssh_enabled ~ssh_enabled_timeout ~ssh_expiry
182+
~console_idle_timeout
180183
in
181184
Db.Host.set_cpu_info ~__context ~self:host ~value:default_cpu_info ;
182185
host
@@ -215,7 +218,8 @@ let make_host2 ~__context ?(ref = Ref.make ()) ?(uuid = make_uuid ())
215218
~last_software_update:(Xapi_host.get_servertime ~__context ~host:ref)
216219
~recommended_guidances:[] ~latest_synced_updates_applied:`unknown
217220
~pending_guidances_recommended:[] ~pending_guidances_full:[]
218-
~last_update_hash:"" ;
221+
~last_update_hash:"" ~ssh_enabled:true ~ssh_enabled_timeout:0L
222+
~ssh_expiry:Date.epoch ~console_idle_timeout:0L ;
219223
ref
220224

221225
let make_pif ~__context ~network ~host ?(device = "eth0")

ocaml/tests/test_host.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ let add_host __context name =
2424
~license_params:[] ~edition:"" ~license_server:[]
2525
~local_cache_sr:Ref.null ~chipset_info:[] ~ssl_legacy:false
2626
~last_software_update:Clock.Date.epoch ~last_update_hash:""
27+
~ssh_enabled:true ~ssh_enabled_timeout:0L ~ssh_expiry:Clock.Date.epoch
28+
~console_idle_timeout:0L
2729
)
2830

2931
(* Creates an unlicensed pool with the maximum number of hosts *)

ocaml/xapi-cli-server/records.ml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ let nullref = Ref.string_of Ref.null
2020

2121
let nid = "<not in database>"
2222

23+
let inconsistent = "<inconsistent>"
24+
2325
let unknown_time = "<unknown time>"
2426

2527
let string_of_float f = Printf.sprintf "%.3f" f
@@ -204,6 +206,37 @@ let get_pbds_host rpc session_id pbds =
204206
let get_sr_host rpc session_id record =
205207
get_pbds_host rpc session_id record.API.sR_PBDs
206208

209+
(** Get consistent field from all hosts, or return a default value if the field
210+
is not the same on all hosts. *)
211+
let get_consistent_field_or_default ~rpc ~session_id ~getter ~transform ~default
212+
=
213+
match Client.Host.get_all ~rpc ~session_id with
214+
| [] ->
215+
default
216+
| hosts -> (
217+
let result =
218+
List.fold_left
219+
(fun acc host ->
220+
match acc with
221+
| `Inconsistent ->
222+
`Inconsistent
223+
| `NotSet ->
224+
`Value (getter ~rpc ~session_id ~self:host |> transform)
225+
| `Value v ->
226+
let current = getter ~rpc ~session_id ~self:host |> transform in
227+
if v = current then `Value v else `Inconsistent
228+
)
229+
`NotSet hosts
230+
in
231+
match result with
232+
| `Value v ->
233+
v
234+
| `Inconsistent ->
235+
default
236+
| `NotSet ->
237+
default
238+
)
239+
207240
let bond_record rpc session_id bond =
208241
let _ref = ref bond in
209242
let empty_record =
@@ -1515,6 +1548,42 @@ let pool_record rpc session_id pool =
15151548
)
15161549
~get_map:(fun () -> (x ()).API.pool_license_server)
15171550
()
1551+
; make_field ~name:"ssh-enabled"
1552+
~get:(fun () ->
1553+
get_consistent_field_or_default ~rpc ~session_id
1554+
~getter:Client.Host.get_ssh_enabled ~transform:string_of_bool
1555+
~default:inconsistent
1556+
)
1557+
()
1558+
; make_field ~name:"ssh-enabled-timeout"
1559+
~get:(fun () ->
1560+
get_consistent_field_or_default ~rpc ~session_id
1561+
~getter:Client.Host.get_ssh_enabled_timeout
1562+
~transform:Int64.to_string ~default:inconsistent
1563+
)
1564+
~set:(fun value ->
1565+
Client.Pool.set_ssh_enabled_timeout ~rpc ~session_id ~self:pool
1566+
~value:(safe_i64_of_string "ssh-enabled-timeout" value)
1567+
)
1568+
()
1569+
; make_field ~name:"ssh-expiry"
1570+
~get:(fun () ->
1571+
get_consistent_field_or_default ~rpc ~session_id
1572+
~getter:Client.Host.get_ssh_expiry ~transform:Date.to_rfc3339
1573+
~default:inconsistent
1574+
)
1575+
()
1576+
; make_field ~name:"console-idle-timeout"
1577+
~get:(fun () ->
1578+
get_consistent_field_or_default ~rpc ~session_id
1579+
~getter:Client.Host.get_console_idle_timeout
1580+
~transform:Int64.to_string ~default:inconsistent
1581+
)
1582+
~set:(fun value ->
1583+
Client.Pool.set_console_idle_timeout ~rpc ~session_id ~self:pool
1584+
~value:(safe_i64_of_string "console-idle-timeout" value)
1585+
)
1586+
()
15181587
]
15191588
}
15201589

@@ -3286,6 +3355,26 @@ let host_record rpc session_id host =
32863355
; make_field ~name:"last-update-hash"
32873356
~get:(fun () -> (x ()).API.host_last_update_hash)
32883357
()
3358+
; make_field ~name:"ssh-enabled"
3359+
~get:(fun () -> string_of_bool (x ()).API.host_ssh_enabled)
3360+
()
3361+
; make_field ~name:"ssh-enabled-timeout"
3362+
~get:(fun () -> Int64.to_string (x ()).API.host_ssh_enabled_timeout)
3363+
~set:(fun value ->
3364+
Client.Host.set_ssh_enabled_timeout ~rpc ~session_id ~self:host
3365+
~value:(safe_i64_of_string "ssh-enabled-timeout" value)
3366+
)
3367+
()
3368+
; make_field ~name:"ssh-expiry"
3369+
~get:(fun () -> Date.to_rfc3339 (x ()).API.host_ssh_expiry)
3370+
()
3371+
; make_field ~name:"console-idle-timeout"
3372+
~get:(fun () -> Int64.to_string (x ()).API.host_console_idle_timeout)
3373+
~set:(fun value ->
3374+
Client.Host.set_console_idle_timeout ~rpc ~session_id ~self:host
3375+
~value:(safe_i64_of_string "console-idle-timeout" value)
3376+
)
3377+
()
32893378
]
32903379
}
32913380

ocaml/xapi-consts/api_errors.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,6 +1428,12 @@ let enable_ssh_partially_failed = add_error "ENABLE_SSH_PARTIALLY_FAILED"
14281428

14291429
let disable_ssh_partially_failed = add_error "DISABLE_SSH_PARTIALLY_FAILED"
14301430

1431+
let set_ssh_timeout_partially_failed =
1432+
add_error "SET_SSH_TIMEOUT_PARTIALLY_FAILED"
1433+
1434+
let set_console_timeout_partially_failed =
1435+
add_error "SET_CONSOLE_TIMEOUT_PARTIALLY_FAILED"
1436+
14311437
let host_driver_no_hardware = add_error "HOST_DRIVER_NO_HARDWARE"
14321438

14331439
let tls_verification_not_enabled_in_pool =

0 commit comments

Comments
 (0)