Skip to content

Commit d6d2f65

Browse files
authored
Merge pull request #2715 from sharady/CA-217301
CA-217301: Block SXM when SR doesn't have VDI_MIRROR capability
2 parents 4d95906 + ae00627 commit d6d2f65

File tree

2 files changed

+32
-23
lines changed

2 files changed

+32
-23
lines changed

ocaml/idl/datamodel.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ let _ =
959959
error Api_errors.too_many_storage_migrates [ "number" ]
960960
~doc:"You reached the maximal number of concurrently migrating VMs." ();
961961
error Api_errors.sr_does_not_support_migration [ "sr" ]
962-
~doc:"You attempted to migrate a VDI on SR which doesn't have snapshot capability" ();
962+
~doc:"You attempted to migrate a VDI to or from an SR which doesn't support migration" ();
963963
error Api_errors.vm_failed_shutdown_ack []
964964
~doc:"VM didn't acknowledge the need to shutdown." ();
965965
error Api_errors.vm_shutdown_timeout [ "vm"; "timeout" ]

ocaml/xapi/xapi_vm_migrate.ml

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,31 +93,38 @@ open Storage_interface
9393
open Listext
9494
open Fun
9595

96-
let assert_sr_support_migration ~__context ~vdi_map ~remote =
96+
let assert_sr_support_operations ~__context ~vdi_map ~remote ~ops =
97+
let op_supported_on_source_sr vdi ops =
98+
(* Check VDIs must not be present on SR which doesn't have required capability *)
99+
let source_sr = Db.VDI.get_SR ~__context ~self:vdi in
100+
let sr_record = Db.SR.get_record_internal ~__context ~self:source_sr in
101+
let sr_features = Xapi_sr_operations.features_of_sr ~__context sr_record in
102+
if not (List.for_all (fun op -> Smint.(has_capability op sr_features)) ops) then
103+
raise (Api_errors.Server_error(Api_errors.sr_does_not_support_migration, [Ref.string_of source_sr]));
104+
in
105+
let op_supported_on_dest_sr sr ops sm_record remote =
106+
(* Check VDIs must not be mirrored to SR which doesn't have required capability *)
107+
let sr_type = XenAPI.SR.get_type remote.rpc remote.session sr in
108+
let sm_capabilities =
109+
match List.filter (fun (_, r) -> r.API.sM_type = sr_type) sm_record with
110+
| [ _, plugin ] -> plugin.API.sM_capabilities
111+
| _ -> []
112+
in
113+
if not (List.for_all (fun op -> List.mem Smint.(string_of_capability op) sm_capabilities) ops) then
114+
raise (Api_errors.Server_error(Api_errors.sr_does_not_support_migration, [Ref.string_of sr]))
115+
in
97116
(* Get destination host SM record *)
98117
let sm_record = XenAPI.SM.get_all_records remote.rpc remote.session in
99-
List.iter (fun (vdi, sr) ->
100-
(* Check VDIs must not be present on SR which doesn't have snapshot capability *)
101-
let source_sr = Db.VDI.get_SR ~__context ~self:vdi in
102-
let sr_record = Db.SR.get_record_internal ~__context ~self:source_sr in
103-
let sr_features = Xapi_sr_operations.features_of_sr ~__context sr_record in
104-
if not Smint.(has_capability Vdi_snapshot sr_features) then
105-
raise (Api_errors.Server_error(Api_errors.sr_does_not_support_migration, [Ref.string_of source_sr]));
106-
(* Check VDIs must not be mirrored to SR which doesn't have snapshot capability *)
107-
let sr_type = XenAPI.SR.get_type remote.rpc remote.session sr in
108-
let sm_capabilities =
109-
match List.filter (fun (_, r) -> r.API.sM_type = sr_type) sm_record with
110-
| [ _, plugin ] -> plugin.API.sM_capabilities
111-
| _ -> []
112-
in
113-
if not (List.exists (fun cp -> cp = Smint.(string_of_capability Vdi_snapshot)) sm_capabilities) then
114-
raise (Api_errors.Server_error(Api_errors.sr_does_not_support_migration, [Ref.string_of sr]))
115-
) vdi_map
118+
(* Don't fail if source and destination SR for all VDIs are same *)
119+
List.filter (fun (vdi,sr) -> Db.VDI.get_SR ~__context ~self:vdi <> sr) vdi_map
120+
|> List.iter (fun (vdi, sr) ->
121+
op_supported_on_source_sr vdi ops;
122+
op_supported_on_dest_sr sr ops sm_record remote;
123+
)
116124

117125
let assert_licensed_storage_motion ~__context =
118126
Pool_features.assert_enabled ~__context ~f:Features.Storage_motion
119127

120-
121128
let rec migrate_with_retries ~__context queue_name max try_no dbg vm_uuid xenops_vdi_map xenops_vif_map xenops =
122129
let open Xapi_xenops_queue in
123130
let module Client = (val make_client queue_name: XENOPS) in
@@ -975,6 +982,11 @@ let assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map ~vif_map ~options =
975982
debug "This is a cross-pool migration";
976983
`cross_pool
977984
in
985+
986+
(* Check VDIs are not migrating to or from an SR which doesn't have required_sr_operations *)
987+
let required_sr_operations = [Smint.Vdi_mirror; Smint.Vdi_snapshot] in
988+
assert_sr_support_operations ~__context ~vdi_map ~remote ~ops:required_sr_operations;
989+
978990
match migration_type with
979991
| `intra_pool ->
980992
(* Prevent VMs from being migrated onto a host with a lower platform version *)
@@ -998,9 +1010,6 @@ let assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map ~vif_map ~options =
9981010
if (not force) && copy && power_state <> `Halted then raise (Api_errors.Server_error (Api_errors.vm_bad_power_state, [Ref.string_of vm; Record_util.power_to_string `Halted; Record_util.power_to_string power_state]));
9991011
(* Check the host can support the VM's required version of virtual hardware platform *)
10001012
Xapi_vm_helpers.assert_hardware_platform_support ~__context ~vm ~host:host_to;
1001-
(* Check VDIs are not on SR which doesn't have snapshot capability *)
1002-
assert_sr_support_migration ~__context ~vdi_map ~remote;
1003-
10041013
(*Check that the remote host is enabled and not in maintenance mode*)
10051014
let check_host_enabled = XenAPI.Host.get_enabled remote.rpc remote.session (remote.dest_host) in
10061015
if not check_host_enabled then raise (Api_errors.Server_error (Api_errors.host_disabled,[Ref.string_of remote.dest_host]));

0 commit comments

Comments
 (0)