Skip to content

Commit 3c3a85d

Browse files
committed
Allow selection of image format during VM migration
This patch allows specifying the destination format for individual VDIs mapped to a destination SR. It adds a new parameter to `VM.migrate_send` and `VM.assert_can_migrate` API. It also adds a new parameter to XE CLI. The format to specify the image format is `image-format:<source VDI UUID>=<destination image format>`. If the given image format cannot be validated, an error is returned. Signed-off-by: Guillaume <[email protected]>
1 parent 4bf58ff commit 3c3a85d

File tree

12 files changed

+257
-91
lines changed

12 files changed

+257
-91
lines changed

ocaml/idl/datamodel_vm.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,13 @@ let migrate_send =
17141714
; param_release= inverness_release
17151715
; param_default= Some (VMap [])
17161716
}
1717+
; {
1718+
param_type= Map (Ref _vdi, String)
1719+
; param_name= "vdi_format_map"
1720+
; param_doc= "Map of source VDI to an image format"
1721+
; param_release= numbered_release "25.6.0-next"
1722+
; param_default= Some (VMap [])
1723+
}
17171724
]
17181725
~result:
17191726
(Ref _vm, "The reference of the newly created VM in the destination pool")
@@ -1781,6 +1788,13 @@ let assert_can_migrate =
17811788
; param_release= inverness_release
17821789
; param_default= Some (VMap [])
17831790
}
1791+
; {
1792+
param_type= Map (Ref _vdi, String)
1793+
; param_name= "vdi_format_map"
1794+
; param_doc= "Map of source VDI to its expected type on destination"
1795+
; param_release= numbered_release "25.6.0-next"
1796+
; param_default= Some (VMap [])
1797+
}
17841798
]
17851799
~allowed_roles:_R_VM_POWER_ADMIN
17861800
~errs:[Api_errors.license_restriction]

ocaml/xapi-cli-server/cli_frontend.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,7 @@ let rec cmdtable_data : (string * cmd_spec) list =
15741574
; "compress"
15751575
; "vif:"
15761576
; "vdi:"
1577+
; "image-format:"
15771578
]
15781579
; help=
15791580
"Migrate the selected VM(s). The parameter '--live' will migrate the \
@@ -1587,7 +1588,9 @@ let rec cmdtable_data : (string * cmd_spec) list =
15871588
'copy=true' will enable the copy mode so that a stopped vm can be \
15881589
copied, instead of migrating, to the destination pool. The vif and \
15891590
vdi mapping parameters take the form 'vif:<source vif uuid>=<dest \
1590-
network uuid>' and 'vdi:<source vdi uuid>=<dest sr uuid>'. \
1591+
network uuid>' and 'vdi:<source vdi uuid>=<dest sr uuid>'. You can \
1592+
also specify the destination image format of the VDI using \
1593+
image-format:<source vdi uuid>=<destination image format>. \
15911594
Unfortunately, destination uuids cannot be tab-completed."
15921595
; implementation= No_fd Cli_operations.vm_migrate
15931596
; flags= [Standard; Vm_selectors]

ocaml/xapi-cli-server/cli_operations.ml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4544,6 +4544,7 @@ let vm_migrate_sxm_params =
45444544
; "remote-network"
45454545
; "vdi"
45464546
; "vgpu"
4547+
; "image-format"
45474548
]
45484549

