-
Notifications
You must be signed in to change notification settings - Fork 291
Support qcow2 format in VDI export/import #6396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
It is a work in progress that I proposed in early steps in the development to be sure I'm doing things right. If you prefer I can close it and only create it when it is ready for review no worries. |
We just clone the repo without modifications from https://github.com/mirage/ocaml-qcow.git This breaks the build... This is the first step to enable VDI import/export for qcow2 file. This commit is just the import from Mirage. Next step is to build the package. Signed-off-by: Guillaume <[email protected]>
Use io-page instead of io-page-unix because io-page is 3.0.0 and io-page-unix is 2.3.0 only Signed-off-by: Guillaume <[email protected]>
Since 6.0.1 Cstruct.len function was deprecated and we must use Cstruct.length. This patch fixes this issue Signed-off-by: Guillaume <[email protected]>
In MirageOS, the Unimplemented variant was removed from the Mirage_block.error type in version 2.0.0. This patch removes all places where this varient is used. In some places we replace it with a Failure. Signed-off-by: Guillaume <[email protected]>
In recent versions of cmdliner, Term.pure and Term.info have been replaced with newer, more explicit constructors. This patch uses Term.const as a replacement. Signed-off-by: Guillaume <[email protected]>
remove dune-project from `ocaml/qcow-tool` that was here from the first import. Now we are building qcow-tool with xapi. This patch creates the package in the toplevel dune-project and removes uneeded build stuff from the original repository. To be able to build qcow-tool we added the following packages to xs-opam: - asetmap - ezjsonm - mirage-block-combinators - mirage-types (deprecated) - mirage-types-lwt (deprecated) - prometheus - unix-type-representations Signed-off-by: Guillaume <[email protected]>
Signed-off-by: Guillaume <[email protected]>
This patch allows to pass "qcow2" as a supported format when calling VDI import/export. Currently we should reach unimplemented qcow tool wrapper if we are using "qcow2"" format. Signed-off-by: Guillaume <[email protected]>
Signed-off-by: Guillaume <[email protected]>
99b3756
to
d77adf5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General comments, given that this is a preview to better understand the practical implementation of the design.
if format = Qcow then | ||
Qcow_tool_wrapper.send | ||
(Qcow_tool_wrapper.update_task_progress __context) | ||
s path size | ||
else | ||
Vhd_tool_wrapper.send ?relative_to:base_path | ||
(Vhd_tool_wrapper.update_task_progress __context) | ||
"none" | ||
(Importexport.Format.to_string format) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better to use a match
statement here (like the one below). In case more variants are added in the future, if
would not raise an error/warning, but an explicit match
would
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes if a new format is added it will fall through the else. I see the point of catching new format. I will do that way.
(* | ||
* Copyright (C) 2025 Vates. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU Lesser General Public License as published | ||
* by the Free Software Foundation; version 2.1 only. with the special | ||
* exception on linking described in file LICENSE. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Lesser General Public License for more details. | ||
*) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be easier to review (and revert in case of errors) if you introduced the (unused) qcow_tool_wrapper in a separate commit, and only then started using it import_raw_vdi etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate commit not separate PR right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
ocaml/xapi/import_raw_vdi.ml
Outdated
let prezeroed = | ||
not | ||
(Sm_fs_ops.must_write_zeroes_into_new_vdi ~__context vdi) | ||
in | ||
debug "GTNDEBUG: we are receiving Raw, Vhd or Qcow file" ; | ||
Sm_fs_ops.with_block_attached_device __context rpc | ||
session_id vdi `RW (fun path -> | ||
if chunked then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be calls to (some, currently undefined) Qcow_tool_wrapper.receive
here? With Qcow
as a separate case in the match statement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes exactly. In fact I did that so I was able to compile but a better way is to report an error that it is not implemented or an empty Qcow_tool_wrapper.receive. But yes the calls will be to Qcow_tool_wrapper.receive.
(** [find_backend_device path] returns [Some path'] where [path'] is the backend path in | ||
the driver domain corresponding to the frontend device [path] in this domain. *) | ||
let find_backend_device path = | ||
try | ||
let open Ezxenstore_core.Xenstore in | ||
(* If we're looking at a xen frontend device, see if the backend | ||
is in the same domain. If so check if it looks like a .vhd *) | ||
let rdev = (Unix.stat path).Unix.st_rdev in | ||
let major = rdev / 256 and minor = rdev mod 256 in | ||
let link = | ||
Unix.readlink (Printf.sprintf "/sys/dev/block/%d:%d/device" major minor) | ||
in | ||
match List.rev (String.split '/' link) with | ||
| id :: "xen" :: "devices" :: _ | ||
when Astring.String.is_prefix ~affix:"vbd-" id -> | ||
let id = int_of_string (String.sub id 4 (String.length id - 4)) in | ||
with_xs (fun xs -> | ||
let self = xs.Xs.read "domid" in | ||
let backend = | ||
xs.Xs.read (Printf.sprintf "device/vbd/%d/backend" id) | ||
in | ||
let params = xs.Xs.read (Printf.sprintf "%s/params" backend) in | ||
match String.split '/' backend with | ||
| "local" :: "domain" :: bedomid :: _ -> | ||
if not (self = bedomid) then | ||
Helpers.internal_error | ||
"find_backend_device: Got domid %s but expected %s" bedomid | ||
self ; | ||
Some params | ||
| _ -> | ||
raise Not_found | ||
) | ||
| _ -> | ||
raise Not_found | ||
with _ -> None | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an identical function also in ocaml/vhd-tool/cli/sparse_dd.ml
. It might be worth putting this into some library accessible to all users (Xapi_stdext
? I'm not sure what the best place for it would be) and replacing all the usages with the single one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably in xcp-idl somewhere. I don't think there's a good place for this currently. It might be worth creating a library package on top of ezxenstore that encapsulates common patterns when interacting with xenstore. Maybe a sublibrary of ezxenstore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree, I saw some common patterns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the plans for the QCOW library code?
We could keep it maintained in the mirage org (I already maintain some mirage repos).
ocaml/qcow-tool/lib/qcow_recycler.ml
Outdated
| Error `Disconnected -> Lwt.return (Error `Disconnected) | ||
| Error `Is_read_only -> Lwt.return (Error `Is_read_only) | ||
| Error e -> Format.kasprintf Lwt.fail_with "Unknown error: %a" B.pp_write_error e | ||
| Error _ -> Format.kasprintf Lwt.fail_with "Unknown error in qcow_recylcer.ml" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather keep printing the error here, otherwise you might have a bad time debugging the cause
@@ -173,7 +173,7 @@ DUNE_IU_PACKAGES3=-j $(JOBS) --destdir=$(DESTDIR) --prefix=$(OPTDIR) --libdir=$( | |||
install-dune3: | |||
dune install $(DUNE_IU_PACKAGES3) | |||
|
|||
DUNE_IU_PACKAGES4=-j $(JOBS) --destdir=$(DESTDIR) --prefix=$(PREFIX) --libdir=$(LIBDIR) --libexecdir=/usr/libexec --mandir=$(MANDIR) vhd-tool forkexec | |||
DUNE_IU_PACKAGES4=-j $(JOBS) --destdir=$(DESTDIR) --prefix=$(PREFIX) --libdir=$(LIBDIR) --libexecdir=/usr/libexec --mandir=$(MANDIR) vhd-tool qcow-tool forkexec |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any particular reason you want to package it here? If it's going to be used as a library there's no need for this. For using the binaries in hosts, they can be generated as part of xapi-tools
(so a change in the dune file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No particular reason. I just follow what has been done (anyway as I think I understood how it was done with vhd-tool). And also as it looks like it was not maintained anymore so I did that. But yes I can also update the mirage package to compile and use it.
ocaml/qcow-tool/lib_test/dune
Outdated
@@ -1,6 +0,0 @@ | |||
(executables |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are the tests being removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that I have an issue when building with some missing opam package (not 100% sure) so I just removed them to compile. But clearly my idea was to reintroduce them later in the process ;)
* GNU Lesser General Public License for more details. | ||
*) | ||
|
||
open Xapi_stdext_std.Xstringext |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid this library if possible, instead use Astring.String, or the standard library (String.split_on_char)
Also avoid open, they can be quite evil. Instead use
module Example = This.Is.Some.Example
Christian maintains a useful style guide here: https://github.com/lindig/ocaml-style?tab=readme-ov-file#avoid-opening-modules-globally
let open
s are much better because their scope is contained and are obvious if the function is not too long.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I 100% agree with let open
. I copied the open from another package I guess but I will apply the your suggestion for sure.
(** [find_backend_device path] returns [Some path'] where [path'] is the backend path in | ||
the driver domain corresponding to the frontend device [path] in this domain. *) | ||
let find_backend_device path = | ||
try | ||
let open Ezxenstore_core.Xenstore in | ||
(* If we're looking at a xen frontend device, see if the backend | ||
is in the same domain. If so check if it looks like a .vhd *) | ||
let rdev = (Unix.stat path).Unix.st_rdev in | ||
let major = rdev / 256 and minor = rdev mod 256 in | ||
let link = | ||
Unix.readlink (Printf.sprintf "/sys/dev/block/%d:%d/device" major minor) | ||
in | ||
match List.rev (String.split '/' link) with | ||
| id :: "xen" :: "devices" :: _ | ||
when Astring.String.is_prefix ~affix:"vbd-" id -> | ||
let id = int_of_string (String.sub id 4 (String.length id - 4)) in | ||
with_xs (fun xs -> | ||
let self = xs.Xs.read "domid" in | ||
let backend = | ||
xs.Xs.read (Printf.sprintf "device/vbd/%d/backend" id) | ||
in | ||
let params = xs.Xs.read (Printf.sprintf "%s/params" backend) in | ||
match String.split '/' backend with | ||
| "local" :: "domain" :: bedomid :: _ -> | ||
if not (self = bedomid) then | ||
Helpers.internal_error | ||
"find_backend_device: Got domid %s but expected %s" bedomid | ||
self ; | ||
Some params | ||
| _ -> | ||
raise Not_found | ||
) | ||
| _ -> | ||
raise Not_found | ||
with _ -> None | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably in xcp-idl somewhere. I don't think there's a good place for this currently. It might be worth creating a library package on top of ezxenstore that encapsulates common patterns when interacting with xenstore. Maybe a sublibrary of ezxenstore.
My idea was to do as was done with |
I like the idea of importing the code at least for now such that it is easy to work on. We most likely want at least to make It fit into our build environment. |
The PR implements the support of QCow2 for the import/export of the VDI as described in this proposal.
It is a work in progress and several steps are required:
- [x] Import the Opam package into XAPI
- [x] Add the package in XAPI RPMs
- [x] Adding path into the XAPI to manage the qcow2 type when using vdi import/export
- [ ] Adding streaming of data in qcow tool