linux_verstring : string;
hostname : string;
uuid : string;
+ dom0_uuid : string;
oem_manufacturer : string option;
oem_model : string option;
oem_build_number : string option;
machine_serial_number: string option;
machine_serial_name: string option;
+ total_memory_mib: int64;
+ dom0_static_max: int64;
}
let read_localhost_info () =
let me = Helpers.get_localhost_uuid () in
let lookup_inventory_nofail k = try Some (Xapi_inventory.lookup k) with _ -> None in
let this_host_name = Helpers.get_hostname() in
+ let total_memory_mib =
+ Vmopshelpers.with_xc
+ (fun xc -> Memory.get_total_memory_mib ~xc) in
+ let dom0_static_max =
+ (* Query the balloon driver to determine how much memory is available for domain 0. *)
+ (* We cannot ask XenControl for this information, since for domain 0, the value of *)
+ (* max_memory_pages is hard-wired to the maximum native integer value ("infinity"). *)
+ let map = Balloon.parse_proc_xen_balloon () in
+ let lookup = fun x -> Opt.unbox (List.assoc x map) in
+ let keys = [Balloon._low_mem_balloon; Balloon._high_mem_balloon; Balloon._current_allocation] in
+ let values = List.map lookup keys in
+ let result = List.fold_left Int64.add 0L values in
+ Memory.bytes_of_kib result in
+
{name_label=this_host_name;
xen_verstring=xen_verstring;
linux_verstring=linux_verstring;
hostname=this_host_name;
uuid=me;
+ dom0_uuid = Xapi_inventory.lookup Xapi_inventory._control_domain_uuid;
oem_manufacturer = lookup_inventory_nofail Xapi_inventory._oem_manufacturer;
oem_model = lookup_inventory_nofail Xapi_inventory._oem_model;
oem_build_number = lookup_inventory_nofail Xapi_inventory._oem_build_number;
machine_serial_number = lookup_inventory_nofail Xapi_inventory._machine_serial_number;
machine_serial_name = lookup_inventory_nofail Xapi_inventory._machine_serial_name;
+ total_memory_mib = total_memory_mib;
+ dom0_static_max = dom0_static_max;
}
-(** Extracts a value from an option that is assumed to have a value. *)
-(** Fails at run time if there is no such value. *)
-let val_of x = match x with (Some x) -> x
-
(** Returns the maximum of two values. *)
let maximum x y = if x > y then x else y
(** Returns the minimum of two values. *)
let minimum x y = if x < y then x else y
-(** Returns the total amount of memory available in this host. *)
-let host_get_total_memory_mib () =
- Vmopshelpers.with_xc
- (fun xc -> Memory.get_total_memory_mib ~xc)
-
let (+++) = Int64.add
(** Ensures that the database has all the necessary records for domain *)
(** This function makes sure there is exactly one record of each type. *)
(** It updates existing records if they are found, or else creates new *)
(** records for any records that are missing. *)
-let rec ensure_domain_zero_records ~__context : unit =
- let domain_zero_ref = ensure_domain_zero_record ~__context in
+let rec ensure_domain_zero_records ~__context (host_info: host_info) : unit =
+ let domain_zero_ref = ensure_domain_zero_record ~__context host_info in
ensure_domain_zero_console_record ~__context ~domain_zero_ref;
- ensure_domain_zero_guest_metrics_record ~__context ~domain_zero_ref;
+ ensure_domain_zero_guest_metrics_record ~__context ~domain_zero_ref host_info;
ensure_domain_zero_shadow_record ~__context ~domain_zero_ref
-and ensure_domain_zero_record ~__context =
+and ensure_domain_zero_record ~__context (host_info: host_info): [`VM] Ref.t =
let ref_lookup () = Helpers.get_domain_zero ~__context in
let ref_create () = Ref.make () in
let (domain_zero_ref, found) =
try ref_lookup (), true
with _ -> ref_create (), false in
if found
- then update_domain_zero_record ~__context ~domain_zero_ref
- else create_domain_zero_record ~__context ~domain_zero_ref;
+ then update_domain_zero_record ~__context ~domain_zero_ref host_info
+ else create_domain_zero_record ~__context ~domain_zero_ref host_info;
domain_zero_ref
-and ensure_domain_zero_console_record ~__context ~domain_zero_ref =
+and ensure_domain_zero_console_record ~__context ~domain_zero_ref : unit =
match Db.VM.get_consoles ~__context ~self: domain_zero_ref with
| [] ->
(* if there are no consoles then make one *)
(* going on; make a new one *)
create_domain_zero_console_record ~__context ~domain_zero_ref
-and ensure_domain_zero_guest_metrics_record ~__context ~domain_zero_ref =
+and ensure_domain_zero_guest_metrics_record ~__context ~domain_zero_ref (host_info: host_info) : unit =
if not (Db.is_valid_ref __context (Db.VM.get_metrics ~__context ~self:domain_zero_ref)) then
begin
debug "Domain 0 record does not have associated guest metrics record. Creating now";
let metrics_ref = Ref.make() in
- create_domain_zero_guest_metrics_record ~__context ~domain_zero_metrics_ref:metrics_ref ~memory_constraints:(create_domain_zero_default_memory_constraints ())
+ create_domain_zero_guest_metrics_record ~__context ~domain_zero_metrics_ref:metrics_ref ~memory_constraints:(create_domain_zero_default_memory_constraints host_info)
~vcpus:(calculate_domain_zero_vcpu_count ~__context);
Db.VM.set_metrics ~__context ~self:domain_zero_ref ~value:metrics_ref
end
-and ensure_domain_zero_shadow_record ~__context ~domain_zero_ref =
+and ensure_domain_zero_shadow_record ~__context ~domain_zero_ref : unit =
(* Always create a new shadow record. *)
let domain_zero_record = Db.VM.get_record ~__context ~self:domain_zero_ref in
Helpers.set_boot_record ~__context ~self:domain_zero_ref domain_zero_record
-and create_domain_zero_record ~__context ~domain_zero_ref =
+and create_domain_zero_record ~__context ~domain_zero_ref (host_info: host_info) : unit =
(* Determine domain 0 memory constraints. *)
- let memory = create_domain_zero_default_memory_constraints () in
+ let memory = create_domain_zero_default_memory_constraints host_info in
(* Determine information about the host machine. *)
let domarch =
let i = Int64.of_nativeint (Int64.to_nativeint 0xffffffffL) in
Domain.string_of_domarch (if i > 0L then Domain.Arch_X64 else Domain.Arch_X32) in
let localhost = Helpers.get_localhost ~__context in
- let hostname = Helpers.get_hostname() in
(* Read the control domain uuid from the inventory file *)
- let uuid = Xapi_inventory.lookup Xapi_inventory._control_domain_uuid in
+ let uuid = host_info.dom0_uuid in
(* FIXME: Assume dom0 has 1 vCPU per Host_cpu for now *)
let vcpus = calculate_domain_zero_vcpu_count ~__context in
let metrics = Ref.make () in
(* Now create the database record. *)
Db.VM.create ~__context ~ref:domain_zero_ref
- ~name_label:("Control domain on host: " ^ hostname) ~uuid
+ ~name_label:("Control domain on host: " ^ host_info.hostname) ~uuid
~name_description:"The domain which manages physical devices and manages other domains"
~hVM_boot_policy:"" ~hVM_boot_params:[] ~hVM_shadow_multiplier:1. ~platform:[] ~pCI_bus:""
~pV_args:"" ~pV_ramdisk:"" ~pV_kernel:"" ~pV_bootloader:"" ~pV_bootloader_args:"" ~pV_legacy_args:""
;
Xapi_vm_helpers.update_memory_overhead ~__context ~vm:domain_zero_ref
-and create_domain_zero_console_record ~__context ~domain_zero_ref =
+and create_domain_zero_console_record ~__context ~domain_zero_ref : unit =
debug "Domain 0 record does not have associated console record. Creating now";
(* first delete any old dom0 console records that may be kicking around: *)
let this_dom0s_consoles = Db.Console.get_refs_where ~__context ~expr: (Eq(Field "_ref", Literal (Ref.string_of domain_zero_ref))) in
~other_config:[]
~port: (Int64.of_int Xapi_globs.host_console_vncport)
-and create_domain_zero_guest_metrics_record ~__context ~domain_zero_metrics_ref ~memory_constraints ~vcpus =
+and create_domain_zero_guest_metrics_record ~__context ~domain_zero_metrics_ref ~memory_constraints ~vcpus : unit =
let rec mkints = function
| 0 -> []
| n -> (mkints (n - 1) @ [n]) in
~last_updated: Date.never
~other_config:[];
-and create_domain_zero_default_memory_constraints () =
+and create_domain_zero_default_memory_constraints host_info : Vm_memory_constraints.t =
try
let constraints = {
static_min = Int64.of_string (Localdb.get Constants.pool_join_mem_stat_min);
Localdb.del Constants.pool_join_mem_target;
constraints
with _ ->
- let static_min, static_max = calculate_domain_zero_memory_static_range () in
+ let static_min, static_max = calculate_domain_zero_memory_static_range host_info in
let target = static_min +++ (Memory.bytes_of_mib 100L) in
let target = if target > static_max then static_max else target in
{
static_max = static_max;
}
-and update_domain_zero_record ~__context ~domain_zero_ref : unit =
+and update_domain_zero_record ~__context ~domain_zero_ref (host_info: host_info) : unit =
(* Fetch existing memory constraints for domain 0. *)
let constraints = Vm_memory_constraints.get ~__context ~vm_ref:domain_zero_ref in
(* Generate new memory constraints from the old constraints. *)
- let constraints = update_domain_zero_memory_constraints constraints in
+ let constraints = update_domain_zero_memory_constraints host_info constraints in
(* Write the updated memory constraints to the database. *)
Vm_memory_constraints.set ~__context ~vm_ref:domain_zero_ref ~constraints
-and update_domain_zero_memory_constraints constraints =
- let static_min, static_max = calculate_domain_zero_memory_static_range () in
+and update_domain_zero_memory_constraints (host_info: host_info) (constraints: Vm_memory_constraints.t) : Vm_memory_constraints.t =
+ let static_min, static_max = calculate_domain_zero_memory_static_range host_info in
let constraints = {constraints with
static_min = static_min;
static_max = static_max;} in
| None ->
(* The existing constraints are invalid, and cannot be transformed *)
(* into valid constraints. Reset the constraints to their defaults. *)
- create_domain_zero_default_memory_constraints ()
+ create_domain_zero_default_memory_constraints host_info
| Some constraints ->
constraints
(** Calculates the range of memory to which domain 0 is constrained, in bytes. *)
-and calculate_domain_zero_memory_static_range () =
+and calculate_domain_zero_memory_static_range (host_info: host_info) : int64 * int64 =
(** Calculates the minimum amount of memory needed by domain 0, in bytes. *)
let calculate_domain_zero_memory_static_min () =
(* Base our calculation on the total amount of host memory. *)
- let host_total_memory_mib = host_get_total_memory_mib () in
+ let host_total_memory_mib = host_info.total_memory_mib in
let minimum = 200L in (* lower hard limit *)
let intercept = 126L in (* [domain 0 memory] when [total host memory] = 0 *)
let gradient = 21.0 /. 1024.0 in (* d [domain 0 memory] / d [total host memory] *)
let result = if result < minimum then minimum else result in
Memory.bytes_of_mib result in
- (** Calculates the maximum amount of memory available to domain 0, in bytes. *)
- let calculate_domain_zero_memory_static_max () =
- (* Query the balloon driver to determine how much memory is available for domain 0. *)
- (* We cannot ask XenControl for this information, since for domain 0, the value of *)
- (* max_memory_pages is hard-wired to the maximum native integer value ("infinity"). *)
- let map = Balloon.parse_proc_xen_balloon () in
- let lookup = fun x -> val_of (List.assoc x map) in
- let keys = [Balloon._low_mem_balloon; Balloon._high_mem_balloon; Balloon._current_allocation] in
- let values = List.map lookup keys in
- let result = List.fold_left Int64.add 0L values in
- Memory.bytes_of_kib result in
-
(* static_min must not be greater than static_max *)
let static_min = calculate_domain_zero_memory_static_min () in
- let static_max = calculate_domain_zero_memory_static_max () in
+ let static_max = host_info.dom0_static_max in
let static_min = minimum static_min static_max in
static_min, static_max
-and calculate_domain_zero_vcpu_count ~__context =
+and calculate_domain_zero_vcpu_count ~__context : int =
List.length (Db.Host.get_host_CPUs ~__context ~self:(Helpers.get_localhost ~__context))
open Db_filter
~utilisation:0. ~flags ~stepping ~model ~family
~features:"" ~other_config:[])
done
-
+
| None ->
warn "Warning: Local db think's we've activated a VDI that's not in the database. Restarting xapi after a scan might fix this...";
())
-
-
-
-(* create localhost record *)
let get_my_ip_addr() =
match (Helpers.get_management_ip_addr()) with
Some ip -> ip
| None -> (error "Cannot read IP address. Check the control interface has an IP address"; "")
-let create_localhost ~__context =
- let info = Create_misc.read_localhost_info () in
+
+let create_localhost ~__context info =
let ip = get_my_ip_addr () in
let me = try Some (Db.Host.get_by_uuid ~__context ~uuid:info.uuid) with _ -> None in
(* me = None on firstboot only *)
~hostname:info.hostname ~address:ip
~external_auth_type:"" ~external_auth_service_name:"" ~external_auth_configuration:[]
~license_params:[] ~edition:"free" ~license_server:["address", "localhost"; "port", "27000"]
- in ()
+ in ()
(* TODO cat /proc/stat for btime ? *)
let get_start_time () =
Date.never
(* not sufficient just to fill in this data on create time [Xen caps may change if VT enabled in BIOS etc.] *)
-let refresh_localhost_info ~__context =
+let refresh_localhost_info ~__context info =
let host = !Xapi_globs.localhost_ref in
- let info = read_localhost_info () in
let software_version = Create_misc.make_software_version () in
(* Xapi_ha_flags.resync_host_armed_flag __context host; *)
(* Ensure basic records exist: *)
+ let info = Create_misc.read_localhost_info () in
+
(* create localhost record if doesn't already exist *)
switched_sync Xapi_globs.sync_create_localhost (fun () ->
debug "creating localhost";
- create_localhost ~__context;
+ create_localhost ~__context info;
);
(* record who we are in xapi_globs *)
switched_sync Xapi_globs.sync_create_domain_zero (fun () ->
debug "creating domain 0";
- Create_misc.ensure_domain_zero_records ~__context;
+ Create_misc.ensure_domain_zero_records ~__context info;
);
let localhost = Helpers.get_localhost ~__context in
(* refresh host info fields *)
switched_sync Xapi_globs.sync_refresh_localhost_info (fun () ->
- refresh_localhost_info ~__context;
+ refresh_localhost_info ~__context info;
);
switched_sync Xapi_globs.sync_local_vdi_activations (fun () ->
--- /dev/null
+(*
+ * Copyright (C) 2011 Citrix Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Xapi_db_upgrade
+
+let upgrade_vm_memory_for_dmc () =
+ let db = Db_upgrade.generic_database_upgrade (Db_cache_types.Database.make (Schema.of_datamodel ())) in
+ let db_ref = Db_ref.in_memory (ref (ref db)) in
+ let __context = Context.make ~database:db_ref "upgrade_vm_memory_for_dmc" in
+
+ (* Db_xml.To.file "/tmp/new3.db" (Db_ref.get_database (Context.database_of __context)); *)
+
+ let host_info = {
+ Create_misc.name_label = "test host";
+ xen_verstring = "unknown";
+ linux_verstring = "something";
+ hostname = "localhost";
+ uuid = Xapi_inventory.lookup Xapi_inventory._installation_uuid;
+ dom0_uuid = "dom0-uuid";
+ oem_manufacturer = None;
+ oem_model = None;
+ oem_build_number = None;
+ machine_serial_number = None;
+ machine_serial_name = None;
+ total_memory_mib = 1024L;
+ dom0_static_max = Memory.bytes_of_mib 512L;
+ } in
+ Dbsync_slave.create_localhost ~__context host_info;
+ Create_misc.ensure_domain_zero_records ~__context host_info;
+
+ let self = List.hd (Db.VM.get_all ~__context) in
+
+ (* Set control domain's dynamic_min <> dynamic_max <> target *)
+ Db.VM.set_memory_dynamic_min ~__context ~self ~value:1L;
+ Db.VM.set_memory_target ~__context ~self ~value:2L;
+ Db.VM.set_memory_dynamic_max ~__context ~self ~value:3L;
+ (* Apply the upgrade rule *)
+ upgrade_vm_memory_for_dmc.fn ~__context;
+ let r = Db.VM.get_record ~__context ~self in
+ if r.API.vM_memory_dynamic_min <> r.API.vM_memory_target
+ then failwith "upgrade_vm_memory_for_dmc: control domain memory_dynamic_min <> memory_target";
+ if r.API.vM_memory_dynamic_max <> r.API.vM_memory_target
+ then failwith "upgrade_vm_memory_for_dmc: control domain memory_dynamic_max <> memory_target";
+
+ (* Make this a non-control domain and change all memory fields *)
+ Db.VM.set_is_control_domain ~__context ~self ~value:false;
+ Db.VM.set_memory_static_min ~__context ~self ~value:5L;
+ Db.VM.set_memory_dynamic_min ~__context ~self ~value:1L;
+ Db.VM.set_memory_target ~__context ~self ~value:2L;
+ Db.VM.set_memory_dynamic_max ~__context ~self ~value:3L;
+ Db.VM.set_memory_static_max ~__context ~self ~value:4L;
+ (* Apply the upgrade rule *)
+ upgrade_vm_memory_for_dmc.fn ~__context;
+ let r = Db.VM.get_record ~__context ~self in
+ if r.API.vM_memory_dynamic_max <> r.API.vM_memory_static_max
+ then failwith "upgrade_vm_memory_for_dmc: memory_dynamic_max <> memory_static_max";
+ if r.API.vM_memory_target <> r.API.vM_memory_static_max
+ then failwith "upgrade_vm_memory_for_dmc: memory_target <> memory_static_max";
+ if r.API.vM_memory_dynamic_min <> r.API.vM_memory_static_max
+ then failwith "upgrade_vm_memory_for_dmc: memory_dynamic_min <> memory_static_max";
+ if r.API.vM_memory_static_min > r.API.vM_memory_static_max
+ then failwith "upgrade_vm_memory_for_dmc: memory_static_min > memory_static_max";
+ Printf.printf "upgrade_vm_memory_for_dmc: OK\n"
+
+let _ =
+ upgrade_vm_memory_for_dmc ()
+
since we still allow them to be migrated we might as well allow them to be suspended because
the code is mostly the same.
*)
-let check_drivers ~vmr ~vmgmr ~op ~ref =
- let has_booted_hvm = Helpers.has_booted_hvm_of_record vmr in
+let check_drivers ~__context ~vmr ~vmgmr ~op ~ref =
+ let has_booted_hvm = Helpers.has_booted_hvm_of_record ~__context vmr in
let pv_drivers = of_guest_metrics vmgmr in
let has_pv_drivers = has_pv_drivers pv_drivers in
(** Take an internal VM record and a proposed operation, return true if the operation
would be acceptable *)
-let check_operation_error ~vmr ~vmgmr ~ref ~clone_suspended_vm_enabled vdis_reset_and_caching ~op =
+let check_operation_error ~__context ~vmr ~vmgmr ~ref ~clone_suspended_vm_enabled vdis_reset_and_caching ~op =
let ref_str = Ref.string_of ref in
let power_state = vmr.Db_actions.vM_power_state in
let current_ops = vmr.Db_actions.vM_current_operations in
(* check PV drivers constraints if needed *)
let current_error = check current_error (fun () ->
if need_pv_drivers_check ~power_state ~op
- then check_drivers ~vmr ~vmgmr ~op ~ref
+ then check_drivers ~__context ~vmr ~vmgmr ~op ~ref
else None) in
(* check is the correct flag is set to allow clone/copy on suspended VM. *)
let is_operation_valid ~__context ~self ~op =
let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching = get_info ~__context ~self in
- match check_operation_error all gm self clone_suspended_vm_enabled vdis_reset_and_caching op with
+ match check_operation_error __context all gm self clone_suspended_vm_enabled vdis_reset_and_caching op with
| None -> true
| Some _ -> false
let assert_operation_valid ~__context ~self ~op =
let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching = get_info ~__context ~self in
- match check_operation_error all gm self clone_suspended_vm_enabled vdis_reset_and_caching op with
+ match check_operation_error __context all gm self clone_suspended_vm_enabled vdis_reset_and_caching op with
| None -> ()
| Some (a,b) -> raise (Api_errors.Server_error (a,b))
let update_allowed_operations ~__context ~self =
let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching = get_info ~__context ~self in
let check accu op =
- match check_operation_error all gm self clone_suspended_vm_enabled vdis_reset_and_caching op with
+ match check_operation_error __context all gm self clone_suspended_vm_enabled vdis_reset_and_caching op with
| None -> op :: accu
| _ -> accu
in