45494550
let vm_migrate printer rpc session_id params =
@@ -4691,6 +4692,17 @@ let vm_migrate printer rpc session_id params =
46914692
)
46924693
(read_map_params "vdi" params)
46934694
in
4695+
let vdi_format_map =
4696+
List.map
4697+
(fun (vdi_uuid, vdi_fmt) ->
4698+
let vdi =
4699+
Client.VDI.get_by_uuid ~rpc ~session_id ~uuid:vdi_uuid
4700+
in
4701+
debug "GTNDEBUG: add image format %s,%s" vdi_uuid vdi_fmt ;
4702+
(vdi, vdi_fmt)
4703+
)
4704+
(read_map_params "image-format" params)
4705+
in
46944706
let vgpu_map =
46954707
List.map
46964708
(fun (vgpu_uuid, gpu_group_uuid) ->
@@ -4853,7 +4865,8 @@ let vm_migrate printer rpc session_id params =
48534865
rpc session_id
48544866
(fun vm ->
48554867
Client.VM.migrate_send ~rpc ~session_id ~vm:(vm.getref ())
4856-
~dest:token ~live:true ~vdi_map ~vif_map ~options ~vgpu_map
4868+
~dest:token ~live:true ~vdi_map ~vdi_format_map ~vif_map
4869+
~options ~vgpu_map
48574870
)
48584871
params
48594872
(["host"; "host-uuid"; "host-name"; "live"; "force"; "copy"]

ocaml/xapi-idl/storage/storage_interface.ml

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ let string_of_vdi_info (x : vdi_info) = Jsonrpc.to_string (rpc_of vdi_info x)
251251
"datapaths". *)
252252
type dp = string [@@deriving rpcty]
253253

254+
type image_format = string [@@deriving rpcty]
255+
254256
type sock_path = string [@@deriving rpcty]
255257

256258
type dp_stat_t = {
@@ -277,6 +279,8 @@ type probe_result =
277279
module Mirror = struct
278280
type id = string [@@deriving rpcty]
279281

282+
type image_format = string [@@deriving rpcty]
283+
280284
type state = Receiving | Sending | Copying [@@deriving rpcty]
281285

282286
type t = {source_vdi: Vdi.t; dest_vdi: Vdi.t; state: state list; failed: bool}
@@ -998,6 +1002,8 @@ module StorageAPI (R : RPC) = struct
9981002
)
9991003

10001004
module MIRROR = struct
1005+
let image_format_p = Param.mk ~name:"image_format" image_format
1006+
10011007
let mirror_vm_p = Param.mk ~name:"mirror_vm" Vm.t
10021008

10031009
let copy_vm_p = Param.mk ~name:"copy_vm" Vm.t
@@ -1009,6 +1015,7 @@ module StorageAPI (R : RPC) = struct
10091015
(dbg_p
10101016
@-> sr_p
10111017
@-> vdi_p
1018+
@-> image_format_p
10121019
@-> dp_p
10131020
@-> mirror_vm_p
10141021
@-> copy_vm_p
@@ -1034,27 +1041,35 @@ module StorageAPI (R : RPC) = struct
10341041
Use the receive_start2 function instead.
10351042
*)
10361043
let receive_start =
1044+
let image_format_p =
1045+
Param.mk ~name:"image_format" Mirror.image_format
1046+
in
10371047
let similar_p = Param.mk ~name:"similar" Mirror.similars in
10381048
let result = Param.mk ~name:"result" Mirror.mirror_receive_result in
10391049
declare "DATA.MIRROR.receive_start" []
10401050
(dbg_p
10411051
@-> sr_p
10421052
@-> VDI.vdi_info_p
10431053
@-> id_p
1054+
@-> image_format_p
10441055
@-> similar_p
10451056
@-> returning result err
10461057
)
10471058

10481059
(** Called on the receiving end to prepare for receipt of the storage. This
10491060
function should be used in conjunction with [receive_finalize2]*)
10501061
let receive_start2 =
1062+
let image_format_p =
1063+
Param.mk ~name:"image_format" Mirror.image_format
1064+
in
10511065
let similar_p = Param.mk ~name:"similar" Mirror.similars in
10521066
let result = Param.mk ~name:"result" Mirror.mirror_receive_result in
10531067
declare "DATA.MIRROR.receive_start2" []
10541068
(dbg_p
10551069
@-> sr_p
10561070
@-> VDI.vdi_info_p
10571071
@-> id_p
1072+
@-> image_format_p
10581073
@-> similar_p
10591074
@-> vm_p
10601075
@-> returning result err
@@ -1420,6 +1435,7 @@ module type Server_impl = sig
14201435
-> dbg:debug_info
14211436
-> sr:sr
14221437
-> vdi:vdi
1438+
-> image_format:string
14231439
-> dp:dp
14241440
-> mirror_vm:vm
14251441
-> copy_vm:vm
@@ -1438,6 +1454,7 @@ module type Server_impl = sig
14381454
-> sr:sr
14391455
-> vdi_info:vdi_info
14401456
-> id:Mirror.id
1457+
-> image_format:Mirror.image_format
14411458
-> similar:Mirror.similars
14421459
-> Mirror.mirror_receive_result
14431460

@@ -1447,6 +1464,7 @@ module type Server_impl = sig
14471464
-> sr:sr
14481465
-> vdi_info:vdi_info
14491466
-> id:Mirror.id
1467+
-> image_format:Mirror.image_format
14501468
-> similar:Mirror.similars
14511469
-> vm:vm
14521470
-> Mirror.mirror_receive_result
@@ -1633,17 +1651,20 @@ module Server (Impl : Server_impl) () = struct
16331651
Impl.DATA.copy () ~dbg ~sr ~vdi ~vm ~url ~dest ~verify_dest
16341652
) ;
16351653
S.DATA.MIRROR.start
1636-
(fun dbg sr vdi dp mirror_vm copy_vm url dest verify_dest ->
1637-
Impl.DATA.MIRROR.start () ~dbg ~sr ~vdi ~dp ~mirror_vm ~copy_vm ~url
1638-
~dest ~verify_dest
1654+
(fun dbg sr vdi image_format dp mirror_vm copy_vm url dest verify_dest ->
1655+
Impl.DATA.MIRROR.start () ~dbg ~sr ~vdi ~image_format ~dp ~mirror_vm
1656+
~copy_vm ~url ~dest ~verify_dest
16391657
) ;
16401658
S.DATA.MIRROR.stop (fun dbg id -> Impl.DATA.MIRROR.stop () ~dbg ~id) ;
16411659
S.DATA.MIRROR.stat (fun dbg id -> Impl.DATA.MIRROR.stat () ~dbg ~id) ;
1642-
S.DATA.MIRROR.receive_start (fun dbg sr vdi_info id similar ->
1643-
Impl.DATA.MIRROR.receive_start () ~dbg ~sr ~vdi_info ~id ~similar
1660+
S.DATA.MIRROR.receive_start (fun dbg sr vdi_info id image_format similar ->
1661+
Impl.DATA.MIRROR.receive_start () ~dbg ~sr ~vdi_info ~id ~image_format
1662+
~similar
16441663
) ;
1645-
S.DATA.MIRROR.receive_start2 (fun dbg sr vdi_info id similar vm ->
1646-
Impl.DATA.MIRROR.receive_start2 () ~dbg ~sr ~vdi_info ~id ~similar ~vm
1664+
S.DATA.MIRROR.receive_start2
1665+
(fun dbg sr vdi_info id image_format similar vm ->
1666+
Impl.DATA.MIRROR.receive_start2 () ~dbg ~sr ~vdi_info ~id ~image_format
1667+
~similar ~vm
16471668
) ;
16481669
S.DATA.MIRROR.receive_cancel (fun dbg id ->
16491670
Impl.DATA.MIRROR.receive_cancel () ~dbg ~id

ocaml/xapi-idl/storage/storage_skeleton.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,17 +157,18 @@ module DATA = struct
157157
module MIRROR = struct
158158
(** [start task sr vdi url sr2] creates a VDI in remote [url]'s [sr2] and
159159
writes data synchronously. It returns the id of the VDI.*)
160-
let start ctx ~dbg ~sr ~vdi ~dp ~mirror_vm ~copy_vm ~url ~dest =
160+
let start ctx ~dbg ~sr ~vdi ~image_format ~dp ~mirror_vm ~copy_vm ~url ~dest
161+
=
161162
u "DATA.MIRROR.start"
162163

163164
let stop ctx ~dbg ~id = u "DATA.MIRROR.stop"
164165

165166
let stat ctx ~dbg ~id = u "DATA.MIRROR.stat"
166167

167-
let receive_start ctx ~dbg ~sr ~vdi_info ~id ~similar =
168+
let receive_start ctx ~dbg ~sr ~vdi_info ~id ~image_format ~similar =
168169
u "DATA.MIRROR.receive_start"
169170

170-
let receive_start2 ctx ~dbg ~sr ~vdi_info ~id ~similar ~vm =
171+
let receive_start2 ctx ~dbg ~sr ~vdi_info ~id ~image_format ~similar ~vm =
171172
u "DATA.MIRROR.receive_start2"
172173

173174
let receive_finalize ctx ~dbg ~id = u "DATA.MIRROR.receive_finalize"

ocaml/xapi-storage-cli/main.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,11 @@ let mirror_start common_opts sr vdi dp url dest verify_dest =
322322
let dp = get_opt dp "Need a local data path" in
323323
let url = get_opt url "Need a URL" in
324324
let dest = get_opt dest "Need a destination SR" in
325+
(* TODO: add image_format as a parameter of the CLI *)
326+
let image_format = "" in
325327
let task =
326-
Client.DATA.MIRROR.start dbg sr vdi dp mirror_vm copy_vm url
328+
Client.DATA.MIRROR.start dbg sr vdi image_format dp mirror_vm copy_vm
329+
url
327330
(Storage_interface.Sr.of_string dest)
328331
verify_dest
329332
in

ocaml/xapi/message_forwarding.ml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2536,26 +2536,26 @@ functor
25362536
assuming it can ignore this check."
25372537

25382538
let assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map ~vif_map
2539-
~options ~vgpu_map =
2539+
~options ~vgpu_map ~vdi_format_map =
25402540
info "VM.assert_can_migrate: VM = '%s'" (vm_uuid ~__context vm) ;
25412541
(* Run the checks that can be done using just the DB directly on the master *)
2542-
Local.VM.assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map ~vif_map
2543-
~vgpu_map ~options ;
2542+
Local.VM.assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map
2543+
~vdi_format_map ~vif_map ~vgpu_map ~options ;
25442544
(* Run further checks on the sending host *)
25452545
assert_can_migrate_sender ~__context ~vm ~dest ~live ~vdi_map ~vif_map
25462546
~vgpu_map ~options
25472547

25482548
let migrate_send ~__context ~vm ~dest ~live ~vdi_map ~vif_map ~options
2549-
~vgpu_map =
2549+
~vgpu_map ~vdi_format_map =
25502550
info "VM.migrate_send: VM = '%s'" (vm_uuid ~__context vm) ;
25512551
let source_host = Db.VM.get_resident_on ~__context ~self:vm in
25522552
let local_fn =
2553-
Local.VM.migrate_send ~vm ~dest ~live ~vdi_map ~vif_map ~vgpu_map
2554-
~options
2553+
Local.VM.migrate_send ~vm ~dest ~live ~vdi_map ~vdi_format_map
2554+
~vif_map ~vgpu_map ~options
25552555
in
25562556
let op session_id rpc =
25572557
Client.VM.migrate_send ~rpc ~session_id ~vm ~dest ~live ~vdi_map
2558-
~vif_map ~options ~vgpu_map
2558+
~vdi_format_map ~vif_map ~options ~vgpu_map
25592559
in
25602560
let migration_type =
25612561
if Xapi_vm_lifecycle_helpers.is_live ~__context ~self:vm then
@@ -2575,7 +2575,8 @@ functor
25752575
Helpers.try_internal_async ~__context API.ref_VM_of_rpc
25762576
(fun () ->
25772577
Client.InternalAsync.VM.migrate_send ~rpc ~session_id ~vm
2578-
~dest ~live ~vdi_map ~vif_map ~options ~vgpu_map
2578+
~dest ~live ~vdi_map ~vdi_format_map ~vif_map ~options
2579+
~vgpu_map
25792580
)
25802581
(fun () -> op session_id rpc)
25812582
)
@@ -2614,7 +2615,7 @@ functor
26142615
Server_helpers.exec_with_subtask ~__context
26152616
"VM.assert_can_migrate" (fun ~__context ->
26162617
assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map
2617-
~vif_map ~vgpu_map ~options
2618+
~vdi_format_map ~vif_map ~vgpu_map ~options
26182619
) ;
26192620
forward_migrate_send ()
26202621
)

ocaml/xapi/storage_migrate.ml

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ module MigrateLocal = struct
700700
) ;
701701
vdi_clone
702702
| None ->
703-
debug "Creating a blank remote VDI" ;
703+
debug "Creating a blank remote VDI <1>" ;
704704
Remote.VDI.create dbg dest {local_vdi with sm_config= []}
705705
in
706706
let remote_copy =
@@ -721,8 +721,8 @@ module MigrateLocal = struct
721721
| e ->
722722
raise (Storage_error (Internal_error (Printexc.to_string e)))
723723

724-
let start ~task ~dbg ~sr ~vdi ~dp ~mirror_vm ~copy_vm ~url ~dest ~verify_dest
725-
=
724+
let start ~task ~dbg ~sr ~vdi ~image_format ~dp ~mirror_vm ~copy_vm ~url ~dest
725+
~verify_dest =
726726
SXM.info
727727
"%s sr:%s vdi:%s dp: %s mirror_vm: %s copy_vm: %s url:%s dest:%s \
728728
verify_dest:%B"
@@ -786,8 +786,8 @@ module MigrateLocal = struct
786786
)
787787
) ;
788788
let (Mirror.Vhd_mirror result) =
789-
Remote.DATA.MIRROR.receive_start2 dbg dest local_vdi mirror_id similars
790-
mirror_vm
789+
Remote.DATA.MIRROR.receive_start2 dbg dest local_vdi mirror_id
790+
image_format similars mirror_vm
791791
in
792792
(* Enable mirroring on the local machine *)
793793
let mirror_dp = result.Mirror.mirror_datapath in
@@ -1122,7 +1122,7 @@ end
11221122
(** module [MigrateRemote] is similar to [MigrateLocal], but most of these functions
11231123
tend to be executed on the receiver side. *)
11241124
module MigrateRemote = struct
1125-
let receive_start_common ~dbg ~sr ~vdi_info ~id ~similar ~vm =
1125+
let receive_start_common ~dbg ~sr ~vdi_info ~id ~image_format ~similar ~vm =
11261126
let on_fail : (unit -> unit) list ref = ref [] in
11271127
let vdis = Local.SR.scan dbg sr in
11281128
(* We drop cbt_metadata VDIs that do not have any actual data *)
@@ -1183,9 +1183,19 @@ module MigrateRemote = struct
11831183
vdi_info.virtual_size new_size
11841184
) ;
11851185
vdi_clone
1186-
| None ->
1187-
debug "Creating a blank remote VDI" ;
1188-
Local.VDI.create dbg sr vdi_info
1186+
| None -> (
1187+
debug "Creating a blank remote VDI <2>" ;
1188+
debug "image_format is set to <%s>" image_format ;
1189+
match image_format with
1190+
| "" ->
1191+
Local.VDI.create dbg sr vdi_info
1192+
| _ ->
1193+
Local.VDI.create dbg sr
1194+
{
1195+
vdi_info with
1196+
sm_config= ("type", image_format) :: vdi_info.sm_config
1197+
}
1198+
)
11891199
in
11901200
debug "Parent disk content_id=%s" parent.content_id ;
11911201
State.add id
@@ -1221,11 +1231,12 @@ module MigrateRemote = struct
12211231
!on_fail ;
12221232
raise e
12231233

