From f150a7e57d09fc3a1c40ec060023b52d1c99c511 Mon Sep 17 00:00:00 2001 From: Gabriel Buica Date: Tue, 7 Oct 2025 13:49:59 +0100 Subject: [PATCH 1/2] CA-417951: Split checks for migration and detecting RPU Turns out that the previous fixes on these were too strict. As the checks for allowing migration and detecting RPU are a bit different now. For migration we want to make sure we are migrating on the same or higher versions for: platform, xapi, and xen versions. For detecting RPU we want the pool to have the same versions for platform and xapi build (only major and minor numbers). Signed-off-by: Gabriel Buica --- ocaml/tests/test_helpers.ml | 16 +- ocaml/xapi/db_gc.ml | 6 +- ocaml/xapi/helpers.ml | 281 +++++++++++++++++-------------- ocaml/xapi/message_forwarding.ml | 8 +- ocaml/xapi/xapi_host.ml | 11 +- ocaml/xapi/xapi_pool.ml | 4 +- ocaml/xapi/xapi_sr.ml | 2 +- ocaml/xapi/xapi_vm.ml | 3 +- ocaml/xapi/xapi_vm_helpers.ml | 2 +- ocaml/xapi/xapi_vm_migrate.ml | 10 +- 10 files changed, 193 insertions(+), 150 deletions(-) diff --git a/ocaml/tests/test_helpers.ml b/ocaml/tests/test_helpers.ml index aecd8d4b15a..5f482387cbb 100644 --- a/ocaml/tests/test_helpers.ml +++ b/ocaml/tests/test_helpers.ml @@ -510,7 +510,7 @@ module Version = struct ] in let test_version_numbers (description, version_string, expected) = - let actual = Helpers.version_numbers_of_string version_string in + let actual = Helpers.Checks.version_numbers_of_string version_string in let description = Printf.sprintf "version_numbers_of_string: %s" description in @@ -553,13 +553,15 @@ module Version = struct ] in let test_compare (description, key, value_a, value_b, expected) = - let actual = Helpers.compare_versions ~version_key:key value_a value_b in + let actual = + Helpers.Checks.compare_versions ~version_key:key value_a value_b + in let description = Printf.sprintf "compare_versions: %s" description in Alcotest.(check int) description expected actual in List.iter test_compare test_cases - let test_compare_all_versions () = + let test_compare_all_versions_migration () = let current = Xapi_globs.[(_platform_version, "8.1.0"); (_xen_version, "4.13.0-15")] in @@ -580,7 +582,8 @@ module Version = struct in let test_compare (description, vers_a, vers_b, expected) = let actual = - Helpers.compare_all_versions ~is_greater_or_equal:vers_a ~than:vers_b + Helpers.Checks.Migration.compare_all_versions + ~is_greater_or_equal:vers_a ~than:vers_b in let description = Printf.sprintf "compare_all_versions: %s" description in Alcotest.(check bool) description expected actual @@ -592,7 +595,10 @@ module Version = struct ("Compare int list", `Quick, test_compare_int_list) ; ("Version numbers from string", `Quick, test_version_numbers_of_string) ; ("Compare versions", `Quick, test_compare_versions) - ; ("Compare all versions", `Quick, test_compare_all_versions) + ; ( "Compare all versions for migration" + , `Quick + , test_compare_all_versions_migration + ) ] let tests = [("Version compare tests", test)] diff --git a/ocaml/xapi/db_gc.ml b/ocaml/xapi/db_gc.ml index 50e2a23a6a1..b1bcf8fc953 100644 --- a/ocaml/xapi/db_gc.ml +++ b/ocaml/xapi/db_gc.ml @@ -149,7 +149,7 @@ let detect_rolling_upgrade ~__context = (* NB: it is critical this code runs once in the master of a pool of one before the dbsync, since this is the only time at which the master's Version will be out of sync with its database record *) let actually_in_progress = - Helpers.pool_has_different_host_platform_versions ~__context + Helpers.Checks.RPU.pool_has_different_host_platform_versions ~__context in (* Check the current state of the Pool as indicated by the Pool.other_config:rolling_upgrade_in_progress *) let pools = Db.Pool.get_all ~__context in @@ -168,9 +168,9 @@ let detect_rolling_upgrade ~__context = let host_versions = List.map (fun host -> - Helpers.get_software_versions ~__context + Helpers.Checks.RPU.get_software_versions ~__context (Helpers.LocalObject host) - |> Helpers.versions_string_of + |> Helpers.Checks.versions_string_of ) (Db.Host.get_all ~__context) in diff --git a/ocaml/xapi/helpers.ml b/ocaml/xapi/helpers.ml index 9807c4540d4..949ff85f05c 100644 --- a/ocaml/xapi/helpers.ml +++ b/ocaml/xapi/helpers.ml @@ -919,142 +919,167 @@ let sort_by_schwarzian ?(descending = false) f list = |> List.sort (fun (_, x') (_, y') -> comp x' y') |> List.map (fun (x, _) -> x) -let version_keys_list = - Xapi_globs.[_platform_version; _xapi_build_version; _xen_version] - -let get_software_versions ~__context host = - ( match host with - | LocalObject self -> - Db.Host.get_software_version ~__context ~self - | RemoteObject (rpc, session_id, self) -> - Client.Client.Host.get_software_version ~rpc ~session_id ~self - ) - |> List.filter (fun (k, _) -> List.mem k version_keys_list) - -let versions_string_of : (string * string) list -> string = - fun ver_list -> - ver_list - |> List.map (fun (k, v) -> Printf.sprintf "%s: %s" k v) - |> String.concat "," - -let version_numbers_of_string version_string = - ( match String.split_on_char '-' version_string with - | [standard_version; patch] -> - String.split_on_char '.' standard_version @ [patch] - | [standard_version] -> - String.split_on_char '.' standard_version - | _ -> - ["0"; "0"; "0"] - ) - |> List.filter_map int_of_string_opt - -let version_of : version_key:string -> (string * string) list -> int list = - fun ~version_key versions_list -> - List.assoc_opt version_key versions_list - |> Option.value ~default:"0.0.0" - |> version_numbers_of_string - -(* Compares host versions, analogous to Stdlib.compare. *) -let compare_versions : - version_key:string - -> (string * string) list - -> (string * string) list - -> int = - fun ~version_key sw_ver_a sw_ver_b -> - let version_a = version_of ~version_key sw_ver_a in - let version_b = version_of ~version_key sw_ver_b in - compare_int_lists version_a version_b - -let compare_all_versions ~is_greater_or_equal:a ~than:b = - List.for_all - (fun version_key -> compare_versions ~version_key a b >= 0) - version_keys_list - -let max_version_in_pool : __context:Context.t -> (string * string) list = - fun ~__context -> - let max_version a b = - if a = [] then - b - else if compare_all_versions ~is_greater_or_equal:a ~than:b then - a - else - b - and versions = - List.map - (fun host_ref -> get_software_versions ~__context (LocalObject host_ref)) - (Db.Host.get_all ~__context) - in - List.fold_left max_version [] versions - -let host_has_highest_version_in_pool : - __context:Context.t -> host:[`host] api_object -> bool = - fun ~__context ~host -> - let host_versions = get_software_versions ~__context host - and max_version = max_version_in_pool ~__context in - compare_all_versions ~is_greater_or_equal:host_versions ~than:max_version - -let host_versions_not_decreasing ~__context ~host_from ~host_to = - let sw_vers_from = get_software_versions ~__context host_from in - let sw_vers_to = get_software_versions ~__context host_to in - compare_all_versions ~is_greater_or_equal:sw_vers_to ~than:sw_vers_from - -let are_host_versions_same_on_master_inner ~__context ~host ~master = - if is_pool_master ~__context ~host then - true - else - let sw_ver_master = get_software_versions ~__context (LocalObject master) in - let sw_ver_host = get_software_versions ~__context (LocalObject host) in +module Checks = struct + let get_software_versions ~version_keys ~__context host = + ( match host with + | LocalObject self -> + Db.Host.get_software_version ~__context ~self + | RemoteObject (rpc, session_id, self) -> + Client.Client.Host.get_software_version ~rpc ~session_id ~self + ) + |> List.filter (fun (k, _) -> List.mem k version_keys) + + let versions_string_of : (string * string) list -> string = + fun ver_list -> + ver_list + |> List.map (fun (k, v) -> Printf.sprintf "%s: %s" k v) + |> String.concat "," + + let version_numbers_of_string version_string = + ( match String.split_on_char '-' version_string with + | [standard_version; patch] -> + String.split_on_char '.' standard_version @ [patch] + | [standard_version] -> + String.split_on_char '.' standard_version + | _ -> + ["0"; "0"; "0"] + ) + |> List.filter_map int_of_string_opt + + let version_of : version_key:string -> (string * string) list -> int list = + fun ~version_key versions_list -> + List.assoc_opt version_key versions_list + |> Option.value ~default:"0.0.0" + |> version_numbers_of_string + + (* Compares host versions, analogous to Stdlib.compare. *) + let compare_versions : + version_key:string + -> (string * string) list + -> (string * string) list + -> int = + fun ~version_key sw_ver_a sw_ver_b -> + let version_a = version_of ~version_key sw_ver_a in + let version_b = version_of ~version_key sw_ver_b in + compare_int_lists version_a version_b + + let compare_all_versions ~version_keys ~is_greater_or_equal:a ~than:b = List.for_all - (fun version_key -> - compare_versions ~version_key sw_ver_master sw_ver_host = 0 - ) - version_keys_list + (fun version_key -> compare_versions ~version_key a b >= 0) + version_keys -let are_host_versions_same_on_master ~__context ~host = - let master = get_master ~__context in - are_host_versions_same_on_master_inner ~__context ~host ~master + module RPU = struct + let version_keys = Xapi_globs.[_platform_version; _xapi_version] -let maybe_raise_vtpm_unimplemented func message = - if not !ignore_vtpm_unimplemented then ( - error {|%s: Functionality not implemented yet. "%s"|} func message ; - raise Api_errors.(Server_error (not_implemented, [message])) - ) + let get_software_versions ~__context host = + get_software_versions ~version_keys ~__context host -let assert_host_versions_are_same_on_master ~__context ~host ~self = - if not (are_host_versions_same_on_master ~__context ~host) then - raise - (Api_errors.Server_error - ( Api_errors.vm_host_incompatible_version - , [Ref.string_of host; Ref.string_of self] - ) - ) + let compare_all_versions ~is_greater_or_equal:a ~than:b = + compare_all_versions ~version_keys ~is_greater_or_equal:a ~than:b -(** PR-1007 - block operations during rolling upgrade *) + let max_version_in_pool : __context:Context.t -> (string * string) list = + fun ~__context -> + let max_version a b = + if a = [] then + b + else if compare_all_versions ~is_greater_or_equal:a ~than:b then + a + else + b + and versions = + List.map + (fun host_ref -> + get_software_versions ~__context (LocalObject host_ref) + ) + (Db.Host.get_all ~__context) + in + List.fold_left max_version [] versions + + let host_has_highest_version_in_pool : + __context:Context.t -> host:[`host] api_object -> bool = + fun ~__context ~host -> + let host_versions = get_software_versions ~__context host + and max_version = max_version_in_pool ~__context in + compare_all_versions ~is_greater_or_equal:host_versions ~than:max_version + + (* Assertion functions which raise an exception if certain invariants + are broken during an upgrade. *) + let assert_rolling_upgrade_not_in_progress : __context:Context.t -> unit = + fun ~__context -> + if rolling_upgrade_in_progress ~__context then + raise + (Api_errors.Server_error (Api_errors.not_supported_during_upgrade, [])) + + let assert_host_has_highest_version_in_pool ~(__context : Context.t) + ~(host : API.ref_host) : unit = + if + not + (host_has_highest_version_in_pool ~__context ~host:(LocalObject host)) + then + raise + (Api_errors.Server_error (Api_errors.not_supported_during_upgrade, [])) -(* Assertion functions which raise an exception if certain invariants - are broken during an upgrade. *) -let assert_rolling_upgrade_not_in_progress : __context:Context.t -> unit = - fun ~__context -> - if rolling_upgrade_in_progress ~__context then - raise (Api_errors.Server_error (Api_errors.not_supported_during_upgrade, [])) + let are_host_versions_same_on_master_inner ~__context ~host ~master = + if is_pool_master ~__context ~host then + true + else + let sw_ver_master = + get_software_versions ~__context (LocalObject master) + in + let sw_ver_host = get_software_versions ~__context (LocalObject host) in + List.for_all + (fun version_key -> + compare_versions ~version_key sw_ver_master sw_ver_host = 0 + ) + version_keys + + let are_host_versions_same_on_master ~__context ~host = + let master = get_master ~__context in + are_host_versions_same_on_master_inner ~__context ~host ~master + + let pool_has_different_host_platform_versions ~__context = + let all_hosts = Db.Host.get_all ~__context in + let master = get_master ~__context in + not + (List.for_all + (fun host -> + are_host_versions_same_on_master_inner ~__context ~host ~master + ) + all_hosts + ) -let assert_host_has_highest_version_in_pool : - __context:Context.t -> host:API.ref_host -> unit = - fun ~__context ~host -> - if not (host_has_highest_version_in_pool ~__context ~host:(LocalObject host)) - then - raise (Api_errors.Server_error (Api_errors.not_supported_during_upgrade, [])) + let assert_host_versions_are_same_on_master ~__context ~host ~self = + if not (are_host_versions_same_on_master ~__context ~host) then + raise + (Api_errors.Server_error + ( Api_errors.vm_host_incompatible_version + , [Ref.string_of host; Ref.string_of self] + ) + ) + end -let pool_has_different_host_platform_versions ~__context = - let all_hosts = Db.Host.get_all ~__context in - let master = get_master ~__context in - not - (List.for_all - (fun host -> - are_host_versions_same_on_master_inner ~__context ~host ~master - ) - all_hosts - ) + module Migration = struct + let version_keys = + Xapi_globs.[_platform_version; _xapi_build_version; _xen_version] + + let get_software_versions ~__context host = + get_software_versions ~version_keys ~__context host + + let compare_all_versions ~is_greater_or_equal:a ~than:b = + compare_all_versions ~version_keys ~is_greater_or_equal:a ~than:b + + let host_versions_not_decreasing ~__context ~host_from ~host_to = + let sw_vers_from = get_software_versions ~__context host_from in + let sw_vers_to = get_software_versions ~__context host_to in + compare_all_versions ~is_greater_or_equal:sw_vers_to ~than:sw_vers_from + end +end + +let maybe_raise_vtpm_unimplemented func message = + if not !ignore_vtpm_unimplemented then ( + error {|%s: Functionality not implemented yet. "%s"|} func message ; + raise Api_errors.(Server_error (not_implemented, [message])) + ) (* Checks that a host has a PBD for a particular SR (meaning that the SR is visible to the host) *) diff --git a/ocaml/xapi/message_forwarding.ml b/ocaml/xapi/message_forwarding.ml index d01bdc851d8..fe815ebe0df 100644 --- a/ocaml/xapi/message_forwarding.ml +++ b/ocaml/xapi/message_forwarding.ml @@ -1921,7 +1921,8 @@ functor let start_on ~__context ~vm ~host ~start_paused ~force = if Helpers.rolling_upgrade_in_progress ~__context then - Helpers.assert_host_has_highest_version_in_pool ~__context ~host ; + Helpers.Checks.RPU.assert_host_has_highest_version_in_pool ~__context + ~host ; Pool_features.assert_enabled ~__context ~f:Features.VM_start ; Xapi_vm_helpers.assert_matches_control_domain_affinity ~__context ~self:vm ~host ; @@ -2427,7 +2428,8 @@ functor let resume_on ~__context ~vm ~host ~start_paused ~force = if Helpers.rolling_upgrade_in_progress ~__context then - Helpers.assert_host_has_highest_version_in_pool ~__context ~host ; + Helpers.Checks.RPU.assert_host_has_highest_version_in_pool ~__context + ~host ; info "VM.resume_on: VM = '%s'; host = '%s'" (vm_uuid ~__context vm) (host_uuid ~__context host) ; let local_fn = Local.VM.resume_on ~vm ~host ~start_paused ~force in @@ -2485,7 +2487,7 @@ functor with_vm_operation ~__context ~self:vm ~doc:"VM.pool_migrate" ~op:`pool_migrate ~strict:(not force) (fun () -> let to_equal_or_greater_version = - Helpers.host_versions_not_decreasing ~__context + Helpers.Checks.Migration.host_versions_not_decreasing ~__context ~host_from:(Helpers.LocalObject source_host) ~host_to:(Helpers.LocalObject host) in diff --git a/ocaml/xapi/xapi_host.ml b/ocaml/xapi/xapi_host.ml index a6e2563c7a3..bc6392d38c5 100644 --- a/ocaml/xapi/xapi_host.ml +++ b/ocaml/xapi/xapi_host.ml @@ -295,19 +295,20 @@ let compute_evacuation_plan_no_wlb ~__context ~host ?(ignore_ha = false) () = the source host. So as long as host versions aren't decreasing, we're allowed to migrate VMs between hosts. *) debug "evacuating host version: %s" - (Helpers.get_software_versions ~__context (Helpers.LocalObject host) - |> Helpers.versions_string_of + (Helpers.Checks.Migration.get_software_versions ~__context + (Helpers.LocalObject host) + |> Helpers.Checks.versions_string_of ) ; let target_hosts = List.filter (fun target -> debug "host %s version: %s" (Db.Host.get_hostname ~__context ~self:target) - Helpers.( - get_software_versions ~__context (LocalObject target) + Helpers.Checks.( + Migration.get_software_versions ~__context (LocalObject target) |> versions_string_of ) ; - Helpers.host_versions_not_decreasing ~__context + Helpers.Checks.Migration.host_versions_not_decreasing ~__context ~host_from:(Helpers.LocalObject host) ~host_to:(Helpers.LocalObject target) ) diff --git a/ocaml/xapi/xapi_pool.ml b/ocaml/xapi/xapi_pool.ml index 3a17815f16b..3a5072c754e 100644 --- a/ocaml/xapi/xapi_pool.ml +++ b/ocaml/xapi/xapi_pool.ml @@ -2618,7 +2618,9 @@ let create_VLAN_from_PIF ~__context ~pif ~network ~vLAN = let enable_disable_m = Mutex.create () let enable_ha ~__context ~heartbeat_srs ~configuration = - if not (Helpers.pool_has_different_host_platform_versions ~__context) then + if + not (Helpers.Checks.RPU.pool_has_different_host_platform_versions ~__context) + then with_lock enable_disable_m (fun () -> Xapi_ha.enable __context heartbeat_srs configuration ) diff --git a/ocaml/xapi/xapi_sr.ml b/ocaml/xapi/xapi_sr.ml index 8261757bb5e..3cd0588038e 100644 --- a/ocaml/xapi/xapi_sr.ml +++ b/ocaml/xapi/xapi_sr.ml @@ -357,7 +357,7 @@ let create ~__context ~host ~device_config ~(physical_size : int64) ~name_label __LOC__ (fun () -> Xapi_clustering.assert_cluster_host_is_enabled_for_matching_sms ~__context ~host ~sr_sm_type:_type ; - Helpers.assert_rolling_upgrade_not_in_progress ~__context ; + Helpers.Checks.RPU.assert_rolling_upgrade_not_in_progress ~__context ; debug "SR.create name_label=%s sm_config=[ %s ]" name_label (String.concat "; " (List.map (fun (k, v) -> k ^ " = " ^ v) sm_config)) ; let sr_uuid = Uuidx.make () in diff --git a/ocaml/xapi/xapi_vm.ml b/ocaml/xapi/xapi_vm.ml index 036c6f07f9a..21b1704e8d2 100644 --- a/ocaml/xapi/xapi_vm.ml +++ b/ocaml/xapi/xapi_vm.ml @@ -65,7 +65,8 @@ let update_allowed_operations ~__context ~self = let assert_can_boot_here ~__context ~self ~host = let snapshot = Db.VM.get_record ~__context ~self in if Helpers.rolling_upgrade_in_progress ~__context then - Helpers.assert_host_versions_are_same_on_master ~__context ~host ~self ; + Helpers.Checks.RPU.assert_host_versions_are_same_on_master ~__context ~host + ~self ; assert_can_boot_here ~__context ~self ~host ~snapshot ~do_cpuid_check:true () let retrieve_wlb_recommendations ~__context ~vm = diff --git a/ocaml/xapi/xapi_vm_helpers.ml b/ocaml/xapi/xapi_vm_helpers.ml index 551a292f396..fc5f0db7623 100644 --- a/ocaml/xapi/xapi_vm_helpers.ml +++ b/ocaml/xapi/xapi_vm_helpers.ml @@ -876,7 +876,7 @@ let vm_can_run_on_host ~__context ~vm ~snapshot ~do_memory_check host = let is_control_domain = Db.VM.get_is_control_domain ~__context ~self:vm in let host_has_proper_version () = if Helpers.rolling_upgrade_in_progress ~__context then - Helpers.host_has_highest_version_in_pool ~__context + Helpers.Checks.RPU.host_has_highest_version_in_pool ~__context ~host:(Helpers.LocalObject host) else true diff --git a/ocaml/xapi/xapi_vm_migrate.ml b/ocaml/xapi/xapi_vm_migrate.ml index 07406014afb..814ed70acea 100644 --- a/ocaml/xapi/xapi_vm_migrate.ml +++ b/ocaml/xapi/xapi_vm_migrate.ml @@ -1804,7 +1804,10 @@ let assert_can_migrate ~__context ~vm ~dest ~live:_ ~vdi_map ~vif_map ~options (* Prevent VMs from being migrated onto a host with a lower platform version *) let host_to = Helpers.LocalObject remote.dest_host in if - not (Helpers.host_versions_not_decreasing ~__context ~host_from ~host_to) + not + (Helpers.Checks.Migration.host_versions_not_decreasing ~__context + ~host_from ~host_to + ) then raise (Api_errors.Server_error (Api_errors.not_supported_during_upgrade, [])) ; @@ -1832,7 +1835,10 @@ let assert_can_migrate ~__context ~vm ~dest ~live:_ ~vdi_map ~vif_map ~options Helpers.RemoteObject (remote.rpc, remote.session, remote.dest_host) in if - not (Helpers.host_versions_not_decreasing ~__context ~host_from ~host_to) + not + (Helpers.Checks.Migration.host_versions_not_decreasing ~__context + ~host_from ~host_to + ) then raise (Api_errors.Server_error From d08b39a30a4f7d1acb0876520144a9990300552d Mon Sep 17 00:00:00 2001 From: Gabriel Buica Date: Tue, 7 Oct 2025 15:52:47 +0100 Subject: [PATCH 2/2] CA-417951: Host.create now takes a software version argument Currently, when a new host is created on the coordinator, it has only a minimal record added for it in the database. And this record only adds the platform version. While the rest is populated when `db_sync` is called. With the new checks for detecting RPU, this results in a 30s interval when the coordinator thinks an RPU is in progress when a new host is added to a pool. Because we already check for for xapi build version, major and minor numbers, in the pre-join checks, it is safe to add this in the minimal record created for a new host (before db_sync gets called). Signed-off-by: Gabriel Buica --- ocaml/idl/datamodel_host.ml | 7 +++++++ ocaml/tests/common/test_common.ml | 1 + ocaml/tests/test_host.ml | 1 + ocaml/xapi/create_misc.ml | 7 +------ ocaml/xapi/dbsync_slave.ml | 2 +- ocaml/xapi/xapi_globs.ml | 5 +++++ ocaml/xapi/xapi_host.ml | 7 +++---- ocaml/xapi/xapi_host.mli | 1 + ocaml/xapi/xapi_pool.ml | 1 + 9 files changed, 21 insertions(+), 11 deletions(-) diff --git a/ocaml/idl/datamodel_host.ml b/ocaml/idl/datamodel_host.ml index 220b8a9977e..0c0d1b1854e 100644 --- a/ocaml/idl/datamodel_host.ml +++ b/ocaml/idl/datamodel_host.ml @@ -1374,6 +1374,13 @@ let create_params = ; param_release= numbered_release "25.32.0" ; param_default= Some (VBool false) } + ; { + param_type= Map (String, String) + ; param_name= "software_version" + ; param_doc= "Information about the software versions on the host" + ; param_release= numbered_release "25.32.0-next" + ; param_default= Some (VMap []) + } ] let create = diff --git a/ocaml/tests/common/test_common.ml b/ocaml/tests/common/test_common.ml index f9888b2631e..c0a77d21716 100644 --- a/ocaml/tests/common/test_common.ml +++ b/ocaml/tests/common/test_common.ml @@ -181,6 +181,7 @@ let make_host ~__context ?(uuid = make_uuid ()) ?(name_label = "host") ~local_cache_sr ~chipset_info ~ssl_legacy ~last_software_update ~last_update_hash ~ssh_enabled ~ssh_enabled_timeout ~ssh_expiry ~console_idle_timeout ~ssh_auto_mode ~secure_boot + ~software_version:(Xapi_globs.software_version ()) in Db.Host.set_cpu_info ~__context ~self:host ~value:default_cpu_info ; host diff --git a/ocaml/tests/test_host.ml b/ocaml/tests/test_host.ml index 350396aa5b4..bb869d292c0 100644 --- a/ocaml/tests/test_host.ml +++ b/ocaml/tests/test_host.ml @@ -26,6 +26,7 @@ let add_host __context name = ~last_software_update:Clock.Date.epoch ~last_update_hash:"" ~ssh_enabled:true ~ssh_enabled_timeout:0L ~ssh_expiry:Clock.Date.epoch ~console_idle_timeout:0L ~ssh_auto_mode:false ~secure_boot:false + ~software_version:(Xapi_globs.software_version ()) ) (* Creates an unlicensed pool with the maximum number of hosts *) diff --git a/ocaml/xapi/create_misc.ml b/ocaml/xapi/create_misc.ml index 26d2c886d52..e47d2e69caa 100644 --- a/ocaml/xapi/create_misc.ml +++ b/ocaml/xapi/create_misc.ml @@ -434,10 +434,6 @@ let create_root_user ~__context = if all = [] then Db.User.create ~__context ~ref ~fullname ~short_name ~uuid ~other_config:[] -let get_xapi_verstring () = - Printf.sprintf "%d.%d" Xapi_version.xapi_version_major - Xapi_version.xapi_version_minor - (** Create assoc list of Supplemental-Pack information. * The package information is taking from the [XS-REPOSITORY] XML file in the package * directory. @@ -531,8 +527,7 @@ let make_software_version ~__context host_info = Xapi_globs.software_version () @ v6_version @ [ - (Xapi_globs._xapi_version, get_xapi_verstring ()) - ; ("xapi_build", Xapi_version.version) + ("xapi_build", Xapi_version.version) ; ("xen", Option.value ~default:"(unknown)" host_info.xen_verstring) ; ("linux", host_info.linux_verstring) ; ("xencenter_min", Xapi_globs.xencenter_min_verstring) diff --git a/ocaml/xapi/dbsync_slave.ml b/ocaml/xapi/dbsync_slave.ml index 8e78cb61ca8..f7baddfee14 100644 --- a/ocaml/xapi/dbsync_slave.ml +++ b/ocaml/xapi/dbsync_slave.ml @@ -65,7 +65,7 @@ let create_localhost ~__context info = ~ssh_expiry:Date.epoch ~console_idle_timeout:Constants.default_console_idle_timeout ~ssh_auto_mode:!Xapi_globs.ssh_auto_mode_default - ~secure_boot:false + ~secure_boot:false ~software_version:[] in () diff --git a/ocaml/xapi/xapi_globs.ml b/ocaml/xapi/xapi_globs.ml index 7ce62795e9f..aaf9b4dbb37 100644 --- a/ocaml/xapi/xapi_globs.ml +++ b/ocaml/xapi/xapi_globs.ml @@ -178,6 +178,10 @@ let vdi_tar_export_dir = "vdi" let software_version () = (* In the case of XCP, all product_* fields will be blank. *) + let get_xapi_verstring () = + Printf.sprintf "%d.%d" Xapi_version.xapi_version_major + Xapi_version.xapi_version_minor + in List.filter (fun (_, value) -> value <> "") [ @@ -187,6 +191,7 @@ let software_version () = ; (_platform_name, Xapi_version.platform_name ()) ; (_platform_version, Xapi_version.platform_version ()) ; (_product_brand, Xapi_version.product_brand ()) + ; (_xapi_version, get_xapi_verstring ()) ; (_build_number, Xapi_version.build_number ()) ; (_git_id, Xapi_version.git_id) ; (_hostname, Xapi_version.hostname) diff --git a/ocaml/xapi/xapi_host.ml b/ocaml/xapi/xapi_host.ml index bc6392d38c5..37bedc658df 100644 --- a/ocaml/xapi/xapi_host.ml +++ b/ocaml/xapi/xapi_host.ml @@ -1029,7 +1029,7 @@ let create ~__context ~uuid ~name_label ~name_description:_ ~hostname ~address ~license_params ~edition ~license_server ~local_cache_sr ~chipset_info ~ssl_legacy:_ ~last_software_update ~last_update_hash ~ssh_enabled ~ssh_enabled_timeout ~ssh_expiry ~console_idle_timeout ~ssh_auto_mode - ~secure_boot = + ~secure_boot ~software_version = (* fail-safe. We already test this on the joining host, but it's racy, so multiple concurrent pool-join might succeed. Note: we do it in this order to avoid a problem checking restrictions during the initial setup of the database *) @@ -1064,9 +1064,8 @@ let create ~__context ~uuid ~name_label ~name_description:_ ~hostname ~address (* no or multiple pools *) in Db.Host.create ~__context ~ref:host ~current_operations:[] - ~allowed_operations:[] ~https_only:false - ~software_version:(Xapi_globs.software_version ()) - ~enabled:false ~aPI_version_major:Datamodel_common.api_version_major + ~allowed_operations:[] ~https_only:false ~software_version ~enabled:false + ~aPI_version_major:Datamodel_common.api_version_major ~aPI_version_minor:Datamodel_common.api_version_minor ~aPI_version_vendor:Datamodel_common.api_version_vendor ~aPI_version_vendor_implementation: diff --git a/ocaml/xapi/xapi_host.mli b/ocaml/xapi/xapi_host.mli index c6e758cf470..b4db3a69e45 100644 --- a/ocaml/xapi/xapi_host.mli +++ b/ocaml/xapi/xapi_host.mli @@ -137,6 +137,7 @@ val create : -> console_idle_timeout:int64 -> ssh_auto_mode:bool -> secure_boot:bool + -> software_version:(string * string) list -> [`host] Ref.t val destroy : __context:Context.t -> self:API.ref_host -> unit diff --git a/ocaml/xapi/xapi_pool.ml b/ocaml/xapi/xapi_pool.ml index 3a5072c754e..0741d57f271 100644 --- a/ocaml/xapi/xapi_pool.ml +++ b/ocaml/xapi/xapi_pool.ml @@ -1059,6 +1059,7 @@ let rec create_or_get_host_on_master __context rpc session_id (host_ref, host) : ~console_idle_timeout:host.API.host_console_idle_timeout ~ssh_auto_mode:host.API.host_ssh_auto_mode ~secure_boot:host.API.host_secure_boot + ~software_version:host.API.host_software_version in (* Copy other-config into newly created host record: *) no_exn