Skip to content

Commit 1d77bfc

Browse files
authored
CP-54026: option to control VM-internal shutdown behaviour under HA (#6412)
Adds a new datamodel field in the pool class: bool pool.ha_reboot_vm_on_internal_shutdown The field is read/write, with the setter restricted to the pool-operator role. The default of this new field is `true` to reflect the current behaviour. This field controls what happens when HA is enabled and a protected VM is shut down internally (e.g. by pressing the shutdown button in Windows): - `true`: the VM is automatically restarted. - `false`: the VM is not restarted and left halted – consistent with the behaviour of shutting the VM down through the API. CLI: xe pool-param-set uuid=... ha-reboot-vm-on-internal-shutdown=false Whether an HA-protected VM is automatically (re)started depends on the field `VM.ha_always_run`, which is managed by xapi. This field is set to `true` when a protected VM is started, and to `false` when it is shut down through the API, which prevents the HA monitor thread from restarting it again. Setting the new pool-field to `false` does the same thing is such a VM is shut down from inside when handling the event in the xenopsd-events thread.
2 parents 012bead + 9ecacc8 commit 1d77bfc

File tree

8 files changed

+39
-6
lines changed

8 files changed

+39
-6
lines changed

ocaml/idl/datamodel_common.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ open Datamodel_roles
1010
to leave a gap for potential hotfixes needing to increment the schema version.*)
1111
let schema_major_vsn = 5
1212

13-
let schema_minor_vsn = 787
13+
let schema_minor_vsn = 788
1414

1515
(* Historical schema versions just in case this is useful later *)
1616
let rio_schema_major_vsn = 5

ocaml/idl/datamodel_lifecycle.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ let prototyped_of_field = function
110110
| "host", "last_software_update" ->
111111
Some "22.20.0"
112112
| "VM_guest_metrics", "services" ->
113-
Some "25.14.0-next"
113+
Some "25.15.0"
114114
| "VM_guest_metrics", "netbios_name" ->
115115
Some "24.28.0"
116116
| "VM", "groups" ->
@@ -123,6 +123,8 @@ let prototyped_of_field = function
123123
Some "23.18.0"
124124
| "VM", "actions__after_softreboot" ->
125125
Some "23.1.0"
126+
| "pool", "ha_reboot_vm_on_internal_shutdown" ->
127+
Some "25.15.0-next"
126128
| "pool", "license_server" ->
127129
Some "25.6.0"
128130
| "pool", "recommendations" ->

ocaml/idl/datamodel_pool.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,6 +2191,12 @@ let t =
21912191
~ty:(Map (String, String))
21922192
~default_value:(Some (VMap [])) "license_server"
21932193
"Licensing data shared within the whole pool"
2194+
; field ~writer_roles:_R_POOL_OP ~qualifier:RW ~lifecycle:[] ~ty:Bool
2195+
~default_value:(Some (VBool true))
2196+
"ha_reboot_vm_on_internal_shutdown"
2197+
"Indicates whether an HA-protected VM that is shut down from \
2198+
inside (not through the API) should be automatically rebooted \
2199+
when HA is enabled"
21942200
]
21952201
)
21962202
()

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 = "7756b4bea0be3985c1c8f6708f04d442"
6+
let last_known_schema_hash = "e10b420b0863116ee188eea9e63b1349"
77

88
let current_schema_hash : string =
99
let open Datamodel_types in

ocaml/tests/common/test_common.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ let make_pool ~__context ~master ?(name_label = "") ?(name_description = "")
300300
?(telemetry_next_collection = API.Date.epoch)
301301
?(last_update_sync = API.Date.epoch) ?(update_sync_frequency = `daily)
302302
?(update_sync_day = 0L) ?(update_sync_enabled = false)
303-
?(recommendations = []) ?(license_server = []) () =
303+
?(recommendations = []) ?(license_server = [])
304+
?(ha_reboot_vm_on_internal_shutdown = true) () =
304305
let pool_ref = Ref.make () in
305306
Db.Pool.create ~__context ~ref:pool_ref ~uuid:(make_uuid ()) ~name_label
306307
~name_description ~master ~default_SR ~suspend_image_SR ~crash_dump_SR
@@ -320,7 +321,8 @@ let make_pool ~__context ~master ?(name_label = "") ?(name_description = "")
320321
~local_auth_max_threads:8L ~ext_auth_max_threads:8L
321322
~ext_auth_cache_enabled:false ~ext_auth_cache_size:50L
322323
~ext_auth_cache_expiry:300L ~update_sync_frequency ~update_sync_day
323-
~update_sync_enabled ~recommendations ~license_server ;
324+
~update_sync_enabled ~recommendations ~license_server
325+
~ha_reboot_vm_on_internal_shutdown ;
324326
pool_ref
325327

326328
let default_sm_features =

ocaml/xapi-cli-server/records.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,15 @@ let pool_record rpc session_id pool =
12441244
; make_field ~name:"ha-overcommitted"
12451245
~get:(fun () -> string_of_bool (x ()).API.pool_ha_overcommitted)
12461246
()
1247+
; make_field ~name:"ha-reboot-vm-on-internal-shutdown"
1248+
~get:(fun () ->
1249+
string_of_bool (x ()).API.pool_ha_reboot_vm_on_internal_shutdown
1250+
)
1251+
~set:(fun x ->
1252+
Client.Pool.set_ha_reboot_vm_on_internal_shutdown ~rpc ~session_id
1253+
~self:pool ~value:(bool_of_string x)
1254+
)
1255+
()
12471256
; make_field ~name:"blobs"
12481257
~get:(fun () -> get_uuid_map_from_ref_map (x ()).API.pool_blobs)
12491258
()

ocaml/xapi/dbsync_master.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ let create_pool_record ~__context =
5454
~update_sync_day:0L ~update_sync_enabled:false ~local_auth_max_threads:8L
5555
~ext_auth_max_threads:1L ~ext_auth_cache_enabled:false
5656
~ext_auth_cache_size:50L ~ext_auth_cache_expiry:300L ~recommendations:[]
57-
~license_server:[]
57+
~license_server:[] ~ha_reboot_vm_on_internal_shutdown:true
5858

5959
let set_master_ip ~__context =
6060
let ip =

ocaml/xapi/xapi_xenops.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,20 @@ let update_vm ~__context id =
20332033
"Will update VM.allowed_operations because power_state has \
20342034
changed." ;
20352035
should_update_allowed_operations := true ;
2036+
(* Update ha_always_run before the power_state (if needed), to avoid racing
2037+
with the HA monitor thread. *)
2038+
let pool = Helpers.get_pool ~__context in
2039+
if
2040+
power_state = `Halted
2041+
&& not
2042+
(Db.Pool.get_ha_reboot_vm_on_internal_shutdown ~__context
2043+
~self:pool
2044+
)
2045+
then (
2046+
Db.VM.set_ha_always_run ~__context ~self ~value:false ;
2047+
debug "Setting ha_always_run on vm=%s as false after shutdown"
2048+
(Ref.string_of self)
2049+
) ;
20362050
debug "xenopsd event: Updating VM %s power_state <- %s" id
20372051
(Record_util.vm_power_state_to_string power_state) ;
20382052
(* This will mark VBDs, VIFs as detached and clear resident_on

0 commit comments

Comments
 (0)