Skip to content

Commit 90e9602

Browse files
authored
CP-52074: Add API for start/stop systemd service sshd (xapi-project#6198)
This PR is to add API and CLI which is used to enable and disable SSH on all hosts in a pool or on specified hosts within a pool.
2 parents 9eeb1f3 + 944a91d commit 90e9602

File tree

16 files changed

+271
-6
lines changed

16 files changed

+271
-6
lines changed

ocaml/forkexecd/lib/fe_systemctl.ml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,19 @@ let stop ~service =
121121
Xapi_stdext_unix.Unixext.unlink_safe destination ;
122122
status
123123

124-
let is_active ~service =
124+
let status ~command ~service =
125125
let status =
126126
Forkhelpers.safe_close_and_exec None None None [] systemctl
127-
["is-active"; "--quiet"; service]
127+
[command; "--quiet"; service]
128128
|> Forkhelpers.waitpid
129129
|> snd
130130
in
131131
Unix.WEXITED 0 = status
132132

133+
let is_active ~service = status ~command:"is-active" ~service
134+
135+
let is_enabled ~service = status ~command:"is-enabled" ~service
136+
133137
(** path to service file *)
134138
let path service = Filename.concat run_path (service ^ ".service")
135139

ocaml/forkexecd/lib/fe_systemctl.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ val start_transient :
4545
val is_active : service:string -> bool
4646
(** [is_active ~service] checks whether the [service] is still running *)
4747

48+
val is_enabled : service:string -> bool
49+
(** [is_enabled ~service] checks whether the [service] is enabled *)
50+
4851
val show : service:string -> status
4952
(** [shows ~service] retrieves the exitcodes and PIDs of the specified [service] *)
5053

ocaml/idl/datamodel_errors.ml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,6 +2010,18 @@ let _ =
20102010

20112011
error Api_errors.too_many_groups [] ~doc:"VM can only belong to one group." () ;
20122012

2013+
error Api_errors.enable_ssh_failed ["host"]
2014+
~doc:"Failed to enable SSH access." () ;
2015+
2016+
error Api_errors.disable_ssh_failed ["host"]
2017+
~doc:"Failed to disable SSH access." () ;
2018+
2019+
error Api_errors.enable_ssh_partially_failed ["hosts"]
2020+
~doc:"Some of hosts failed to enable SSH access." () ;
2021+
2022+
error Api_errors.disable_ssh_partially_failed ["hosts"]
2023+
~doc:"Some of hosts failed to disable SSH access." () ;
2024+
20132025
message
20142026
(fst Api_messages.ha_pool_overcommitted)
20152027
~doc:

ocaml/idl/datamodel_host.ml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2338,6 +2338,28 @@ let emergency_clear_mandatory_guidance =
23382338
~doc:"Clear the pending mandatory guidance on this host"
23392339
~allowed_roles:_R_LOCAL_ROOT_ONLY ()
23402340

2341+
let enable_ssh =
2342+
call ~name:"enable_ssh"
2343+
~doc:
2344+
"Enable SSH access on the host. It will start the service sshd only if \
2345+
it is not running. It will also enable the service sshd only if it is \
2346+
not enabled. A newly joined host in the pool or an ejected host from \
2347+
the pool would keep the original status."
2348+
~lifecycle:[]
2349+
~params:[(Ref _host, "self", "The host")]
2350+
~allowed_roles:_R_POOL_ADMIN ()
2351+
2352+
let disable_ssh =
2353+
call ~name:"disable_ssh"
2354+
~doc:
2355+
"Disable SSH access on the host. It will stop the service sshd only if \
2356+
it is running. It will also disable the service sshd only if it is \
2357+
enabled. A newly joined host in the pool or an ejected host from the \
2358+
pool would keep the original status."
2359+
~lifecycle:[]
2360+
~params:[(Ref _host, "self", "The host")]
2361+
~allowed_roles:_R_POOL_ADMIN ()
2362+
23412363
let latest_synced_updates_applied_state =
23422364
Enum
23432365
( "latest_synced_updates_applied_state"
@@ -2494,6 +2516,8 @@ let t =
24942516
; set_https_only
24952517
; apply_recommended_guidances
24962518
; emergency_clear_mandatory_guidance
2519+
; enable_ssh
2520+
; disable_ssh
24972521
]
24982522
~contents:
24992523
([

ocaml/idl/datamodel_pool.ml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,24 @@ let get_guest_secureboot_readiness =
15391539
~result:(pool_guest_secureboot_readiness, "The readiness of the pool")
15401540
~allowed_roles:_R_POOL_OP ()
15411541

1542+
let enable_ssh =
1543+
call ~name:"enable_ssh"
1544+
~doc:
1545+
"Enable SSH access on all hosts in the pool. It's a helper which calls \
1546+
host.enable_ssh for all the hosts in the pool."
1547+
~lifecycle:[]
1548+
~params:[(Ref _pool, "self", "The pool")]
1549+
~allowed_roles:_R_POOL_ADMIN ()
1550+
1551+
let disable_ssh =
1552+
call ~name:"disable_ssh"
1553+
~doc:
1554+
"Disable SSH access on all hosts in the pool. It's a helper which calls \
1555+
host.disable_ssh for all the hosts in the pool."
1556+
~lifecycle:[]
1557+
~params:[(Ref _pool, "self", "The pool")]
1558+
~allowed_roles:_R_POOL_ADMIN ()
1559+
15421560
(** A pool class *)
15431561
let t =
15441562
create_obj ~in_db:true
@@ -1633,6 +1651,8 @@ let t =
16331651
; set_ext_auth_cache_size
16341652
; set_ext_auth_cache_expiry
16351653
; get_guest_secureboot_readiness
1654+
; enable_ssh
1655+
; disable_ssh
16361656
]
16371657
~contents:
16381658
([

ocaml/sdk-gen/go/gen_go_helper.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ let acronyms =
3838
; "db"
3939
; "xml"
4040
; "eof"
41+
; "ssh"
4142
]
4243
|> StringSet.of_list
4344

ocaml/xapi-cli-server/cli_frontend.ml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,32 @@ let rec cmdtable_data : (string * cmd_spec) list =
10481048
; flags= [Host_selectors]
10491049
}
10501050
)
1051+
; ( "host-enable-ssh"
1052+
, {
1053+
reqd= []
1054+
; optn= []
1055+
; help=
1056+
"Enable SSH access on the host. It will start the service sshd only \
1057+
if it is not running. It will also enable the service sshd only if \
1058+
it is not enabled. A newly joined host in the pool or an ejected \
1059+
host from the pool would keep the original status."
1060+
; implementation= No_fd Cli_operations.host_enable_ssh
1061+
; flags= [Host_selectors]
1062+
}
1063+
)
1064+
; ( "host-disable-ssh"
1065+
, {
1066+
reqd= []
1067+
; optn= []
1068+
; help=
1069+
"Disable SSH access on the host. It will stop the service sshd only \
1070+
if it is running. It will also disable the service sshd only if it \
1071+
is enabled. A newly joined host in the pool or an ejected host from \
1072+
the pool would keep the original status."
1073+
; implementation= No_fd Cli_operations.host_disable_ssh
1074+
; flags= [Host_selectors]
1075+
}
1076+
)
10511077
; ( "host-emergency-clear-mandatory-guidance"
10521078
, {
10531079
reqd= []
@@ -3105,6 +3131,28 @@ let rec cmdtable_data : (string * cmd_spec) list =
31053131
; flags= []
31063132
}
31073133
)
3134+
; ( "pool-enable-ssh"
3135+
, {
3136+
reqd= []
3137+
; optn= []
3138+
; help=
3139+
"Enable SSH access on all hosts in the pool. It's a helper which \
3140+
calls host.enable_ssh for all the hosts in the pool."
3141+
; implementation= No_fd Cli_operations.pool_enable_ssh
3142+
; flags= []
3143+
}
3144+
)
3145+
; ( "pool-disable-ssh"
3146+
, {
3147+
reqd= []
3148+
; optn= []
3149+
; help=
3150+
"Disable SSH access on all hosts in the pool. It's a helper which \
3151+
calls host.disable_ssh for all the hosts in the pool."
3152+
; implementation= No_fd Cli_operations.pool_disable_ssh
3153+
; flags= []
3154+
}
3155+
)
31083156
; ( "host-ha-xapi-healthcheck"
31093157
, {
31103158
reqd= []

ocaml/xapi-cli-server/cli_operations.ml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6779,6 +6779,14 @@ let pool_sync_bundle fd _printer rpc session_id params =
67796779
| None ->
67806780
failwith "Required parameter not found: filename"
67816781

6782+
let pool_enable_ssh _printer rpc session_id params =
6783+
let pool = get_pool_with_default rpc session_id params "uuid" in
6784+
Client.Pool.enable_ssh ~rpc ~session_id ~self:pool
6785+
6786+
let pool_disable_ssh _printer rpc session_id params =
6787+
let pool = get_pool_with_default rpc session_id params "uuid" in
6788+
Client.Pool.disable_ssh ~rpc ~session_id ~self:pool
6789+
67826790
let host_restore fd _printer rpc session_id params =
67836791
let filename = List.assoc "file-name" params in
67846792
let op _ host =
@@ -7729,6 +7737,26 @@ let host_apply_updates _printer rpc session_id params =
77297737
params ["hash"]
77307738
)
77317739

7740+
let host_enable_ssh _printer rpc session_id params =
7741+
ignore
7742+
(do_host_op rpc session_id
7743+
(fun _ host ->
7744+
let host = host.getref () in
7745+
Client.Host.enable_ssh ~rpc ~session_id ~self:host
7746+
)
7747+
params []
7748+
)
7749+
7750+
let host_disable_ssh _printer rpc session_id params =
7751+
ignore
7752+
(do_host_op rpc session_id
7753+
(fun _ host ->
7754+
let host = host.getref () in
7755+
Client.Host.disable_ssh ~rpc ~session_id ~self:host
7756+
)
7757+
params []
7758+
)
7759+
77327760
module SDN_controller = struct
77337761
let introduce printer rpc session_id params =
77347762
let port =

ocaml/xapi-consts/api_errors.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,3 +1403,11 @@ let telemetry_next_collection_too_late =
14031403
let illegal_in_fips_mode = add_error "ILLEGAL_IN_FIPS_MODE"
14041404

14051405
let too_many_groups = add_error "TOO_MANY_GROUPS"
1406+
1407+
let enable_ssh_failed = add_error "ENABLE_SSH_FAILED"
1408+
1409+
let disable_ssh_failed = add_error "DISABLE_SSH_FAILED"
1410+
1411+
let enable_ssh_partially_failed = add_error "ENABLE_SSH_PARTIALLY_FAILED"
1412+
1413+
let disable_ssh_partially_failed = add_error "DISABLE_SSH_PARTIALLY_FAILED"

ocaml/xapi/message_forwarding.ml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,14 @@ functor
11851185
let get_guest_secureboot_readiness ~__context ~self =
11861186
info "%s: pool='%s'" __FUNCTION__ (pool_uuid ~__context self) ;
11871187
Local.Pool.get_guest_secureboot_readiness ~__context ~self
1188+
1189+
let enable_ssh ~__context ~self =
1190+
info "%s: pool = '%s'" __FUNCTION__ (pool_uuid ~__context self) ;
1191+
Local.Pool.enable_ssh ~__context ~self
1192+
1193+
let disable_ssh ~__context ~self =
1194+
info "%s: pool = '%s'" __FUNCTION__ (pool_uuid ~__context self) ;
1195+
Local.Pool.disable_ssh ~__context ~self
11881196
end
11891197

11901198
module VM = struct
@@ -4154,6 +4162,20 @@ functor
41544162
let emergency_clear_mandatory_guidance ~__context =
41554163
info "Host.emergency_clear_mandatory_guidance" ;
41564164
Local.Host.emergency_clear_mandatory_guidance ~__context
4165+
4166+
let enable_ssh ~__context ~self =
4167+
info "%s: host = '%s'" __FUNCTION__ (host_uuid ~__context self) ;
4168+
let local_fn = Local.Host.enable_ssh ~self in
4169+
do_op_on ~local_fn ~__context ~host:self (fun session_id rpc ->
4170+
Client.Host.enable_ssh ~rpc ~session_id ~self
4171+
)
4172+
4173+
let disable_ssh ~__context ~self =
4174+
info "%s: host = '%s'" __FUNCTION__ (host_uuid ~__context self) ;
4175+
let local_fn = Local.Host.disable_ssh ~self in
4176+
do_op_on ~local_fn ~__context ~host:self (fun session_id rpc ->
4177+
Client.Host.disable_ssh ~rpc ~session_id ~self
4178+
)
41574179
end
41584180

41594181
module Host_crashdump = struct

0 commit comments

Comments
 (0)