Skip to content

Commit 83169b4

Browse files
simonjbeaumontKonstantina Chremmou
authored andcommitted
CP-17481: is_control_domain =/=> domain zero
The API has always had documentation that allows for more than one VM to have `is_control_domain = true`: > field ... "is_control_domain" "true if this is a control domain (domain 0 or a driver domain)"; Most of Xapi has been written with this in mind, e.g. `Xapi_host.destroy` which iterates through a list, `my_control_domains`. However there are a few places where it is assumed that dom0 is the only VM with `is_control_domain = true` and this patch makes these a bit more sane. Where the original code assumed only one control domain and did an operation that only makes sense for domain 0, an additional filter is applied to only operate on VMs with `domid = 0`. Where the original code assumed only one control domain and did an operation that makes sense for all control domains then this has been extended to operate on the list of VMs with `is_control_domain = true`. Signed-off-by: Si Beaumont <simon.beaumont@citrix.com>
1 parent 8c108e2 commit 83169b4

11 files changed

+56
-46
lines changed

ocaml/xapi/helpers.ml

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,11 @@ let get_user ~__context username =
310310
failwith "Failed to find any users";
311311
List.hd uuids (* FIXME! it assumes that there is only one element in the list (root), username is not used*)
312312

313-
(* Expects only 1 control domain per host; just return first in list for now if multiple.. *)
313+
let is_domain_zero ~__context vm_ref =
314+
Db.VM.get_is_control_domain ~__context ~self:vm_ref
315+
&& Db.VM.get_domid ~__context ~self:vm_ref = 0L
316+
317+
(* Expects only 1 domain zero per host; just return first in list for now if multiple.. *)
314318
exception No_domain_zero of string
315319
let domain_zero_ref_cache = ref None
316320
let domain_zero_ref_cache_mutex = Mutex.create ()
@@ -324,14 +328,14 @@ let get_domain_zero ~__context : API.ref_VM =
324328
let uuid = Xapi_inventory.lookup Xapi_inventory._control_domain_uuid in
325329
try
326330
let vm = Db.VM.get_by_uuid ~__context ~uuid in
327-
if not (Db.VM.get_is_control_domain ~__context ~self:vm) then begin
328-
error "VM uuid %s is not a control domain but the uuid is in my inventory file" uuid;
331+
if not (is_domain_zero ~__context vm) then begin
332+
error "VM uuid %s is not domain zero but the uuid is in my inventory file" uuid;
329333
raise (No_domain_zero uuid);
330334
end;
331335
domain_zero_ref_cache := Some vm;
332336
vm
333337
with _ ->
334-
error "Failed to find control domain (uuid = %s)" uuid;
338+
error "Failed to find domain zero (uuid = %s)" uuid;
335339
raise (No_domain_zero uuid)
336340
)
337341

@@ -509,21 +513,19 @@ let boot_method_of_vm ~__context ~vm =
509513
(** Returns true if the supplied VM configuration is HVM.
510514
NB that just because a VM's current configuration looks like HVM doesn't imply it
511515
actually booted that way; you must check the boot_record to be sure *)
512-
let is_hvm (x: API.vM_t) = not(x.API.vM_is_control_domain) && x.API.vM_HVM_boot_policy <> ""
516+
let is_hvm (x: API.vM_t) = x.API.vM_HVM_boot_policy <> ""
513517

514518
let will_boot_hvm ~__context ~self = Db.VM.get_HVM_boot_policy ~__context ~self <> ""
515519

516520
let has_booted_hvm ~__context ~self =
517-
(not (Db.VM.get_is_control_domain ~__context ~self))
518-
&&
519-
let boot_record = get_boot_record ~__context ~self in
520-
boot_record.API.vM_HVM_boot_policy <> ""
521+
let boot_record = get_boot_record ~__context ~self in
522+
boot_record.API.vM_HVM_boot_policy <> ""
521523

522524
let has_booted_hvm_of_record ~__context r =
523-
(not (r.Db_actions.vM_is_control_domain))
524-
&&
525-
let boot_record = get_boot_record_of_record ~__context ~string:r.Db_actions.vM_last_booted_record ~uuid:r.Db_actions.vM_uuid in
526-
boot_record.API.vM_HVM_boot_policy <> ""
525+
let boot_record =
526+
get_boot_record_of_record ~__context
527+
~string:r.Db_actions.vM_last_booted_record ~uuid:r.Db_actions.vM_uuid in
528+
boot_record.API.vM_HVM_boot_policy <> ""
527529

528530
let is_running ~__context ~self = Db.VM.get_domid ~__context ~self <> -1L
529531

ocaml/xapi/pool_db_backup.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ let prepare_database_for_restore ~old_context ~new_context =
7373

