Skip to content

Commit 42ec66c

Browse files
committed
Start/stop metadata replication on PBD plug/unplug.
Signed-off-by: John Else <[email protected]>
1 parent 53bc6d4 commit 42ec66c

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

ocaml/xapi/xapi_pbd.ml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* @group XenAPI functions
1616
*)
1717

18+
open Client
1819
open Db_filter
1920
open Db_filter_types
2021

@@ -79,12 +80,31 @@ let abort_if_storage_attached_to_protected_vms ~__context ~self =
7980
) protected_vms
8081
end
8182

83+
let find_metadata_vdis ~__context ~sr =
84+
let pool = Helpers.get_pool ~__context in
85+
List.filter
86+
(fun vdi ->
87+
Db.VDI.get_type ~__context ~self:vdi = `metadata &&
88+
Db.VDI.get_metadata_of_pool ~__context ~self:vdi = pool)
89+
(Db.SR.get_VDIs ~__context ~self:sr)
90+
8291
let plug ~__context ~self =
8392
let currently_attached = Db.PBD.get_currently_attached ~__context ~self in
8493
if not currently_attached then
8594
begin
8695
let sr = Db.PBD.get_SR ~__context ~self in
8796
Storage_access.SR.attach ~__context ~self:sr;
97+
(* Try to re-enable metadata replication to all suitable VDIs. *)
98+
try
99+
List.iter
100+
(fun vdi ->
101+
debug "Automatically re-enabling database replication to VDI %s" (Ref.string_of vdi);
102+
Xapi_vdi_helpers.enable_database_replication ~__context ~vdi)
103+
(find_metadata_vdis ~__context ~sr)
104+
with Api_errors.Server_error(code, _) when code = Api_errors.no_more_redo_logs_allowed ->
105+
(* The redo log limit was reached - don't throw an exception since automatic *)
106+
(* re-enabling of database replication is best-effort. *)
107+
debug "Metadata is being replicated to the maximum allowed number of VDIs."
88108
end
89109

90110
let unplug ~__context ~self =
@@ -106,6 +126,13 @@ let unplug ~__context ~self =
106126
then raise (Api_errors.Server_error(Api_errors.ha_is_enabled, []))
107127
end;
108128

129+
(* Disable metadata replication to VDIs in the SR. *)
130+
List.iter
131+
(fun vdi ->
132+
debug "Automatically disabling database replication to VDI %s" (Ref.string_of vdi);
133+
Xapi_vdi_helpers.disable_database_replication ~__context ~vdi)
134+
(find_metadata_vdis ~__context ~sr);
135+
109136
let vdis = get_active_vdis_by_pbd ~__context ~self in
110137
if List.length vdis > 0
111138
then raise (Api_errors.Server_error(Api_errors.vdi_in_use,List.map Ref.string_of vdis));

ocaml/xapi/xapi_sr.ml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,14 @@ let disable_database_replication ~__context ~sr =
479479
(Db.SR.get_VDIs ~__context ~self:sr)
480480
in
481481
List.iter
482-
(fun vdi -> Xapi_vdi_helpers.disable_database_replication ~__context ~vdi)
482+
(fun vdi ->
483+
Xapi_vdi_helpers.disable_database_replication ~__context ~vdi;
484+
(* The VDI may have VBDs hanging around other than those created by the database replication code. *)
485+
(* They must be destroyed before the VDI can be destroyed. *)
486+
Xapi_vdi_helpers.destroy_all_vbds ~__context ~vdi;
487+
Helpers.call_api_functions ~__context (fun rpc session_id ->
488+
Client.VDI.destroy ~rpc ~session_id ~self:vdi)
489+
)
483490
metadata_vdis
484491

485492
let create_new_blob ~__context ~sr ~name ~mime_type =

ocaml/xapi/xapi_vdi_helpers.ml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,25 @@ let get_master_dom0 ~__context =
4747
let vms = Db.Host.get_resident_VMs ~__context ~self:master in
4848
List.hd (List.filter (fun vm -> Db.VM.get_is_control_domain ~__context ~self:vm) vms)
4949

50+
(* Unplug and destroy any existing VBDs owned by the VDI. *)
51+
let destroy_all_vbds ~__context ~vdi =
52+
let existing_vbds = Db.VDI.get_VBDs ~__context ~self:vdi in
53+
Helpers.call_api_functions ~__context
54+
(fun rpc session_id -> List.iter
55+
(fun vbd ->
56+
try
57+
Client.VBD.unplug ~rpc ~session_id ~self:vbd;
58+
Client.VBD.destroy ~rpc ~session_id ~self:vbd
59+
with Api_errors.Server_error(code, _) when code = Api_errors.device_already_detached ->
60+
Client.VBD.destroy ~rpc ~session_id ~self:vbd)
61+
existing_vbds)
62+
5063
(* Create and plug a VBD from the VDI, then create a redo log and point it at the block device. *)
5164
let enable_database_replication ~__context ~vdi =
5265
Mutex.execute redo_log_lifecycle_mutex (fun () ->
5366
let name_label = Db.VDI.get_name_label ~__context ~self:vdi in
5467
let uuid = Db.VDI.get_uuid ~__context ~self:vdi in
55-
debug "Attempting to disable metadata replication on VDI [%s:%s]." name_label uuid;
68+
debug "Attempting to enable metadata replication on VDI [%s:%s]." name_label uuid;
5669
if Hashtbl.mem metadata_replication vdi then
5770
debug "Metadata is already being replicated to VDI [%s:%s]." name_label uuid
5871
else begin
@@ -62,6 +75,8 @@ let enable_database_replication ~__context ~vdi =
6275
raise (Api_errors.Server_error(Api_errors.no_more_redo_logs_allowed, []));
6376
let log = Redo_log.create () in
6477
let dom0 = get_master_dom0 ~__context in
78+
(* We've established that metadata is not being replicated to this VDI, so it should be safe to do this. *)
79+
destroy_all_vbds ~__context ~vdi;
6580
(* Create and plug vbd *)
6681
let vbd = Helpers.call_api_functions ~__context (fun rpc session_id ->
6782
let vbd = Client.VBD.create ~rpc ~session_id ~vM:dom0 ~empty:false ~vDI:vdi
@@ -77,6 +92,7 @@ let enable_database_replication ~__context ~vdi =
7792
try
7893
Redo_log.enable_block log ("/dev/" ^ device);
7994
Redo_log.startup log;
95+
Redo_log.flush_db_to_redo_log (Db_ref.get_database (Db_backend.make ()));
8096
Hashtbl.add metadata_replication vdi (vbd, log);
8197
let vbd_uuid = Db.VBD.get_uuid ~__context ~self:vbd in
8298
debug "Redo log started on VBD %s" vbd_uuid

0 commit comments

Comments
 (0)