diff --git a/ocaml/idl/datamodel.ml b/ocaml/idl/datamodel.ml index 4372877b995..c0e2029a786 100644 --- a/ocaml/idl/datamodel.ml +++ b/ocaml/idl/datamodel.ml @@ -5118,6 +5118,10 @@ module SM = struct ~ty:(Set String) "required_cluster_stack" "The storage plugin requires that one of these cluster stacks is \ configured and running." + ; field ~in_oss_since:None ~qualifier:DynamicRO ~lifecycle:[] + ~default_value:(Some (VSet [])) ~ty:(Set String) + "supported_image_formats" + "Image formats suported by the SR (VHD, RAW, Qcow2, ...)" ] () end @@ -5439,6 +5443,10 @@ module VDI = struct [ (Ref _vdi, "vdi", "The VDI to migrate") ; (Ref _sr, "sr", "The destination SR") + ; ( String + , "dest_img_format" + , "The image format to use on destination SR" + ) ; (Map (String, String), "options", "Other parameters") ] ~result:(Ref _vdi, "The new reference of the migrated VDI.") diff --git a/ocaml/idl/datamodel_common.ml b/ocaml/idl/datamodel_common.ml index 819b7c61141..4786d2d329e 100644 --- a/ocaml/idl/datamodel_common.ml +++ b/ocaml/idl/datamodel_common.ml @@ -10,7 +10,7 @@ open Datamodel_roles to leave a gap for potential hotfixes needing to increment the schema version.*) let schema_major_vsn = 5 -let schema_minor_vsn = 789 +let schema_minor_vsn = 790 (* Historical schema versions just in case this is useful later *) let rio_schema_major_vsn = 5 diff --git a/ocaml/idl/datamodel_vm.ml b/ocaml/idl/datamodel_vm.ml index e72721b4ce0..acc9c6ff080 100644 --- a/ocaml/idl/datamodel_vm.ml +++ b/ocaml/idl/datamodel_vm.ml @@ -1714,6 +1714,13 @@ let migrate_send = ; param_release= inverness_release ; param_default= Some (VMap []) } + ; { + param_type= Map (Ref _vdi, String) + ; param_name= "vdi_format_map" + ; param_doc= "Map of source VDI to an image format" + ; param_release= numbered_release "25.6.0-next" + ; param_default= Some (VMap []) + } ] ~result: (Ref _vm, "The reference of the newly created VM in the destination pool") @@ -1781,6 +1788,13 @@ let assert_can_migrate = ; param_release= inverness_release ; param_default= Some (VMap []) } + ; { + param_type= Map (Ref _vdi, String) + ; param_name= "vdi_format_map" + ; param_doc= "Map of source VDI to its expected type on destination" + ; param_release= numbered_release "25.6.0-next" + ; param_default= Some (VMap []) + } ] ~allowed_roles:_R_VM_POWER_ADMIN ~errs:[Api_errors.license_restriction] diff --git a/ocaml/idl/schematest.ml b/ocaml/idl/schematest.ml index c8abcb1f999..26da9cf214d 100644 --- a/ocaml/idl/schematest.ml +++ b/ocaml/idl/schematest.ml @@ -3,7 +3,7 @@ let hash x = Digest.string x |> Digest.to_hex (* BEWARE: if this changes, check that schema has been bumped accordingly in ocaml/idl/datamodel_common.ml, usually schema_minor_vsn *) -let last_known_schema_hash = "4cd835e2557dd7b5cbda6c681730c447" +let last_known_schema_hash = "4cd835e2557dd7b5cbda6c681730c448" let current_schema_hash : string = let open Datamodel_types in diff --git a/ocaml/tests/common/test_common.ml b/ocaml/tests/common/test_common.ml index 9e4703f117c..21fd2ab1c7c 100644 --- a/ocaml/tests/common/test_common.ml +++ b/ocaml/tests/common/test_common.ml @@ -351,11 +351,12 @@ let make_sm ~__context ?(ref = Ref.make ()) ?(uuid = make_uuid ()) ?(copyright = "") ?(version = "") ?(required_api_version = "") ?(capabilities = []) ?(features = default_sm_features) ?(host_pending_features = []) ?(configuration = []) ?(other_config = []) - ?(driver_filename = "/dev/null") ?(required_cluster_stack = []) () = + ?(driver_filename = "/dev/null") ?(required_cluster_stack = []) + ?(supported_image_formats = []) () = Db.SM.create ~__context ~ref ~uuid ~_type ~name_label ~name_description ~vendor ~copyright ~version ~required_api_version ~capabilities ~features ~host_pending_features ~configuration ~other_config ~driver_filename - ~required_cluster_stack ; + ~required_cluster_stack ~supported_image_formats ; ref let make_sr ~__context ?(ref = Ref.make ()) ?(uuid = make_uuid ()) diff --git a/ocaml/tests/test_sm_features.ml b/ocaml/tests/test_sm_features.ml index 6b7ef99502d..172be6d99fa 100644 --- a/ocaml/tests/test_sm_features.ml +++ b/ocaml/tests/test_sm_features.ml @@ -250,6 +250,7 @@ module CreateSMObject = Generic.MakeStateful (struct ; configuration= [] ; required_cluster_stack= [] ; smapi_version= SMAPIv2 + ; supported_image_formats= [] } let extract_output __context _ = diff --git a/ocaml/tests/test_vdi_cbt.ml b/ocaml/tests/test_vdi_cbt.ml index 54ae411ac97..534edcd4911 100644 --- a/ocaml/tests/test_vdi_cbt.ml +++ b/ocaml/tests/test_vdi_cbt.ml @@ -31,6 +31,7 @@ let register_smapiv2_server (module S : Storage_interface.Server_impl) sr_ref = ; configuration= [] ; required_cluster_stack= [] ; smapi_version= SMAPIv2 + ; supported_image_formats= [] } in diff --git a/ocaml/xapi-cli-server/cli_frontend.ml b/ocaml/xapi-cli-server/cli_frontend.ml index b066d7a8dd5..6413b52b792 100644 --- a/ocaml/xapi-cli-server/cli_frontend.ml +++ b/ocaml/xapi-cli-server/cli_frontend.ml @@ -1611,6 +1611,7 @@ let rec cmdtable_data : (string * cmd_spec) list = ; "compress" ; "vif:" ; "vdi:" + ; "image-format:" ] ; help= "Migrate the selected VM(s). The parameter '--live' will migrate the \ @@ -1624,7 +1625,9 @@ let rec cmdtable_data : (string * cmd_spec) list = 'copy=true' will enable the copy mode so that a stopped vm can be \ copied, instead of migrating, to the destination pool. The vif and \ vdi mapping parameters take the form 'vif:=' and 'vdi:='. \ + network uuid>' and 'vdi:='. You can \ + also specify the destination image format of the VDI using \ + image-format:=. \ Unfortunately, destination uuids cannot be tab-completed." ; implementation= No_fd Cli_operations.vm_migrate ; flags= [Standard; Vm_selectors] @@ -2466,10 +2469,10 @@ let rec cmdtable_data : (string * cmd_spec) list = ; ( "vdi-pool-migrate" , { reqd= ["uuid"; "sr-uuid"] - ; optn= [] + ; optn= ["dest-img-format"] ; help= - "Migrate a VDI to a specified SR, while the VDI is attached to a \ - running guest." + "Migrate a VDI to a specified SR, while it is attached to a running \ + guest. You can specify the image format for the destination." ; implementation= No_fd Cli_operations.vdi_pool_migrate ; flags= [] } diff --git a/ocaml/xapi-cli-server/cli_operations.ml b/ocaml/xapi-cli-server/cli_operations.ml index 65c91a031fc..4677517b4a0 100644 --- a/ocaml/xapi-cli-server/cli_operations.ml +++ b/ocaml/xapi-cli-server/cli_operations.ml @@ -2063,8 +2063,12 @@ let vdi_pool_migrate printer rpc session_id params = Client.VDI.get_by_uuid ~rpc ~session_id ~uuid:(List.assoc "uuid" params) and sr = Client.SR.get_by_uuid ~rpc ~session_id ~uuid:(List.assoc "sr-uuid" params) + and dest_img_format = + List.assoc_opt "dest-img-format" params |> Option.value ~default:"" and options = [] (* no options implemented yet *) in - let newvdi = Client.VDI.pool_migrate ~rpc ~session_id ~vdi ~sr ~options in + let newvdi = + Client.VDI.pool_migrate ~rpc ~session_id ~vdi ~sr ~dest_img_format ~options + in let newuuid = Client.VDI.get_uuid ~rpc ~session_id ~self:newvdi in printer (Cli_printer.PList [newuuid]) @@ -4560,6 +4564,7 @@ let vm_migrate_sxm_params = ; "remote-network" ; "vdi" ; "vgpu" + ; "image-format" ] let vm_migrate printer rpc session_id params = @@ -4707,6 +4712,17 @@ let vm_migrate printer rpc session_id params = ) (read_map_params "vdi" params) in + let vdi_format_map = + List.map + (fun (vdi_uuid, vdi_fmt) -> + let vdi = + Client.VDI.get_by_uuid ~rpc ~session_id ~uuid:vdi_uuid + in + debug "GTNDEBUG: add image format %s,%s" vdi_uuid vdi_fmt ; + (vdi, vdi_fmt) + ) + (read_map_params "image-format" params) + in let vgpu_map = List.map (fun (vgpu_uuid, gpu_group_uuid) -> @@ -4869,7 +4885,8 @@ let vm_migrate printer rpc session_id params = rpc session_id (fun vm -> Client.VM.migrate_send ~rpc ~session_id ~vm:(vm.getref ()) - ~dest:token ~live:true ~vdi_map ~vif_map ~options ~vgpu_map + ~dest:token ~live:true ~vdi_map ~vdi_format_map ~vif_map + ~options ~vgpu_map ) params (["host"; "host-uuid"; "host-name"; "live"; "force"; "copy"] diff --git a/ocaml/xapi-cli-server/records.ml b/ocaml/xapi-cli-server/records.ml index cb88ace5540..7f51fd2d657 100644 --- a/ocaml/xapi-cli-server/records.ml +++ b/ocaml/xapi-cli-server/records.ml @@ -3844,6 +3844,11 @@ let sm_record rpc session_id sm = ; make_field ~name:"required-cluster-stack" ~get:(fun () -> concat_with_comma (x ()).API.sM_required_cluster_stack) () + ; make_field ~name:"supported-image-formats" + ~get:(fun () -> + concat_with_comma (x ()).API.sM_supported_image_formats + ) + () ] } diff --git a/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.0 b/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.0 index 93c377800c0..292d852204e 100644 --- a/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.0 +++ b/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.0 @@ -1 +1 @@ -StatusSuccessValuerequired_cluster_stackconfigurationconfigurationconfigurationfeaturesrequired_api_versionrequired_api_versionversionversioncopyrightcopyrightvendorvendordescriptiondescriptionnamenamedriverdriver \ No newline at end of file +StatusSuccessValuesupported_image_formatsrequired_cluster_stackconfigurationconfigurationconfigurationfeaturesrequired_api_versionrequired_api_versionversionversioncopyrightcopyrightvendorvendordescriptiondescriptionnamenamedriverdriver diff --git a/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.1 b/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.1 index cdf744f3fe2..d543bfecd03 100644 --- a/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.1 +++ b/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.1 @@ -1 +1 @@ -StatusSuccessValuerequired_cluster_stackconfigurationconfigurationconfigurationfeaturesfeaturesrequired_api_versionrequired_api_versionversionversioncopyrightcopyrightvendorvendordescriptiondescriptionnamenamedriverdriver \ No newline at end of file +StatusSuccessValuesupported_image_formatsrequired_cluster_stackconfigurationconfigurationconfigurationfeaturesfeaturesrequired_api_versionrequired_api_versionversionversioncopyrightcopyrightvendorvendordescriptiondescriptionnamenamedriverdriver diff --git a/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.2 b/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.2 index f26aeeaa073..f0880cdb2f1 100644 --- a/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.2 +++ b/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.2 @@ -1 +1 @@ -StatusSuccessValuerequired_cluster_stackrequired_cluster_stackconfigurationconfigurationconfigurationfeaturesrequired_api_versionrequired_api_versionversionversioncopyrightcopyrightvendorvendordescriptiondescriptionnamenamedriverdriver \ No newline at end of file +StatusSuccessValuesupported_image_formatsvhdrequired_cluster_stackrequired_cluster_stackconfigurationconfigurationconfigurationfeaturesrequired_api_versionrequired_api_versionversionversioncopyrightcopyrightvendorvendordescriptiondescriptionnamenamedriverdriver diff --git a/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.3 b/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.3 index 38dacf3f661..d1fbabb1885 100644 --- a/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.3 +++ b/ocaml/xapi-idl/lib_test/test_data/storage/responses/Query.query.response.3 @@ -1 +1 @@ -StatusSuccessValuerequired_cluster_stackrequired_cluster_stackconfigurationconfigurationconfigurationfeaturesfeaturesrequired_api_versionrequired_api_versionversionversioncopyrightcopyrightvendorvendordescriptiondescriptionnamenamedriverdriver \ No newline at end of file +StatusSuccessValuesupported_image_formatsrequired_cluster_stackrequired_cluster_stackconfigurationconfigurationconfigurationfeaturesfeaturesrequired_api_versionrequired_api_versionversionversioncopyrightcopyrightvendorvendordescriptiondescriptionnamenamedriverdriver diff --git a/ocaml/xapi-idl/storage/storage_interface.ml b/ocaml/xapi-idl/storage/storage_interface.ml index eaabacc9e8f..25939f67484 100644 --- a/ocaml/xapi-idl/storage/storage_interface.ml +++ b/ocaml/xapi-idl/storage/storage_interface.ml @@ -264,6 +264,8 @@ let string_of_vdi_info (x : vdi_info) = Jsonrpc.to_string (rpc_of vdi_info x) "datapaths". *) type dp = string [@@deriving rpcty] +type image_format = string [@@deriving rpcty] + type sock_path = string [@@deriving rpcty] type dp_stat_t = { @@ -290,6 +292,8 @@ type probe_result = module Mirror = struct type id = string [@@deriving rpcty] + type image_format = string [@@deriving rpcty] + type state = Receiving | Sending | Copying [@@deriving rpcty] type t = {source_vdi: Vdi.t; dest_vdi: Vdi.t; state: state list; failed: bool} @@ -477,6 +481,7 @@ type query_result = { ; configuration: (string * string) list ; required_cluster_stack: string list ; smapi_version: smapi_version + ; supported_image_formats: string list } [@@deriving rpcty] @@ -503,6 +508,8 @@ module StorageAPI (R : RPC) = struct let vdi_p = Param.mk ~name:"vdi" Vdi.t + let image_format_p = Param.mk ~name:"image_format" image_format + let vm_p = Param.mk ~name:"vm" Vm.t let dp_p = Param.mk ~name:"dp" dp @@ -687,9 +694,9 @@ module StorageAPI (R : RPC) = struct declare "SR.destroy" [] (dbg_p @-> sr_p @-> returning unit_p err) (** [scan task sr] returns a list of VDIs contained within an attached SR. - @deprecated This function is deprecated, and is only here to keep backward - compatibility with old xapis that call Remote.SR.scan during SXM. - Use the scan2 function instead. + @deprecated This function is deprecated, and is only here to keep backward + compatibility with old xapis that call Remote.SR.scan during SXM. + Use the scan2 function instead. *) let scan = let open TypeCombinators in @@ -1065,6 +1072,7 @@ module StorageAPI (R : RPC) = struct (dbg_p @-> sr_p @-> vdi_p + @-> image_format_p @-> vm_p @-> url_p @-> returning operation_p err @@ -1081,7 +1089,7 @@ module StorageAPI (R : RPC) = struct @-> returning status_p err ) - (** [import_activate dbg dp sr vdi vm] returns a server socket address to + (** [import_activate dbg dp sr vdi vm] returns a server socket address to which a fd can be passed via SCM_RIGHTS for mirroring purposes.*) let import_activate = declare "DATA.import_activate" [] @@ -1095,7 +1103,7 @@ module StorageAPI (R : RPC) = struct (** [get_nbd_server dbg dp sr vdi vm] returns the address of a generic nbd server that can be connected to. Depending on the backend, this will either - be a nbd server backed by tapdisk or qemu-dp. Note this is different + be a nbd server backed by tapdisk or qemu-dp. Note this is different from [import_activate] as the returned server does not accept fds. *) let get_nbd_server = declare "DATA.get_nbd_server" [] @@ -1116,9 +1124,9 @@ module StorageAPI (R : RPC) = struct let id_p = Param.mk ~name:"id" Mirror.id - (** [send_start dbg dp task src_sr vdi mirror_vm mirror_id local_vdi copy_vm - live_vm url remote_mirror dest_sr verify_dest] - takes the remote mirror [remote_mirror] prepared by the destination host + (** [send_start dbg dp task src_sr vdi image_format mirror_vm mirror_id + local_vdi copy_vm live_vm url remote_mirror dest_sr verify_dest] + takes the remote mirror [remote_mirror] prepared by the destination host and initiates the mirroring of [vdi] from the source *) let send_start = let recv_result_p = @@ -1133,6 +1141,7 @@ module StorageAPI (R : RPC) = struct @-> task_id_p @-> src_sr_p @-> vdi_p + @-> image_format_p @-> mirror_vm_p @-> id_p @-> local_vdi_p @@ -1145,35 +1154,43 @@ module StorageAPI (R : RPC) = struct @-> returning unit_p err ) - (** Called on the receiving end - @deprecated This function is deprecated, and is only here to keep backward - compatibility with old xapis that call Remote.DATA.MIRROR.receive_start during SXM. - Use the receive_start3 function instead. + (** Called on the receiving end + @deprecated This function is deprecated, and is only here to keep backward + compatibility with old xapis that call Remote.DATA.MIRROR.receive_start during SXM. + Use the receive_start3 function instead. *) let receive_start = + let image_format_p = + Param.mk ~name:"image_format" Mirror.image_format + in let similar_p = Param.mk ~name:"similar" Mirror.similars in let result = Param.mk ~name:"result" Mirror.mirror_receive_result in declare "DATA.MIRROR.receive_start" [] (dbg_p @-> sr_p @-> VDI.vdi_info_p + @-> image_format_p @-> id_p @-> similar_p @-> returning result err ) - (** Called on the receiving end - @deprecated This function is deprecated, and is only here to keep backward - compatibility with old xapis that call Remote.DATA.MIRROR.receive_start2 during SXM. - Use the receive_start3 function instead. + (** Called on the receiving end + @deprecated This function is deprecated, and is only here to keep backward + compatibility with old xapis that call Remote.DATA.MIRROR.receive_start2 during SXM. + Use the receive_start3 function instead. *) let receive_start2 = + let image_format_p = + Param.mk ~name:"image_format" Mirror.image_format + in let similar_p = Param.mk ~name:"similar" Mirror.similars in let result = Param.mk ~name:"result" Mirror.mirror_receive_result in declare "DATA.MIRROR.receive_start2" [] (dbg_p @-> sr_p @-> VDI.vdi_info_p + @-> image_format_p @-> id_p @-> similar_p @-> vm_p @@ -1189,6 +1206,7 @@ module StorageAPI (R : RPC) = struct (dbg_p @-> sr_p @-> VDI.vdi_info_p + @-> image_format_p @-> id_p @-> similar_p @-> vm_p @@ -1197,26 +1215,26 @@ module StorageAPI (R : RPC) = struct @-> returning result err ) - (** Called on the receiving end - @deprecated This function is deprecated, and is only here to keep backward + (** Called on the receiving end + @deprecated This function is deprecated, and is only here to keep backward compatibility with old xapis that call Remote.DATA.MIRROR.receive_finalize - during SXM. Use the receive_finalize3 function instead. + during SXM. Use the receive_finalize3 function instead. *) let receive_finalize = declare "DATA.MIRROR.receive_finalize" [] (dbg_p @-> id_p @-> returning unit_p err) - (** Called on the receiving end - @deprecated This function is deprecated, and is only here to keep backward + (** Called on the receiving end + @deprecated This function is deprecated, and is only here to keep backward compatibility with old xapis that call Remote.DATA.MIRROR.receive_finalize2 - during SXM. Use the receive_finalize3 function instead. + during SXM. Use the receive_finalize3 function instead. *) let receive_finalize2 = declare "DATA.MIRROR.receive_finalize2" [] (dbg_p @-> id_p @-> returning unit_p err) - (** [receive_finalize3 dbg id] will stop the mirroring process and compose - the snapshot VDI with the mirror VDI. It also cleans up the storage resources + (** [receive_finalize3 dbg id] will stop the mirroring process and compose + the snapshot VDI with the mirror VDI. It also cleans up the storage resources used by mirroring. It is called after the the source VM is paused. This fucntion should be used in conjunction with [receive_start3] *) let receive_finalize3 = @@ -1231,9 +1249,9 @@ module StorageAPI (R : RPC) = struct (** [receive_cancel dbg id] is called in the case of migration failure to do the clean up. - @deprecated This function is deprecated, and is only here to keep backward + @deprecated This function is deprecated, and is only here to keep backward compatibility with old xapis that call Remote.DATA.MIRROR.receive_cancel - during SXM. Use the receive_cancel2 function instead. + during SXM. Use the receive_cancel2 function instead. *) let receive_cancel = declare "DATA.MIRROR.receive_cancel" [] @@ -1319,6 +1337,7 @@ module type MIRROR = sig -> dp:dp -> sr:sr -> vdi:vdi + -> image_format:image_format -> mirror_vm:vm -> mirror_id:Mirror.id -> local_vdi:vdi_info @@ -1335,6 +1354,7 @@ module type MIRROR = sig -> dbg:debug_info -> sr:sr -> vdi_info:vdi_info + -> image_format:string -> id:Mirror.id -> similar:Mirror.similars -> Mirror.mirror_receive_result @@ -1344,6 +1364,7 @@ module type MIRROR = sig -> dbg:debug_info -> sr:sr -> vdi_info:vdi_info + -> image_format:string -> id:Mirror.id -> similar:Mirror.similars -> vm:vm @@ -1354,6 +1375,7 @@ module type MIRROR = sig -> dbg:debug_info -> sr:sr -> vdi_info:vdi_info + -> image_format:string -> mirror_id:Mirror.id -> similar:Mirror.similars -> vm:vm @@ -1656,6 +1678,7 @@ module type Server_impl = sig -> dbg:debug_info -> sr:sr -> vdi:vdi + -> image_format:string -> vm:vm -> dest:string -> operation @@ -1843,8 +1866,8 @@ module Server (Impl : Server_impl) () = struct S.DATA.copy (fun dbg sr vdi vm url dest verify_dest -> Impl.DATA.copy () ~dbg ~sr ~vdi ~vm ~url ~dest ~verify_dest ) ; - S.DATA.mirror (fun dbg sr vdi vm dest -> - Impl.DATA.mirror () ~dbg ~sr ~vdi ~vm ~dest + S.DATA.mirror (fun dbg sr vdi image_format vm dest -> + Impl.DATA.mirror () ~dbg ~sr ~vdi ~image_format ~vm ~dest ) ; S.DATA.stat (fun dbg sr vdi vm key -> Impl.DATA.stat () ~dbg ~sr ~vdi ~vm ~key @@ -1856,6 +1879,7 @@ module Server (Impl : Server_impl) () = struct dp sr vdi + image_format mirror_vm mirror_id local_vdi @@ -1866,20 +1890,23 @@ module Server (Impl : Server_impl) () = struct dest_sr verify_dest -> - Impl.DATA.MIRROR.send_start () ~dbg ~task_id ~dp ~sr ~vdi ~mirror_vm - ~mirror_id ~local_vdi ~copy_vm ~live_vm ~url ~remote_mirror ~dest_sr - ~verify_dest + Impl.DATA.MIRROR.send_start () ~dbg ~task_id ~dp ~sr ~vdi ~image_format + ~mirror_vm ~mirror_id ~local_vdi ~copy_vm ~live_vm ~url ~remote_mirror + ~dest_sr ~verify_dest ) ; - S.DATA.MIRROR.receive_start (fun dbg sr vdi_info id similar -> - Impl.DATA.MIRROR.receive_start () ~dbg ~sr ~vdi_info ~id ~similar + S.DATA.MIRROR.receive_start (fun dbg sr vdi_info image_format id similar -> + Impl.DATA.MIRROR.receive_start () ~dbg ~sr ~vdi_info ~image_format ~id + ~similar ) ; - S.DATA.MIRROR.receive_start2 (fun dbg sr vdi_info id similar vm -> - Impl.DATA.MIRROR.receive_start2 () ~dbg ~sr ~vdi_info ~id ~similar ~vm + S.DATA.MIRROR.receive_start2 + (fun dbg sr vdi_info image_format id similar vm -> + Impl.DATA.MIRROR.receive_start2 () ~dbg ~sr ~vdi_info ~image_format ~id + ~similar ~vm ) ; S.DATA.MIRROR.receive_start3 - (fun dbg sr vdi_info mirror_id similar vm url verify_dest -> - Impl.DATA.MIRROR.receive_start3 () ~dbg ~sr ~vdi_info ~mirror_id - ~similar ~vm ~url ~verify_dest + (fun dbg sr vdi_info image_format mirror_id similar vm url verify_dest -> + Impl.DATA.MIRROR.receive_start3 () ~dbg ~sr ~vdi_info ~image_format + ~mirror_id ~similar ~vm ~url ~verify_dest ) ; S.DATA.MIRROR.receive_cancel (fun dbg id -> Impl.DATA.MIRROR.receive_cancel () ~dbg ~id diff --git a/ocaml/xapi-idl/storage/storage_skeleton.ml b/ocaml/xapi-idl/storage/storage_skeleton.ml index a2d2d04ab08..0e2d68a1845 100644 --- a/ocaml/xapi-idl/storage/storage_skeleton.ml +++ b/ocaml/xapi-idl/storage/storage_skeleton.ml @@ -183,7 +183,7 @@ module DATA = struct let copy ctx ~dbg ~sr ~vdi ~vm ~url ~dest = Storage_interface.unimplemented __FUNCTION__ - let mirror ctx ~dbg ~sr ~vdi ~vm ~dest = + let mirror ctx ~dbg ~sr ~vdi ~image_format ~vm ~dest = Storage_interface.unimplemented __FUNCTION__ let stat ctx ~dbg ~sr ~vdi ~vm ~key = @@ -198,18 +198,19 @@ module DATA = struct module MIRROR = struct type context = unit - let send_start ctx ~dbg ~task_id ~dp ~sr ~vdi ~mirror_vm ~mirror_id - ~local_vdi ~copy_vm ~live_vm ~url ~remote_mirror ~dest_sr ~verify_dest = + let send_start ctx ~dbg ~task_id ~dp ~sr ~vdi ~image_format ~mirror_vm + ~mirror_id ~local_vdi ~copy_vm ~live_vm ~url ~remote_mirror ~dest_sr + ~verify_dest = Storage_interface.unimplemented __FUNCTION__ - let receive_start ctx ~dbg ~sr ~vdi_info ~id ~similar = + let receive_start ctx ~dbg ~sr ~vdi_info ~image_format ~id ~similar = Storage_interface.unimplemented __FUNCTION__ - let receive_start2 ctx ~dbg ~sr ~vdi_info ~id ~similar ~vm = + let receive_start2 ctx ~dbg ~sr ~vdi_info ~image_format ~id ~similar ~vm = Storage_interface.unimplemented __FUNCTION__ - let receive_start3 ctx ~dbg ~sr ~vdi_info ~mirror_id ~similar ~vm ~url - ~verify_dest = + let receive_start3 ctx ~dbg ~sr ~vdi_info ~image_format ~mirror_id ~similar + ~vm ~url ~verify_dest = Storage_interface.unimplemented __FUNCTION__ let receive_finalize ctx ~dbg ~id = diff --git a/ocaml/xapi-storage-cli/main.ml b/ocaml/xapi-storage-cli/main.ml index f581d6b6b48..5a26ef2215f 100644 --- a/ocaml/xapi-storage-cli/main.ml +++ b/ocaml/xapi-storage-cli/main.ml @@ -317,16 +317,19 @@ let copy_vm = Vm.of_string "SXM_copy" let live_vm = Vm.of_string "live_vm" -let mirror_start common_opts sr vdi dp url dest verify_dest = +let mirror_start common_opts sr vdi dp url dest verify_dest dest_img_format = on_vdi' (fun sr vdi -> let get_opt x err = match x with Some y -> y | None -> failwith err in let dp = get_opt dp "Need a local data path" in let url = get_opt url "Need a URL" in let dest = get_opt dest "Need a destination SR" in + let image_format = + match dest_img_format with Some s -> s | None -> "" + in let task = - Storage_migrate.start ~dbg ~sr ~vdi ~dp ~mirror_vm ~copy_vm ~live_vm - ~url + Storage_migrate.start ~dbg ~sr ~vdi ~image_format ~dp ~mirror_vm + ~copy_vm ~live_vm ~url ~dest:(Storage_interface.Sr.of_string dest) ~verify_dest in @@ -531,6 +534,10 @@ let mirror_start_cmd = let doc = "Verify certicate of remote server" in Arg.(value & pos 5 bool false & info [] ~docv:"VERIFYDEST" ~doc) in + let dest_img_format = + let doc = "Specify the image format on the destination SR" in + Arg.(value & pos 6 (some string) None & info [] ~docv:"IMAGEFORMAT" ~doc) + in ( Term.( ret (const mirror_start @@ -541,6 +548,7 @@ let mirror_start_cmd = $ url $ dest $ verify_dest + $ dest_img_format ) ) , Cmd.info "mirror-start" ~sdocs:_common_options ~doc ~man diff --git a/ocaml/xapi-storage-script/main.ml b/ocaml/xapi-storage-script/main.ml index e04a93203b3..01d156f4670 100644 --- a/ocaml/xapi-storage-script/main.ml +++ b/ocaml/xapi-storage-script/main.ml @@ -937,6 +937,8 @@ module QueryImpl (M : META) = struct ; required_cluster_stack= response.Xapi_storage.Plugin.required_cluster_stack ; smapi_version= SMAPIv3 + ; supported_image_formats= + response.Xapi_storage.Plugin.supported_image_formats } in wrap th @@ -1812,7 +1814,7 @@ module DATAImpl (M : META) = struct let stat_impl dbg sr vdi vm key = wrap @@ stat dbg sr vdi vm key - let mirror dbg sr vdi' vm' remote = + let mirror dbg sr vdi' image_format' vm' remote = let vdi = Storage_interface.Vdi.string_of vdi' in let domain = Storage_interface.Vm.string_of vm' in Attached_SRs.find sr >>>= fun sr -> @@ -1836,7 +1838,8 @@ module DATAImpl (M : META) = struct | MirrorV1 v -> return (Storage_interface.Mirror.MirrorV1 v) - let mirror_impl dbg sr vdi vm remote = wrap @@ mirror dbg sr vdi vm remote + let mirror_impl dbg sr vdi image_format vm remote = + wrap @@ mirror dbg sr vdi image_format vm remote let data_import_activate_impl dbg _dp sr vdi' vm' = wrap diff --git a/ocaml/xapi-storage-script/test/volume/org.xen.xapi.storage.dummyv5/plugin.py b/ocaml/xapi-storage-script/test/volume/org.xen.xapi.storage.dummyv5/plugin.py index bf54820cdc4..6618ee2f1c4 100755 --- a/ocaml/xapi-storage-script/test/volume/org.xen.xapi.storage.dummyv5/plugin.py +++ b/ocaml/xapi-storage-script/test/volume/org.xen.xapi.storage.dummyv5/plugin.py @@ -31,7 +31,8 @@ def query(self, dbg): # pylint: disable=unused-argument "VDI_CREATE", "VDI_DESTROY"], "configuration": {}, - "required_cluster_stack": []} + "required_cluster_stack": [], + "supported_image_formats": []} if __name__ == "__main__": diff --git a/ocaml/xapi-storage/generator/lib/plugin.ml b/ocaml/xapi-storage/generator/lib/plugin.ml index 4fc4d6d3fa0..f346a196968 100644 --- a/ocaml/xapi-storage/generator/lib/plugin.ml +++ b/ocaml/xapi-storage/generator/lib/plugin.ml @@ -18,6 +18,9 @@ type query_result = { (** Key/description pairs describing required device_config parameters. *) ; required_cluster_stack: string list (** The plugin requires one of these cluster stacks to be active. *) + ; supported_image_formats: string list + (** List of image formats (VHD, RAW, Qcow2, ...) supported by an + SR.type. *) } [@@deriving rpcty] diff --git a/ocaml/xapi-storage/python/examples/datapath/loop+blkback/plugin.py b/ocaml/xapi-storage/python/examples/datapath/loop+blkback/plugin.py index 4cbc9939fbd..fc02432959e 100755 --- a/ocaml/xapi-storage/python/examples/datapath/loop+blkback/plugin.py +++ b/ocaml/xapi-storage/python/examples/datapath/loop+blkback/plugin.py @@ -37,7 +37,8 @@ def query(self, dbg): "required_api_version": "5.0", "features": [], "configuration": {}, - "required_cluster_stack": []} + "required_cluster_stack": [], + "supported_image_formats": []} if __name__ == "__main__": diff --git a/ocaml/xapi-storage/python/examples/volume/org.xen.xapi.storage.simple-file/plugin.py b/ocaml/xapi-storage/python/examples/volume/org.xen.xapi.storage.simple-file/plugin.py index 583043015ed..4402b55d514 100755 --- a/ocaml/xapi-storage/python/examples/volume/org.xen.xapi.storage.simple-file/plugin.py +++ b/ocaml/xapi-storage/python/examples/volume/org.xen.xapi.storage.simple-file/plugin.py @@ -54,7 +54,8 @@ def query(self, dbg): "VDI_RESIZE", "THIN_PROVISIONING"], "configuration": config, - "required_cluster_stack": [] + "required_cluster_stack": [], + "supported_image_formats": [] } if __name__ == "__main__": diff --git a/ocaml/xapi/message_forwarding.ml b/ocaml/xapi/message_forwarding.ml index b52aaaa20ec..1c602f9a38a 100644 --- a/ocaml/xapi/message_forwarding.ml +++ b/ocaml/xapi/message_forwarding.ml @@ -2535,26 +2535,26 @@ functor assuming it can ignore this check." let assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map ~vif_map - ~options ~vgpu_map = + ~options ~vgpu_map ~vdi_format_map = info "VM.assert_can_migrate: VM = '%s'" (vm_uuid ~__context vm) ; (* Run the checks that can be done using just the DB directly on the master *) - Local.VM.assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map ~vif_map - ~vgpu_map ~options ; + Local.VM.assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map + ~vdi_format_map ~vif_map ~vgpu_map ~options ; (* Run further checks on the sending host *) assert_can_migrate_sender ~__context ~vm ~dest ~live ~vdi_map ~vif_map ~vgpu_map ~options let migrate_send ~__context ~vm ~dest ~live ~vdi_map ~vif_map ~options - ~vgpu_map = + ~vgpu_map ~vdi_format_map = info "VM.migrate_send: VM = '%s'" (vm_uuid ~__context vm) ; let source_host = Db.VM.get_resident_on ~__context ~self:vm in let local_fn = - Local.VM.migrate_send ~vm ~dest ~live ~vdi_map ~vif_map ~vgpu_map - ~options + Local.VM.migrate_send ~vm ~dest ~live ~vdi_map ~vdi_format_map + ~vif_map ~vgpu_map ~options in let remote_fn = - Client.VM.migrate_send ~vm ~dest ~live ~vdi_map ~vif_map ~options - ~vgpu_map + Client.VM.migrate_send ~vm ~dest ~live ~vdi_map ~vdi_format_map + ~vif_map ~options ~vgpu_map in let migration_type = if Xapi_vm_lifecycle_helpers.is_live ~__context ~self:vm then @@ -2575,7 +2575,8 @@ functor Helpers.try_internal_async ~__context API.ref_VM_of_rpc (fun () -> Client.InternalAsync.VM.migrate_send ~rpc ~session_id ~vm - ~dest ~live ~vdi_map ~vif_map ~options ~vgpu_map + ~dest ~live ~vdi_map ~vdi_format_map ~vif_map ~options + ~vgpu_map ) (fun () -> remote_fn ~session_id ~rpc) ) @@ -2614,7 +2615,7 @@ functor Server_helpers.exec_with_subtask ~__context "VM.assert_can_migrate" (fun ~__context -> assert_can_migrate ~__context ~vm ~dest ~live ~vdi_map - ~vif_map ~vgpu_map ~options + ~vdi_format_map ~vif_map ~vgpu_map ~options ) ; forward_migrate_send () ) @@ -5315,7 +5316,7 @@ functor ~prefer_slaves:true ~remote_fn ) - let pool_migrate ~__context ~vdi ~sr ~options = + let pool_migrate ~__context ~vdi ~sr ~dest_img_format ~options = let vbds = let expr = Xapi_database.Db_filter_types.( @@ -5335,7 +5336,9 @@ functor ("__internal__vm", Ref.string_of vm) :: List.remove_assoc "__internal__vm" options in - let local_fn = Local.VDI.pool_migrate ~vdi ~sr ~options in + let local_fn = + Local.VDI.pool_migrate ~vdi ~sr ~dest_img_format ~options + in let force = try bool_of_string (List.assoc "force" options) with _ -> false in @@ -5370,11 +5373,12 @@ functor in let remote_fn ~rpc ~session_id = let sync_op () = - Client.VDI.pool_migrate ~rpc ~session_id ~vdi ~sr ~options + Client.VDI.pool_migrate ~rpc ~session_id ~vdi ~sr + ~dest_img_format ~options in let async_op () = Client.InternalAsync.VDI.pool_migrate ~rpc ~session_id ~vdi ~sr - ~options + ~dest_img_format ~options in Helpers.try_internal_async ~__context API.ref_VDI_of_rpc async_op sync_op diff --git a/ocaml/xapi/sm_exec.ml b/ocaml/xapi/sm_exec.ml index c4e2c46a1a9..ba439558756 100644 --- a/ocaml/xapi/sm_exec.ml +++ b/ocaml/xapi/sm_exec.ml @@ -570,6 +570,13 @@ let parse_sr_get_driver_info driver (xml : Xml.xml) = ) (XMLRPC.From.array XMLRPC.From.structure (safe_assoc "configuration" info)) in + let image_formats = + match List.assoc_opt "supported_image_formats" info with + | None -> + [] + | Some lst -> + XMLRPC.From.array XMLRPC.From.string lst + in { sr_driver_filename= driver ; sr_driver_name= name @@ -583,6 +590,7 @@ let parse_sr_get_driver_info driver (xml : Xml.xml) = ; sr_driver_text_features= text_features ; sr_driver_required_cluster_stack= [] ; sr_smapi_version= SMAPIv1 + ; sr_driver_supported_image_formats= image_formats } let sr_get_driver_info ~dbg driver = diff --git a/ocaml/xapi/smint.ml b/ocaml/xapi/smint.ml index e58340b5239..9a3ce556797 100644 --- a/ocaml/xapi/smint.ml +++ b/ocaml/xapi/smint.ml @@ -153,7 +153,7 @@ module Feature = struct let of_string_int64_opt (c, v) = List.assoc_opt c string_to_capability_table |> Option.map (fun c -> (c, v)) - (** [has_capability c fl] will test weather the required capability [c] is present + (** [has_capability c fl] will test weather the required capability [c] is present in the feature list [fl]. Callers should use this function to test if a feature is available rather than directly using membership functions on a feature list as this function might have special logic for some features. *) @@ -193,6 +193,7 @@ type sr_driver_info = { ; sr_driver_configuration: (string * string) list ; sr_driver_required_cluster_stack: string list ; sr_smapi_version: Storage_interface.smapi_version + ; sr_driver_supported_image_formats: string list } let query_result_of_sr_driver_info x = @@ -208,6 +209,7 @@ let query_result_of_sr_driver_info x = ; configuration= x.sr_driver_configuration ; required_cluster_stack= x.sr_driver_required_cluster_stack ; smapi_version= x.sr_smapi_version + ; supported_image_formats= x.sr_driver_supported_image_formats } type attach_info = { diff --git a/ocaml/xapi/storage_migrate.ml b/ocaml/xapi/storage_migrate.ml index 1ff03c3d7ed..7c70605d86f 100644 --- a/ocaml/xapi/storage_migrate.ml +++ b/ocaml/xapi/storage_migrate.ml @@ -51,7 +51,7 @@ module MigrateRemote = struct Migrate_Backend.receive_cancel2 () ~dbg ~mirror_id ~url ~verify_dest end -(** This module [MigrateLocal] consists of the concrete implementations of the +(** This module [MigrateLocal] consists of the concrete implementations of the migration part of SMAPI. Functions inside this module are sender driven, which means they tend to be executed on the sender side. although there is not a hard rule on what is executed on the sender side, this provides some heuristics. *) @@ -125,15 +125,15 @@ module MigrateLocal = struct raise (Storage_error (Migration_preparation_failure (Printexc.to_string e))) - let start ~task_id ~dbg ~sr ~vdi ~dp ~mirror_vm ~copy_vm ~live_vm ~url ~dest - ~verify_dest = + let start ~task_id ~dbg ~sr ~vdi ~image_format ~dp ~mirror_vm ~copy_vm + ~live_vm ~url ~dest ~verify_dest = SXM.info - "%s sr:%s vdi:%s dp: %s mirror_vm: %s copy_vm: %s url:%s dest:%s \ - verify_dest:%B" + "%s sr:%s vdi:%s image_format: %s dp: %s mirror_vm: %s copy_vm: %s \ + url:%s dest:%s verify_dest:%B" __FUNCTION__ (Storage_interface.Sr.string_of sr) (Storage_interface.Vdi.string_of vdi) - dp + image_format dp (Storage_interface.Vm.string_of mirror_vm) (Storage_interface.Vm.string_of copy_vm) url @@ -168,11 +168,11 @@ module MigrateLocal = struct let (module Migrate_Backend) = choose_backend dbg sr in try let remote_mirror = - prepare ~dbg ~sr ~vdi ~dest ~local_vdi ~mirror_id ~mirror_vm ~url - ~verify_dest + prepare ~dbg ~sr ~vdi ~image_format ~dest ~local_vdi ~mirror_id + ~mirror_vm ~url ~verify_dest in - Migrate_Backend.send_start () ~dbg ~task_id ~dp ~sr ~vdi ~mirror_vm - ~mirror_id ~local_vdi ~copy_vm ~live_vm ~url ~remote_mirror + Migrate_Backend.send_start () ~dbg ~task_id ~dp ~sr ~vdi ~image_format + ~mirror_vm ~mirror_id ~local_vdi ~copy_vm ~live_vm ~url ~remote_mirror ~dest_sr:dest ~verify_dest ; Some (Mirror_id mirror_id) with @@ -427,14 +427,14 @@ let copy ~dbg ~sr ~vdi ~vm ~url ~dest ~verify_dest = ~sr ~vdi ~vm ~url ~dest ~verify_dest ) -let start ~dbg ~sr ~vdi ~dp ~mirror_vm ~copy_vm ~live_vm ~url ~dest ~verify_dest - = +let start ~dbg ~sr ~vdi ~image_format ~dp ~mirror_vm ~copy_vm ~live_vm ~url + ~dest ~verify_dest = with_dbg ~name:__FUNCTION__ ~dbg @@ fun dbg -> with_task_and_thread ~dbg (fun task -> MigrateLocal.start ~task_id:(Storage_task.id_of_handle task) - ~dbg:dbg.Debug_info.log ~sr ~vdi ~dp ~mirror_vm ~copy_vm ~live_vm ~url - ~dest ~verify_dest + ~dbg:dbg.Debug_info.log ~sr ~vdi ~image_format ~dp ~mirror_vm ~copy_vm + ~live_vm ~url ~dest ~verify_dest ) (* XXX: PR-1255: copy the xenopsd 'raise Exception' pattern *) diff --git a/ocaml/xapi/storage_mux.ml b/ocaml/xapi/storage_mux.ml index 0427f76ca54..c4f47b9f321 100644 --- a/ocaml/xapi/storage_mux.ml +++ b/ocaml/xapi/storage_mux.ml @@ -77,6 +77,7 @@ module Mux = struct ; configuration= [] ; required_cluster_stack= [] ; smapi_version= SMAPIv2 + ; supported_image_formats= [] } let diagnostics () ~dbg = @@ -812,14 +813,14 @@ module Mux = struct let copy () ~dbg = with_dbg ~name:"DATA.copy" ~dbg @@ fun dbg -> Storage_migrate.copy ~dbg - let mirror () ~dbg ~sr ~vdi ~vm ~dest = + let mirror () ~dbg ~sr ~vdi ~image_format ~vm ~dest = with_dbg ~name:"DATA.mirror" ~dbg @@ fun di -> info "%s dbg:%s sr: %s vdi: %s vm:%s remote:%s" __FUNCTION__ dbg (s_of_sr sr) (s_of_vdi vdi) (s_of_vm vm) dest ; let module C = StorageAPI (Idl.Exn.GenClient (struct let rpc = of_sr sr end)) in - C.DATA.mirror (Debug_info.to_string di) sr vdi vm dest + C.DATA.mirror (Debug_info.to_string di) sr vdi image_format vm dest let stat () ~dbg ~sr ~vdi ~vm ~key = with_dbg ~name:"DATA.stat" ~dbg @@ fun di -> @@ -851,41 +852,45 @@ module Mux = struct module MIRROR = struct type context = unit - let send_start _ctx ~dbg:_ ~task_id:_ ~dp:_ ~sr:_ ~vdi:_ ~mirror_vm:_ - ~mirror_id:_ ~local_vdi:_ ~copy_vm:_ ~live_vm:_ ~url:_ + let send_start _ctx ~dbg:_ ~task_id:_ ~dp:_ ~sr:_ ~vdi:_ ~image_format:_ + ~mirror_vm:_ ~mirror_id:_ ~local_vdi:_ ~copy_vm:_ ~live_vm:_ ~url:_ ~remote_mirror:_ ~dest_sr:_ ~verify_dest:_ = Storage_interface.unimplemented __FUNCTION__ (* see storage_smapi{v1,v3}_migrate.ml *) - let receive_start () ~dbg ~sr ~vdi_info ~id ~similar = + let receive_start () ~dbg ~sr ~vdi_info ~image_format ~id ~similar = with_dbg ~name:"DATA.MIRROR.receive_start" ~dbg @@ fun _di -> - info "%s dbg: %s sr: %s vdi_info: %s mirror_id: %s similar: %s" + info + "%s dbg: %s sr: %s vdi_info: %s image_format: %s mirror_id: %s \ + similar: %s" __FUNCTION__ dbg (s_of_sr sr) (string_of_vdi_info vdi_info) - id + image_format id (String.concat ";" similar) ; (* This goes straight to storage_smapiv1_migrate for backwards compatability reasons, new code should not call receive_start any more *) - Storage_smapiv1_migrate.MIRROR.receive_start () ~dbg ~sr ~vdi_info ~id - ~similar + Storage_smapiv1_migrate.MIRROR.receive_start () ~dbg ~sr ~vdi_info + ~image_format ~id ~similar - let receive_start2 () ~dbg ~sr ~vdi_info ~id ~similar ~vm = + let receive_start2 () ~dbg ~sr ~vdi_info ~image_format ~id ~similar ~vm = with_dbg ~name:"DATA.MIRROR.receive_start2" ~dbg @@ fun _di -> - info "%s dbg: %s sr: %s vdi_info: %s mirror_id: %s similar: %s vm: %s" + info + "%s dbg: %s sr: %s vdi_info: %s image_format: %s mirror_id: %s \ + similar: %s vm: %s" __FUNCTION__ dbg (s_of_sr sr) (string_of_vdi_info vdi_info) - id + image_format id (String.concat ";" similar) (s_of_vm vm) ; info "%s dbg:%s" __FUNCTION__ dbg ; (* This goes straight to storage_smapiv1_migrate for backwards compatability reasons, new code should not call receive_start any more *) - Storage_smapiv1_migrate.MIRROR.receive_start2 () ~dbg ~sr ~vdi_info ~id - ~similar ~vm + Storage_smapiv1_migrate.MIRROR.receive_start2 () ~dbg ~sr ~vdi_info + ~image_format ~id ~similar ~vm (** see storage_smapiv{1,3}_migrate.receive_start3 *) - let receive_start3 () ~dbg:_ ~sr:_ ~vdi_info:_ ~mirror_id:_ ~similar:_ - ~vm:_ = + let receive_start3 () ~dbg:_ ~sr:_ ~vdi_info:_ ~image_format:_ + ~mirror_id:_ ~similar:_ ~vm:_ = Storage_interface.unimplemented __FUNCTION__ let receive_finalize () ~dbg ~id = diff --git a/ocaml/xapi/storage_smapiv1.ml b/ocaml/xapi/storage_smapiv1.ml index 0995edc35c4..01458a449ef 100644 --- a/ocaml/xapi/storage_smapiv1.ml +++ b/ocaml/xapi/storage_smapiv1.ml @@ -126,6 +126,7 @@ module SMAPIv1 : Server_impl = struct ; configuration= [] ; required_cluster_stack= [] ; smapi_version= SMAPIv1 + ; supported_image_formats= [] } let diagnostics _context ~dbg:_ = @@ -1129,7 +1130,8 @@ module SMAPIv1 : Server_impl = struct let copy _context ~dbg:_ ~sr:_ ~vdi:_ ~vm:_ ~url:_ ~dest:_ ~verify_dest:_ = assert false - let mirror _context ~dbg:_ ~sr:_ ~vdi:_ ~vm:_ ~dest:_ = assert false + let mirror _context ~dbg:_ ~sr:_ ~vdi:_ ~image_format:_ ~vm:_ ~dest:_ = + assert false let stat _context ~dbg:_ ~sr:_ ~vdi:_ ~vm:_ ~key:_ = assert false @@ -1140,20 +1142,21 @@ module SMAPIv1 : Server_impl = struct module MIRROR = struct type context = unit - let send_start _ctx ~dbg:_ ~task_id:_ ~dp:_ ~sr:_ ~vdi:_ ~mirror_vm:_ - ~mirror_id:_ ~local_vdi:_ ~copy_vm:_ ~live_vm:_ ~url:_ + let send_start _ctx ~dbg:_ ~task_id:_ ~dp:_ ~sr:_ ~vdi:_ ~image_format:_ + ~mirror_vm:_ ~mirror_id:_ ~local_vdi:_ ~copy_vm:_ ~live_vm:_ ~url:_ ~remote_mirror:_ ~dest_sr:_ ~verify_dest:_ = assert false - let receive_start _context ~dbg:_ ~sr:_ ~vdi_info:_ ~id:_ ~similar:_ = + let receive_start _context ~dbg:_ ~sr:_ ~vdi_info:_ ~image_format:_ ~id:_ + ~similar:_ = assert false - let receive_start2 _context ~dbg:_ ~sr:_ ~vdi_info:_ ~id:_ ~similar:_ - ~vm:_ = + let receive_start2 _context ~dbg:_ ~sr:_ ~vdi_info:_ ~image_format:_ ~id:_ + ~similar:_ ~vm:_ = assert false - let receive_start3 _context ~dbg:_ ~sr:_ ~vdi_info:_ ~mirror_id:_ - ~similar:_ ~vm:_ ~url:_ ~verify_dest:_ = + let receive_start3 _context ~dbg:_ ~sr:_ ~vdi_info:_ ~image_format:_ + ~mirror_id:_ ~similar:_ ~vm:_ ~url:_ ~verify_dest:_ = assert false let receive_finalize _context ~dbg:_ ~id:_ = assert false diff --git a/ocaml/xapi/storage_smapiv1_migrate.ml b/ocaml/xapi/storage_smapiv1_migrate.ml index c850d61f842..0110c3b98c0 100644 --- a/ocaml/xapi/storage_smapiv1_migrate.ml +++ b/ocaml/xapi/storage_smapiv1_migrate.ml @@ -567,13 +567,15 @@ let mirror_cleanup ~dbg ~sr ~snapshot = module MIRROR : SMAPIv2_MIRROR = struct type context = unit - let send_start _ctx ~dbg ~task_id ~dp ~sr ~vdi ~mirror_vm ~mirror_id - ~local_vdi ~copy_vm ~live_vm ~url ~remote_mirror ~dest_sr ~verify_dest = + let send_start _ctx ~dbg ~task_id ~dp ~sr ~vdi ~image_format ~mirror_vm + ~mirror_id ~local_vdi ~copy_vm ~live_vm ~url ~remote_mirror ~dest_sr + ~verify_dest = D.debug - "%s dbg: %s dp: %s sr: %s vdi:%s mirror_vm:%s mirror_id: %s live_vm: %s \ - url:%s dest_sr:%s verify_dest:%B" - __FUNCTION__ dbg dp (s_of_sr sr) (s_of_vdi vdi) (s_of_vm mirror_vm) - mirror_id (s_of_vm live_vm) url (s_of_sr dest_sr) verify_dest ; + "%s dbg: %s dp: %s sr: %s vdi:%s image_format:%s mirror_vm:%s mirror_id: \ + %s live_vm: %s url:%s dest_sr:%s verify_dest:%B" + __FUNCTION__ dbg dp (s_of_sr sr) (s_of_vdi vdi) image_format + (s_of_vm mirror_vm) mirror_id (s_of_vm live_vm) url (s_of_sr dest_sr) + verify_dest ; let (module Remote) = Storage_migrate_helper.get_remote_backend url verify_dest in @@ -615,7 +617,7 @@ module MIRROR : SMAPIv2_MIRROR = struct (Storage_interface.Vdi.string_of mirror_res.Mirror.mirror_vdi.vdi) ; mirror_cleanup ~dbg ~sr ~snapshot - let receive_start_common ~dbg ~sr ~vdi_info ~id ~similar ~vm + let receive_start_common ~dbg ~sr ~vdi_info ~image_format ~id ~similar ~vm (module SMAPI : SMAPIv2) = let on_fail : (unit -> unit) list ref = ref [] in let vdis = SMAPI.SR.scan dbg sr in @@ -625,6 +627,7 @@ module MIRROR : SMAPIv2_MIRROR = struct try let vdi_info = {vdi_info with sm_config= [("base_mirror", id)]} in let leaf = SMAPI.VDI.create dbg sr vdi_info in + D.debug "GTNDEBUG: What to do with image_format" ; D.info "Created leaf VDI for mirror receive: %s" (string_of_vdi_info leaf) ; on_fail := (fun () -> SMAPI.VDI.destroy dbg sr leaf.vdi) :: !on_fail ; (* dummy VDI is created so that the leaf VDI becomes a differencing disk, @@ -722,29 +725,36 @@ module MIRROR : SMAPIv2_MIRROR = struct !on_fail ; raise e - let receive_start _ctx ~dbg ~sr ~vdi_info ~id ~similar = - D.debug "%s dbg: %s sr: %s vdi: %s id: %s" __FUNCTION__ dbg (s_of_sr sr) + let receive_start _ctx ~dbg ~sr ~vdi_info ~image_format ~id ~similar = + D.debug "%s dbg: %s sr: %s vdi: %s image_format: %s id: %s" __FUNCTION__ dbg + (s_of_sr sr) (string_of_vdi_info vdi_info) - id ; - receive_start_common ~dbg ~sr ~vdi_info ~id ~similar ~vm:(Vm.of_string "0") + image_format id ; + receive_start_common ~dbg ~sr ~vdi_info ~image_format ~id ~similar + ~vm:(Vm.of_string "0") (module Local) - let receive_start2 _ctx ~dbg ~sr ~vdi_info ~id ~similar ~vm = - D.debug "%s dbg: %s sr: %s vdi: %s id: %s" __FUNCTION__ dbg (s_of_sr sr) + let receive_start2 _ctx ~dbg ~sr ~vdi_info ~image_format ~id ~similar ~vm = + D.debug "%s dbg: %s sr: %s vdi: %s image_format: %s id: %s" __FUNCTION__ dbg + (s_of_sr sr) (string_of_vdi_info vdi_info) - id ; - receive_start_common ~dbg ~sr ~vdi_info ~id ~similar ~vm (module Local) + image_format id ; + receive_start_common ~dbg ~sr ~vdi_info ~image_format ~id ~similar ~vm + (module Local) - let receive_start3 _ctx ~dbg ~sr ~vdi_info ~mirror_id ~similar ~vm ~url - ~verify_dest = - D.debug "%s dbg: %s sr: %s vdi: %s id: %s vm: %s url: %s verify_dest: %B" + let receive_start3 _ctx ~dbg ~sr ~vdi_info ~image_format ~mirror_id ~similar + ~vm ~url ~verify_dest = + D.debug + "%s dbg: %s sr: %s vdi: %s image_format: %s id: %s vm: %s url: %s \ + verify_dest: %B" __FUNCTION__ dbg (s_of_sr sr) (string_of_vdi_info vdi_info) - mirror_id (s_of_vm vm) url verify_dest ; + image_format mirror_id (s_of_vm vm) url verify_dest ; let (module Remote) = Storage_migrate_helper.get_remote_backend url verify_dest in - receive_start_common ~dbg ~sr ~vdi_info ~id:mirror_id ~similar ~vm + receive_start_common ~dbg ~sr ~vdi_info ~image_format ~id:mirror_id ~similar + ~vm (module Remote) let receive_finalize _ctx ~dbg ~id = diff --git a/ocaml/xapi/storage_smapiv1_wrapper.ml b/ocaml/xapi/storage_smapiv1_wrapper.ml index 86879780fba..c64a8e09fd5 100644 --- a/ocaml/xapi/storage_smapiv1_wrapper.ml +++ b/ocaml/xapi/storage_smapiv1_wrapper.ml @@ -1142,7 +1142,7 @@ functor (s_of_vdi vdi) url (s_of_sr dest) ; Impl.DATA.copy context ~dbg ~sr ~vdi ~vm ~url ~dest - let mirror _context ~dbg:_ ~sr:_ ~vdi:_ ~vm:_ ~dest:_ = + let mirror _context ~dbg:_ ~sr:_ ~vdi:_ ~image_format:_ ~vm:_ ~dest:_ = Storage_interface.unimplemented __FUNCTION__ let stat _context ~dbg:_ ~sr:_ ~vdi:_ ~vm:_ ~key:_ = @@ -1192,28 +1192,34 @@ functor module MIRROR = struct type context = unit - let send_start _ctx ~dbg:_ ~task_id:_ ~dp:_ ~sr:_ ~vdi:_ ~mirror_vm:_ - ~mirror_id:_ ~local_vdi:_ ~copy_vm:_ ~live_vm:_ ~url:_ + let send_start _ctx ~dbg:_ ~task_id:_ ~dp:_ ~sr:_ ~vdi:_ ~image_format:_ + ~mirror_vm:_ ~mirror_id:_ ~local_vdi:_ ~copy_vm:_ ~live_vm:_ ~url:_ ~remote_mirror:_ ~dest_sr:_ ~verify_dest:_ = Storage_interface.unimplemented __FUNCTION__ - let receive_start context ~dbg ~sr ~vdi_info ~id ~similar = - info "DATA.MIRROR.receive_start dbg:%s sr:%s id:%s similar:[%s]" dbg - (s_of_sr sr) id + let receive_start context ~dbg ~sr ~vdi_info ~image_format ~id ~similar + = + info + "DATA.MIRROR.receive_start dbg:%s sr:%s id:%s image_format:%s \ + similar:[%s]" + dbg (s_of_sr sr) id image_format (String.concat "," similar) ; - Impl.DATA.MIRROR.receive_start context ~dbg ~sr ~vdi_info ~id ~similar + Impl.DATA.MIRROR.receive_start context ~dbg ~sr ~vdi_info ~id + ~image_format ~similar - let receive_start2 context ~dbg ~sr ~vdi_info ~id ~similar ~vm = + let receive_start2 context ~dbg ~sr ~vdi_info ~image_format ~id ~similar + ~vm = info - "DATA.MIRROR.receive_start2 dbg:%s sr:%s id:%s similar:[%s] vm:%s" - dbg (s_of_sr sr) id + "DATA.MIRROR.receive_start2 dbg:%s sr:%s id:%s image_format:%s \ + similar:[%s] vm:%s" + dbg (s_of_sr sr) id image_format (String.concat "," similar) (s_of_vm vm) ; Impl.DATA.MIRROR.receive_start2 context ~dbg ~sr ~vdi_info ~id - ~similar ~vm + ~image_format ~similar ~vm - let receive_start3 _context ~dbg:_ ~sr:_ ~vdi_info:_ ~mirror_id:_ - ~similar:_ ~vm:_ = + let receive_start3 _context ~dbg:_ ~sr:_ ~vdi_info:_ ~image_format:_ + ~mirror_id:_ ~similar:_ ~vm:_ = (* See Storage_smapiv1_migrate.receive_start3 *) Storage_interface.unimplemented __FUNCTION__ diff --git a/ocaml/xapi/storage_smapiv3_migrate.ml b/ocaml/xapi/storage_smapiv3_migrate.ml index 774239c0804..3e28ed65028 100644 --- a/ocaml/xapi/storage_smapiv3_migrate.ml +++ b/ocaml/xapi/storage_smapiv3_migrate.ml @@ -108,14 +108,15 @@ let mirror_wait ~dbg ~sr ~vdi ~vm ~mirror_id mirror_key = module MIRROR : SMAPIv2_MIRROR = struct type context = unit - let send_start _ctx ~dbg ~task_id:_ ~dp ~sr ~vdi ~mirror_vm ~mirror_id - ~local_vdi:_ ~copy_vm:_ ~live_vm ~url ~remote_mirror ~dest_sr ~verify_dest - = + let send_start _ctx ~dbg ~task_id:_ ~dp ~sr ~vdi ~image_format ~mirror_vm + ~mirror_id ~local_vdi:_ ~copy_vm:_ ~live_vm ~url ~remote_mirror ~dest_sr + ~verify_dest = D.debug - "%s dbg: %s dp: %s sr: %s vdi:%s mirror_vm:%s mirror_id: %s live_vm: %s \ - url:%s dest_sr:%s verify_dest:%B" - __FUNCTION__ dbg dp (s_of_sr sr) (s_of_vdi vdi) (s_of_vm mirror_vm) - mirror_id (s_of_vm live_vm) url (s_of_sr dest_sr) verify_dest ; + "%s dbg: %s dp: %s sr: %s vdi:%s image_format: %s mirror_vm:%s \ + mirror_id: %s live_vm: %s url:%s dest_sr:%s verify_dest:%B" + __FUNCTION__ dbg dp (s_of_sr sr) (s_of_vdi vdi) image_format + (s_of_vm mirror_vm) mirror_id (s_of_vm live_vm) url (s_of_sr dest_sr) + verify_dest ; ignore (Local.VDI.attach3 dbg dp sr vdi (Vm.of_string "0") true) ; (* TODO we are not activating the VDI here because SMAPIv3 does not support activating the VDI again on dom 0 when it is already activated on the live_vm. @@ -151,7 +152,9 @@ module MIRROR : SMAPIv2_MIRROR = struct D.info "%s nbd_proxy_path: %s nbd_url %s" __FUNCTION__ nbd_proxy_path nbd_uri ; - let mk = Local.DATA.mirror dbg sr vdi live_vm nbd_uri in + let mk = + Local.DATA.mirror dbg sr vdi "GTNDEBUG: image_format" live_vm nbd_uri + in D.debug "%s Updating active local mirrors: id=%s" __FUNCTION__ mirror_id ; let alm = @@ -184,14 +187,16 @@ module MIRROR : SMAPIv2_MIRROR = struct ) ) - let receive_start _ctx ~dbg:_ ~sr:_ ~vdi_info:_ ~id:_ ~similar:_ = + let receive_start _ctx ~dbg:_ ~sr:_ ~vdi_info:_ ~image_format:_ ~id:_ + ~similar:_ = Storage_interface.unimplemented __FUNCTION__ - let receive_start2 _ctx ~dbg:_ ~sr:_ ~vdi_info:_ ~id:_ ~similar:_ ~vm:_ = + let receive_start2 _ctx ~dbg:_ ~sr:_ ~vdi_info:_ ~image_format:_ ~id:_ + ~similar:_ ~vm:_ = Storage_interface.unimplemented __FUNCTION__ - let receive_start3 _ctx ~dbg ~sr ~vdi_info ~mirror_id ~similar:_ ~vm ~url - ~verify_dest = + let receive_start3 _ctx ~dbg ~sr ~vdi_info ~image_format:_ ~mirror_id + ~similar:_ ~vm ~url ~verify_dest = D.debug "%s dbg: %s sr: %s vdi: %s id: %s vm: %s url: %s verify_dest: %B" __FUNCTION__ dbg (s_of_sr sr) (string_of_vdi_info vdi_info) diff --git a/ocaml/xapi/xapi_services.ml b/ocaml/xapi/xapi_services.ml index ca9e3d729ca..7e802972e44 100644 --- a/ocaml/xapi/xapi_services.ml +++ b/ocaml/xapi/xapi_services.ml @@ -256,6 +256,7 @@ let get_handler (req : Http.Request.t) s _ = ; configuration= [] ; required_cluster_stack= [] ; smapi_version= SMAPIv2 + ; supported_image_formats= [] } in respond req (Storage_interface.(rpc_of query_result) q) s diff --git a/ocaml/xapi/xapi_sm.ml b/ocaml/xapi/xapi_sm.ml index 769484ddd7f..c207bb30c60 100644 --- a/ocaml/xapi/xapi_sm.ml +++ b/ocaml/xapi/xapi_sm.ml @@ -49,6 +49,7 @@ let create_from_query_result ~__context q = ~host_pending_features:[] ~configuration:q.configuration ~other_config:[] ~driver_filename:(Sm_exec.cmd_name q.driver) ~required_cluster_stack:q.required_cluster_stack + ~supported_image_formats:q.supported_image_formats ) let find_pending_features existing_features features = @@ -143,7 +144,10 @@ let update_from_query_result ~__context (self, r) q_result = if r.API.sM_configuration <> q_result.configuration then Db.SM.set_configuration ~__context ~self ~value:q_result.configuration ; if r.API.sM_driver_filename <> driver_filename then - Db.SM.set_driver_filename ~__context ~self ~value:driver_filename + Db.SM.set_driver_filename ~__context ~self ~value:driver_filename ; + if r.API.sM_supported_image_formats <> q_result.supported_image_formats then + Db.SM.set_supported_image_formats ~__context ~self + ~value:q_result.supported_image_formats ) let is_v1 x = version_of_string x < [2; 0] diff --git a/ocaml/xapi/xapi_vm_migrate.ml b/ocaml/xapi/xapi_vm_migrate.ml index e5eca21283d..8d14211715a 100644 --- a/ocaml/xapi/xapi_vm_migrate.ml +++ b/ocaml/xapi/xapi_vm_migrate.ml @@ -216,12 +216,76 @@ let assert_sr_support_operations ~__context ~vdi_map ~remote ~local_ops op_supported_on_dest_sr sr remote_ops sm_record remote ) +(** [get_vdi_type vdi_ref vdi_format_map] returns the vdi type found in the + [vdi_format_map] mapping for a given [vdi_ref]. If no type is found None + is returned. *) +let get_vdi_type ~vdi_ref ~vdi_format_map = + List.assoc_opt vdi_ref vdi_format_map + +(** [assert_vdi_format_is_supported] checks that all VDIs in [vdi_map] are included in the list of + supported image format of their corresponding SM. The type of the VDI is found in [vdi_format_map]. + - If no VDI type is specified we just returned so no error is raised. + - If an SM reports an empty list of supported formats, we cannot verify compatibility and no error + is raised. So if the format is not actually supported, the failure will be detected later when + attempting to create the VDI using that image format. *) +let assert_vdi_format_is_supported ~__context ~vdi_map ~vdi_format_map = + List.iter + (fun (vdi_ref, sr_ref) -> + let vdi_uuid = Db.VDI.get_uuid ~__context ~self:vdi_ref in + let sr_uuid = Db.SR.get_uuid ~__context ~self:sr_ref in + match List.assoc_opt vdi_ref vdi_format_map with + | None -> + debug "GTNDEBUG: read vdi %s, sr %s. No type specified for the VDI" + vdi_uuid sr_uuid + | Some ty -> ( + (* To get the supported image format from SM we need the SR type because both have + the same type. *) + let sr_type = Db.SR.get_type ~__context ~self:sr_ref in + let sm_refs = + Db.SM.get_refs_where ~__context + ~expr:(Eq (Field "type", Literal sr_type)) + in + match sm_refs with + | [sm_ref] -> + debug "GTNDEBUG: read vdi %s, sr %s. Type is %s" vdi_uuid sr_uuid + ty ; + let sm_formats = + Db.SM.get_supported_image_formats ~__context ~self:sm_ref + in + if sm_formats <> [] && not (List.mem ty sm_formats) then + raise + Api_errors.( + Server_error + ( vdi_incompatible_type + , [ + Printf.sprintf + "Image format %s is not supported by %s" ty sr_uuid + ] + ) + ) + | _ -> + raise + Api_errors.( + Server_error + ( vdi_incompatible_type + , [ + Printf.sprintf + "Found more than one SM ref (%d) when checking type \ + (%s)of VDI." + (List.length sm_refs) ty + ] + ) + ) + ) + ) + vdi_map + (** Check that none of the VDIs that are mapped to a different SR have CBT or encryption enabled. This function must be called with the complete [vdi_map], which contains all the VDIs of the VM. [check_vdi_map] should be called before this function to verify that this is the case. *) -let assert_can_migrate_vdis ~__context ~vdi_map = +let assert_can_migrate_vdis ~__context ~vdi_map ~vdi_format_map = let assert_cbt_not_enabled vdi = if Db.VDI.get_cbt_enabled ~__context ~self:vdi then raise Api_errors.(Server_error (vdi_cbt_enabled, [Ref.string_of vdi])) @@ -231,6 +295,7 @@ let assert_can_migrate_vdis ~__context ~vdi_map = if List.exists (fun (key, _value) -> key = "key_hash") sm_config then raise Api_errors.(Server_error (vdi_is_encrypted, [Ref.string_of vdi])) in + assert_vdi_format_is_supported ~__context ~vdi_map ~vdi_format_map ; List.iter (fun (vdi, target_sr) -> if target_sr <> Db.VDI.get_SR ~__context ~self:vdi then ( @@ -379,6 +444,7 @@ let pool_migrate ~__context ~vm ~host ~options = info "This is a localhost migration" ; let open Xapi_xenops_queue in let queue_name = queue_of_vm ~__context ~self:vm in + debug "GTNDEBUG: queue_name is %s" queue_name ; let module XenopsAPI = (val make_client queue_name : XENOPS) in let session_id = Ref.string_of (Context.get_session_id __context) in (* If `network` provided in `options`, try to get `xenops_url` on this network *) @@ -722,6 +788,8 @@ let update_snapshot_info ~__context ~dbg ~url ~vdi_map ~snapshots_map type vdi_mirror = { vdi: [`VDI] API.Ref.t ; (* The API reference of the local VDI *) + vdi_format: string + ; (* The image format of the VDI the must be used during its creation *) dp: string ; (* The datapath the VDI will be using if the VM is running *) location: Storage_interface.Vdi.t @@ -818,8 +886,11 @@ let get_vdi_mirror __context vm vdi do_mirror = |> ( ^ ) "MIR" |> Storage_interface.Vm.of_string in + (* vdi_format will be set later in migrate_send *) + let vdi_format = "" in { vdi + ; vdi_format ; dp ; location ; sr @@ -847,8 +918,8 @@ let vdi_filter __context allow_mirror vbd = let vdi = Db.VBD.get_VDI ~__context ~self:vbd in Some (get_vdi_mirror __context vm vdi do_mirror) -let vdi_copy_fun __context dbg vdi_map remote is_intra_pool remote_vdis so_far - total_size copy vconf continuation = +let vdi_copy_fun __context dbg vdi_map vdi_format_map remote is_intra_pool + remote_vdis so_far total_size copy vconf continuation = TaskHelper.exn_if_cancelling ~__context ; let dest_sr_ref = List.assoc vconf.vdi vdi_map in let dest_sr_uuid = @@ -1044,8 +1115,9 @@ let vdi_copy_fun __context dbg vdi_map remote is_intra_pool remote_vdis so_far (* Layering violation!! *) ignore (Storage_access.register_mirror __context id) ; Storage_migrate.start ~dbg ~sr:vconf.sr ~vdi:vconf.location ~dp:new_dp - ~mirror_vm:vconf.mirror_vm ~copy_vm:vconf.copy_vm ~live_vm - ~url:remote.sm_url ~dest:dest_sr ~verify_dest:is_intra_pool + ~image_format:vconf.vdi_format ~mirror_vm:vconf.mirror_vm + ~copy_vm:vconf.copy_vm ~live_vm ~url:remote.sm_url ~dest:dest_sr + ~verify_dest:is_intra_pool in let mapfn x = let total = Int64.to_float total_size in @@ -1208,8 +1280,8 @@ let check_vdi_map ~__context vms_vdis vdi_map = vms_vdis ) -let migrate_send' ~__context ~vm ~dest ~live:_ ~vdi_map ~vif_map ~vgpu_map - ~options = +let migrate_send' ~__context ~vm ~dest ~live:_ ~vdi_map ~vdi_format_map ~vif_map + ~vgpu_map ~options = SMPERF.debug "vm.migrate_send called vm:%s" (Db.VM.get_uuid ~__context ~self:vm) ; let open Xapi_xenops in @@ -1387,10 +1459,21 @@ let migrate_send' ~__context ~vm ~dest ~live:_ ~vdi_map ~vif_map ~vgpu_map extra_vdis in let vdi_map = vdi_map @ extra_vdi_map in - let all_vdis = vms_vdis @ extra_vdis in + let all_vdis = + List.map + (fun vm -> + match get_vdi_type vm.vdi vdi_format_map with + | None -> + vm + | Some vdi_type -> + {vm with vdi_format= vdi_type} + ) + vms_vdis + @ extra_vdis + in (* This is a good time to check our VDIs, because the vdi_map should be complete at this point; it should include all the VDIs in the all_vdis list. *) - assert_can_migrate_vdis ~__context ~vdi_map ; + assert_can_migrate_vdis ~__context ~vdi_map ~vdi_format_map ; let dbg = Context.string_of_task_and_tracing __context in let open Xapi_xenops_queue in let queue_name = queue_of_vm ~__context ~self:vm in @@ -1426,8 +1509,8 @@ let migrate_send' ~__context ~vm ~dest ~live:_ ~vdi_map ~vif_map ~vgpu_map let so_far = ref 0L in let new_vm = with_many - (vdi_copy_fun __context dbg vdi_map remote is_intra_pool remote_vdis - so_far total_size copy + (vdi_copy_fun __context dbg vdi_map vdi_format_map remote is_intra_pool + remote_vdis so_far total_size copy ) all_vdis @@ fun all_map -> @@ -1769,7 +1852,7 @@ let migration_type ~__context ~remote = `cross_pool let assert_can_migrate ~__context ~vm ~dest ~live:_ ~vdi_map ~vif_map ~options - ~vgpu_map = + ~vgpu_map ~vdi_format_map = Xapi_vm_helpers.assert_no_legacy_hardware ~__context ~vm ; assert_licensed_storage_motion ~__context ; let remote = remote_of_dest ~__context dest in @@ -1924,7 +2007,7 @@ let assert_can_migrate ~__context ~vm ~dest ~live:_ ~vdi_map ~vif_map ~options (* Previously there was also a check that none of the VDIs have CBT enabled. This is unnecessary, we only need to check that none of the VDIs that *will be moved* have CBT enabled. *) - assert_can_migrate_vdis ~__context ~vdi_map + assert_can_migrate_vdis ~__context ~vdi_map ~vdi_format_map let assert_can_migrate_sender ~__context ~vm ~dest ~live:_ ~vdi_map:_ ~vif_map:_ ~vgpu_map ~options:_ = @@ -1943,13 +2026,13 @@ let assert_can_migrate_sender ~__context ~vm ~dest ~live:_ ~vdi_map:_ ~vif_map:_ ~vm ~vgpu_map ~host:remote.dest_host ?remote:remote_for_migration_type () let migrate_send ~__context ~vm ~dest ~live ~vdi_map ~vif_map ~options ~vgpu_map - = + ~vdi_format_map = with_migrate (fun () -> - migrate_send' ~__context ~vm ~dest ~live ~vdi_map ~vif_map ~vgpu_map - ~options + migrate_send' ~__context ~vm ~dest ~live ~vdi_map ~vdi_format_map ~vif_map + ~vgpu_map ~options ) -let vdi_pool_migrate ~__context ~vdi ~sr ~options = +let vdi_pool_migrate ~__context ~vdi ~sr ~dest_img_format ~options = if Db.VDI.get_type ~__context ~self:vdi = `cbt_metadata then ( error "VDI.pool_migrate: the specified VDI has type cbt_metadata (at %s)" __LOC__ ; @@ -2035,13 +2118,15 @@ let vdi_pool_migrate ~__context ~vdi ~sr ~options = XenAPI.Host.migrate_receive ~rpc ~session_id ~host:dest_host ~network ~options in - assert_can_migrate ~__context ~vm ~dest ~live:true ~vdi_map ~vif_map:[] - ~vgpu_map:[] ~options:[] ; + assert_can_migrate ~__context ~vm ~dest ~live:true ~vdi_map + ~vdi_format_map:[(vdi, dest_img_format)] + ~vif_map:[] ~vgpu_map:[] ~options:[] ; assert_can_migrate_sender ~__context ~vm ~dest ~live:true ~vdi_map ~vif_map:[] ~vgpu_map:[] ~options:[] ; ignore - (migrate_send ~__context ~vm ~dest ~live:true ~vdi_map ~vif_map:[] - ~vgpu_map:[] ~options:[] + (migrate_send ~__context ~vm ~dest ~live:true ~vdi_map + ~vdi_format_map:[(vdi, dest_img_format)] + ~vif_map:[] ~vgpu_map:[] ~options ) ) ; Db.VBD.get_VDI ~__context ~self:vbd