1224-
let receive_start ~dbg ~sr ~vdi_info ~id ~similar =
1225-
receive_start_common ~dbg ~sr ~vdi_info ~id ~similar ~vm:(Vm.of_string "0")
1234+
let receive_start ~dbg ~sr ~vdi_info ~id ~image_format ~similar =
1235+
receive_start_common ~dbg ~sr ~vdi_info ~id ~image_format ~similar
1236+
~vm:(Vm.of_string "0")
12261237

1227-
let receive_start2 ~dbg ~sr ~vdi_info ~id ~similar ~vm =
1228-
receive_start_common ~dbg ~sr ~vdi_info ~id ~similar ~vm
1238+
let receive_start2 ~dbg ~sr ~vdi_info ~id ~image_format ~similar ~vm =
1239+
receive_start_common ~dbg ~sr ~vdi_info ~image_format ~id ~similar ~vm
12291240

12301241
let receive_finalize ~dbg ~id =
12311242
let recv_state = State.find_active_receive_mirror id in
@@ -1446,10 +1457,11 @@ let copy ~dbg ~sr ~vdi ~vm ~url ~dest ~verify_dest =
14461457
~dest ~verify_dest
14471458
)
14481459

1449-
let start ~dbg ~sr ~vdi ~dp ~mirror_vm ~copy_vm ~url ~dest ~verify_dest =
1460+
let start ~dbg ~sr ~vdi ~image_format ~dp ~mirror_vm ~copy_vm ~url ~dest
1461+
~verify_dest =
14501462
with_task_and_thread ~dbg (fun task ->
1451-
MigrateLocal.start ~task ~dbg:dbg.Debug_info.log ~sr ~vdi ~dp ~mirror_vm
1452-
~copy_vm ~url ~dest ~verify_dest
1463+
MigrateLocal.start ~task ~dbg:dbg.Debug_info.log ~sr ~vdi ~image_format
1464+
~dp ~mirror_vm ~copy_vm ~url ~dest ~verify_dest
14531465
)
14541466

14551467
(* XXX: PR-1255: copy the xenopsd 'raise Exception' pattern *)

0 commit comments

Comments
 (0)