7474
(* Set the master's dom0 to ours *)
7575
let my_control_uuid = Xapi_inventory.lookup Xapi_inventory._control_domain_uuid in
76-
begin match List.filter (fun self -> Db.VM.get_is_control_domain ~__context:new_context ~self)
76+
begin match List.filter (fun vm -> Helpers.is_domain_zero ~__context:new_context vm)
7777
(Db.Host.get_resident_VMs ~__context:new_context ~self:master) with
7878
| [ dom0 ] ->
7979
Db.VM.set_uuid ~__context:new_context ~self:dom0 ~value:my_control_uuid

ocaml/xapi/quicktest.ml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -717,11 +717,7 @@ let vdi_test session_id =
717717
debug test (Printf.sprintf "Time to create: %f%!" createtime);
718718
let pbd = List.hd (Client.SR.get_PBDs !rpc session_id sr) in
719719
let host = Client.PBD.get_host !rpc session_id pbd in
720-
let vms = Client.VM.get_all !rpc session_id in
721-
let filter vm =
722-
Client.VM.get_is_control_domain !rpc session_id vm &&
723-
Client.VM.get_resident_on !rpc session_id vm = host in
724-
let dom0 = List.find filter vms in
720+
let dom0 = dom0_of_host session_id host in
725721
let device = List.hd (Client.VM.get_allowed_VBD_devices !rpc session_id dom0) in
726722
debug test (Printf.sprintf "Creating a VBD connecting the VDI to localhost%!");
727723
let vbd = Client.VBD.create ~rpc:!rpc ~session_id ~vM:dom0 ~vDI:newvdi ~userdevice:device ~bootable:false
@@ -748,11 +744,7 @@ let async_test session_id =
748744
"description" sr 4194304L `user false false [] [] [] [] in
749745
let pbd = List.hd (Client.SR.get_PBDs !rpc session_id sr) in
750746
let host = Client.PBD.get_host !rpc session_id pbd in
751-
let vms = Client.VM.get_all !rpc session_id in
752-
let filter vm =
753-
Client.VM.get_is_control_domain !rpc session_id vm &&
754-
Client.VM.get_resident_on !rpc session_id vm = host in
755-
let dom0 = List.find filter vms in
747+
let dom0 = dom0_of_host session_id host in
756748
let device = List.hd (Client.VM.get_allowed_VBD_devices !rpc session_id dom0) in
757749
let vbd = Client.VBD.create ~rpc:!rpc ~session_id ~vM:dom0 ~vDI:newvdi ~userdevice:device ~bootable:false
758750
~mode:`RW ~_type:`Disk ~unpluggable:true ~empty:false ~other_config:[] ~qos_algorithm_type:"" ~qos_algorithm_params:[] in

ocaml/xapi/quicktest_common.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,13 @@ let find_guest_installer_network session_id =
240240
match List.filter (fun (_, r) -> List.mem_assoc Xapi_globs.is_guest_installer_network r.API.network_other_config) all with
241241
| (rf, _) :: _ -> rf
242242
| _ -> failwith "Could not find guest installer network"
243+
244+
(** Return a host's domain zero *)
245+
let dom0_of_host session_id host =
246+
match
247+
List.filter (fun vm ->
248+
Client.VM.get_is_control_domain !rpc session_id vm
249+
&& Client.VM.get_domid !rpc session_id vm = 0L
250+
) (Client.Host.get_resident_VMs !rpc session_id host) with
251+
| [] -> failwith (Printf.sprintf "Host %s has no running domain zero" (Client.Host.get_uuid !rpc session_id host))
252+
| vm :: _ -> vm

ocaml/xapi/quicktest_storage.ml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,6 @@ let choose_active_pbd session_id sr =
7373
| [] -> failwith (Printf.sprintf "SR %s has no attached PBDs" (Client.SR.get_uuid !rpc session_id sr))
7474
| x :: _ -> x
7575

76-
(** Return a host's control domain *)
77-
let control_domain_of_host session_id host =
78-
match List.filter (fun vm -> Client.VM.get_is_control_domain !rpc session_id vm)
79-
(Client.Host.get_resident_VMs !rpc session_id host) with
80-
| [] -> failwith (Printf.sprintf "Host %s has no running control domain" (Client.Host.get_uuid !rpc session_id host))
81-
| vm :: _ -> vm
82-
8376
(** Scan an SR and return the number of VDIs contained within *)
8477
let count_vdis session_id sr =
8578
Client.SR.scan !rpc session_id sr;
@@ -181,7 +174,7 @@ let vdi_create_destroy_plug_checksize caps session_id sr =
181174

182175
let plug_in_check_size session_id host vdi =
183176
let size_should_be = Client.VDI.get_virtual_size !rpc session_id vdi in
184-
let dom0 = control_domain_of_host session_id host in
177+
let dom0 = dom0_of_host session_id host in
185178
let vbd = vbd_create_helper ~session_id ~vM:dom0 ~vDI:vdi () in
186179
Client.VBD.plug !rpc session_id vbd;
187180
finally

ocaml/xapi/workload_balancing.ml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -568,8 +568,14 @@ let retrieve_wlb_config ~__context =
568568
perform_wlb_request ~meth:"GetXenPoolConfiguration" ~params ~handle_response
569569
~__context ()
570570

571-
let get_dom0_vm ~__context host=
572-
List.hd (List.filter (fun v -> (Db.VM.get_is_control_domain ~__context ~self:v)) (Db.Host.get_resident_VMs ~__context ~self:(Db.Host.get_by_uuid ~__context ~uuid:host)))
571+
let get_dom0_vm ~__context host =
572+
let resident_VMs =
573+
Db.Host.get_resident_VMs ~__context
574+
~self:(Db.Host.get_by_uuid ~__context ~uuid:host) in
575+
List.filter (fun v ->
576+
Helpers.is_domain_zero ~__context v
577+
) resident_VMs
578+
|> List.hd
573579

574580
let get_opt_recommendations ~__context =
575581
assert_wlb_enabled ~__context;

ocaml/xapi/xapi_host.ml

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,19 @@ let assert_bacon_mode ~__context ~host =
113113
let vm_data = [selfref; "vm"; Ref.string_of (List.hd guest_vms)] in
114114
raise (Api_errors.Server_error (Api_errors.host_in_use, vm_data)));
115115
debug "Bacon test: VMs OK - %d running VMs" (List.length vms);
116-
let controldomain = List.find (fun vm -> Db.VM.get_resident_on ~__context ~self:vm = host &&
117-
Db.VM.get_is_control_domain ~__context ~self:vm) (Db.VM.get_all ~__context) in
118-
let vbds = List.filter (fun vbd -> Db.VBD.get_VM ~__context ~self:vbd = controldomain &&
119-
Db.VBD.get_currently_attached ~__context ~self:vbd) (Db.VBD.get_all ~__context) in
120-
if List.length vbds > 0 then
121-
raise (Api_errors.Server_error (Api_errors.host_in_use, [ selfref; "vbd"; List.hd (List.map Ref.string_of vbds) ]));
116+
let control_domain_vbds =
117+
List.filter (fun vm ->
118+
Db.VM.get_resident_on ~__context ~self:vm = host
119+
&& Db.VM.get_is_control_domain ~__context ~self:vm
120+
) (Db.VM.get_all ~__context)
121+
|> List.map (fun self -> Db.VM.get_VBDs ~__context ~self)
122+
|> List.flatten
123+
|> List.filter (fun self -> Db.VBD.get_currently_attached ~__context ~self) in
124+
if List.length control_domain_vbds > 0 then
125+
raise (Api_errors.Server_error (
126+
Api_errors.host_in_use,
127+
[ selfref; "vbd"; List.hd (List.map Ref.string_of control_domain_vbds) ]
128+
));
122129
debug "Bacon test: VBDs OK"
123130

124131
let signal_networking_change ~__context =

ocaml/xapi/xapi_pool.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -854,10 +854,10 @@ let eject ~__context ~host =
854854
* rest of the pool. *)
855855
Pool_features.update_pool_features ~__context;
856856

857-
(* and destroy my control domain, since you can't do this from the API [operation not allowed] *)
857+
(* and destroy my control domains, since you can't do this from the API [operation not allowed] *)
858858
begin try
859-
let my_control_domain = List.find (fun x->x.API.vM_is_control_domain) (List.map snd my_vms_with_records) in
860-
Db.VM.destroy ~__context ~self:(Db.VM.get_by_uuid ~__context ~uuid:my_control_domain.API.vM_uuid)
859+
let my_control_domains = List.filter (fun x->x.API.vM_is_control_domain) (List.map snd my_vms_with_records) in
860+
List.iter (fun control_domain -> Db.VM.destroy ~__context ~self:(Db.VM.get_by_uuid ~__context ~uuid:control_domain.API.vM_uuid)) my_control_domains;
861861
with _ -> () end;
862862
debug "Pool.eject: setting our role to be master";
863863
Pool_role.set_role Pool_role.Master;

ocaml/xapi/xapi_vdi_helpers.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ let metadata_replication : ((API.ref_VDI, (API.ref_VBD * Redo_log.redo_log)) Has
3737
let get_master_dom0 ~__context =
3838
let master = Helpers.get_master ~__context in
3939
let vms = Db.Host.get_resident_VMs ~__context ~self:master in
40-
List.hd (List.filter (fun vm -> Db.VM.get_is_control_domain ~__context ~self:vm) vms)
40+
List.hd (List.filter (fun vm -> Helpers.is_domain_zero ~__context vm) vms)
4141

4242
(* Unplug and destroy any existing VBDs owned by the VDI. *)
4343
let destroy_all_vbds ~__context ~vdi =

ocaml/xapi/xapi_vm_lifecycle.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ let check_operation_error ~__context ~vmr ~vmgmr ~ref ~clone_suspended_vm_enable
327327
&& op <> `metadata_export
328328
&& op <> `changing_dynamic_range
329329
&& op <> `start
330-
then Some (Api_errors.operation_not_allowed, ["Operations on domain 0 are not allowed"])
330+
then Some (Api_errors.operation_not_allowed, ["Operations on control domain are not allowed"])
331331
else None) in
332332

333333
(* check for any HVM guest feature needed by the op *)

0 commit comments

Comments
 (0)