@@ -111,32 +111,68 @@ let pre_join_checks ~__context ~rpc ~session_id ~force =
111111 raise (Api_errors. Server_error (code, [" The pool uses v6d. Pool edition list = " ^ pool_edn_list_str]))
112112 in
113113
114- (* CA-73264 Applied patches must match *)
115- let assert_applied_patches_match () =
116- let get_patches patches get_pool_patch get_uuid =
117- let patch_refs = List. map (fun x -> get_pool_patch ~self: x) patches in
118- let patch_uuids = List. map (fun x -> get_uuid ~self: x) patch_refs in
119- patch_uuids in
120- let pool_patches = get_patches
121- (Client.Host. get_patches ~rpc ~session_id ~self: (get_master ~rpc ~session_id ))
122- (Client.Host_patch. get_pool_patch ~rpc ~session_id )
123- (Client.Pool_patch. get_uuid ~rpc ~session_id ) in
124- let host_patches = get_patches
125- (Db.Host. get_patches ~__context ~self: (Helpers. get_localhost ~__context))
126- (Db.Host_patch. get_pool_patch ~__context) (Db.Pool_patch. get_uuid ~__context) in
127- let string_of_patches ps = (String. concat " " (List. map (fun patch -> patch) ps)) in
128- let diff = (List. set_difference host_patches pool_patches) @
129- (List. set_difference pool_patches host_patches)in
130- if (List. length diff > 0 ) then begin
131- error " Pool.join failed because of patches mismatch" ;
132- error " Remote has %s" (string_of_patches pool_patches);
133- error " Local has %s" (string_of_patches host_patches);
134- raise (Api_errors. Server_error (Api_errors. pool_hosts_not_homogeneous,
135- [(Printf. sprintf " Patches applied differ: Remote has %s -- Local has %s"
136- (string_of_patches pool_patches) (string_of_patches host_patches))]))
114+ let assert_api_version_matches () =
115+ let master = get_master rpc session_id in
116+ let candidate_slave = Helpers. get_localhost ~__context in
117+ let master_major = Client.Host. get_API_version_major ~rpc ~session_id ~self: master in
118+ let master_minor = Client.Host. get_API_version_minor ~rpc ~session_id ~self: master in
119+ let slave_major = Db.Host. get_API_version_major ~__context ~self: candidate_slave in
120+ let slave_minor = Db.Host. get_API_version_minor ~__context ~self: candidate_slave in
121+ if master_major <> slave_major || master_minor <> slave_minor then
122+ begin
123+ error " The joining host's API version is %Ld.%Ld while the master's is %Ld.%Ld"
124+ slave_major slave_minor master_major master_minor;
125+ raise (Api_errors. Server_error (Api_errors. pool_joining_host_must_have_same_api_version,
126+ [Printf. sprintf " %Ld.%Ld" slave_major slave_minor; Printf. sprintf " %Ld.%Ld" master_major master_minor;]))
127+ end
128+ in
129+
130+ let assert_db_schema_matches () =
131+ let master = get_master rpc session_id in
132+ let candidate_slave = Helpers. get_localhost ~__context in
133+ let master_sw_version = Client.Host. get_software_version ~rpc ~session_id ~self: master in
134+ let slave_sw_version = Db.Host. get_software_version ~__context ~self: candidate_slave in
135+ let master_db_schema = try List. assoc Xapi_globs. _db_schema master_sw_version with _ -> " " in
136+ let slave_db_schema = try List. assoc Xapi_globs. _db_schema slave_sw_version with _ -> " " in
137+ if master_db_schema = " " || slave_db_schema = " " || master_db_schema <> slave_db_schema then
138+ begin
139+ error " The joining host's database schema is %s; the master's is %s"
140+ slave_db_schema master_db_schema;
141+ raise (Api_errors. Server_error (Api_errors. pool_joining_host_must_have_same_db_schema,
142+ [slave_db_schema; master_db_schema]))
137143 end
138144 in
139145
146+ let assert_homogeneous_updates () =
147+ let module S = Helpers. StringSet in
148+ let local_host = Helpers. get_localhost ~__context in
149+ let local_uuid = Db.Host. get_uuid ~__context ~self: local_host in
150+ let updates_on ~rpc ~session_id host =
151+ Client.Host. get_updates ~rpc ~session_id ~self: host
152+ |> List. map (fun self -> Client.Pool_update. get_record ~rpc ~session_id ~self )
153+ |> List. filter (fun upd -> upd.API. pool_update_enforce_homogeneity = true )
154+ |> List. map (fun upd -> upd.API. pool_update_uuid)
155+ |> S. of_list in
156+ let local_updates =
157+ Helpers. call_api_functions ~__context (fun rpc session_id ->
158+ updates_on ~rpc ~session_id local_host) in
159+ (* iterate over all pool hosts and compare patches to local host *)
160+ Client.Host. get_all rpc session_id |> List. iter (fun pool_host ->
161+ let remote_updates = updates_on rpc session_id pool_host in
162+ if not (S. equal local_updates remote_updates) then begin
163+ let remote_uuid = Client.Host. get_uuid rpc session_id pool_host in
164+ let diff xs ys = S. diff xs ys |> S. elements |> String. concat " ," in
165+ let reason = [remote_uuid] in
166+ error
167+ " Pool join: Updates differ. Only on pool host %s: {%s} -- only on local host %s: {%s}"
168+ remote_uuid
169+ (diff remote_updates local_updates)
170+ local_uuid
171+ (diff local_updates remote_updates);
172+ raise Api_errors. (Server_error (pool_hosts_not_homogeneous,reason))
173+ end )
174+ in
175+
140176 (* CP-700: Restrict pool.join if AD configuration of slave-to-be does not match *)
141177 (* that of master of pool-to-join *)
142178 let assert_external_auth_matches () =
@@ -347,7 +383,10 @@ let pre_join_checks ~__context ~rpc ~session_id ~force =
347383 assert_external_auth_matches () ;
348384 assert_restrictions_match () ;
349385 assert_homogeneous_vswitch_configuration () ;
350- assert_applied_patches_match () ;
386+ (* CA-247399: check first the API version and then the database schema *)
387+ assert_api_version_matches () ;
388+ assert_db_schema_matches () ;
389+ assert_homogeneous_updates () ;
351390 assert_homogeneous_primary_address_type ()
352391
353392let rec create_or_get_host_on_master __context rpc session_id (host_ref , host ) : API.ref_host =
0 commit comments