This commit adds a new -o kubevirt mode. You can specify where to place the disks and metadata (guest.yaml) file using -os. Also allocation mode (-oa) and disk format (-of) may be set. For example: $ virt-v2v -i disk guest.img -o kubevirt -os /var/tmp will generate /var/tmp/guest.yaml and /var/tmp/guest-sda This is not finalized since undoubtedly the way the disks are handled will have to be changed in future. --- docs/virt-v2v.pod | 18 +++++ output/Makefile.am | 4 + output/create_kubevirt_yaml.ml | 128 ++++++++++++++++++++++++++++++++ output/create_kubevirt_yaml.mli | 27 +++++++ output/output_kubevirt.ml | 96 ++++++++++++++++++++++++ output/output_kubevirt.mli | 21 ++++++ v2v/v2v.ml | 5 +- 7 files changed, 298 insertions(+), 1 deletion(-) diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod index d627734b0d..7041a0d69d 100644 --- a/docs/virt-v2v.pod +++ b/docs/virt-v2v.pod @@ -429,6 +429,24 @@ instead. Set the output method to OpenStack Glance. In this mode the converted guest is uploaded to Glance. See L<virt-v2v-output-openstack(1)>. +=item B<-o> B<kubevirt> + +Set the output method to I<kubevirt>. + +In this mode, the converted guest is written to a local directory +specified by I<-os /dir> (the directory must exist). The converted +guest’s disks are written to: + + /dir/name-sda + /dir/name-sdb + [etc] + +and guest metadata is created in the associated YAML file: + + /dir/name.yaml + +where C<name> is the guest name. + =item B<-o> B<libvirt> Set the output method to I<libvirt>. This is the default. diff --git a/output/Makefile.am b/output/Makefile.am index dd488549db..7a13a99217 100644 --- a/output/Makefile.am +++ b/output/Makefile.am @@ -44,10 +44,12 @@ EXTRA_DIST = \ SOURCES_MLI = \ changeuid.mli \ create_libvirt_xml.mli \ + create_kubevirt_yaml.mli \ openstack_image_properties.mli \ output.mli \ output_disk.mli \ output_glance.mli \ + output_kubevirt.mli \ output_libvirt.mli \ output_null.mli \ output_openstack.mli \ @@ -69,6 +71,7 @@ SOURCES_ML = \ changeuid.ml \ python_script.ml \ create_libvirt_xml.ml \ + create_kubevirt_yaml.ml \ qemuopts.ml \ openstack_image_properties.ml \ output_rhv_upload_cancel_source.ml \ @@ -81,6 +84,7 @@ SOURCES_ML = \ output.ml \ output_disk.ml \ output_glance.ml \ + output_kubevirt.ml \ output_libvirt.ml \ output_null.ml \ output_openstack.ml \ diff --git a/output/create_kubevirt_yaml.ml b/output/create_kubevirt_yaml.ml new file mode 100644 index 0000000000..205e9be38a --- /dev/null +++ b/output/create_kubevirt_yaml.ml @@ -0,0 +1,128 @@ +(* virt-v2v + * Copyright (C) 2009-2022 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +open Printf + +open Std_utils +open Tools_utils +open Common_gettext.Gettext + +open Types +open Utils +open YAML + +let create_kubevirt_yaml source inspect + { guestcaps; target_buses; target_firmware; target_nics } + outdisk_name output_format output_name = + (* The body of the YAML contains various sections attached to + * a tree. We fill in these sections first. + *) + let metadata = ref [] in + let devices = ref [] in + let disks = ref [] in + let resources = ref [] in + let volumes = ref [] in + + (* The guest name. *) + List.push_back metadata ("name", String output_name); + + (* The one Windows example I have includes this clock section, and + * the other non-Windows examples do not. I'm not certain this + * is correct. XXX + *) + if inspect.i_type = "windows" then ( + List.push_back resources ( + "clock", Assoc [ + "timer", Assoc [ + "hpet", Assoc [ "present", Bool false ]; + "hyperv", List []; + "pit", Assoc [ "tickPolicy", String "delay" ]; + "rtc", Assoc [ "tickPolicy", String "catchup" ]; + ]; + "utc", List [] + ] + ) + ); + + (* XXX genid *) + + (* Memory. *) + let memory_str = sprintf "%LdMi" (source.s_memory /^ 1024_L /^ 1024_L) in + List.push_back resources ("requests", Assoc ["memory", String memory_str]); + + (* # vCPUs. XXX vendor, model, topology *) + List.push_back resources ("cpu", Assoc ["cores", Int source.s_vcpu]); + + (* Machine features. *) + let features = List.map (fun name -> name, List []) source.s_features in + List.push_back resources ("features", Assoc features); + + (* XXX firmware, display, sound *) + + (* XXX guestcaps: rng, balloon, vsock, virtio 1.0 *) + + (* We're using local ("host") disks here which is not realistic. *) + Array.iter ( + function + | BusSlotEmpty -> + (* XXX How to place devices on the bus? *) () + | BusSlotDisk d -> + let disk_id = sprintf "disk-%d" d.s_disk_id in + let disk = Assoc [ + "disk", Assoc ["bus", String "virtio"]; + "name", String disk_id + ] in + List.push_back disks disk; + let vol = Assoc [ + "hostDisk", Assoc [ + "path", String (outdisk_name d.s_disk_id); + "type", String "Disk"; + ]; + "name", String disk_id + ] in + List.push_back volumes vol + | BusSlotRemovable _ -> + (* XXX removables *) () + ) target_buses.target_virtio_blk_bus; + + (* XXX ide, scsi, floppy, NICs *) + + (* Create the final document. *) + if !disks <> [] then + List.push_back devices ("disks", List !disks); + let domain = ref [] in + if !devices <> [] then + List.push_back domain ("devices", Assoc !devices); + List.push_back domain ("resources", Assoc !resources); + + let spec = ref [] in + List.push_back spec ("domain", Assoc !domain); + if !volumes <> [] then + List.push_back spec ("volumes", List !volumes); + List.push_back spec ("terminationGracePeriodSeconds", Int 0); + + let body = [ + "#", String generated_by; + "apiVersion", String "kubevirt.io/v1"; + "kind", String "VirtualMachineInstance"; + "metadata", Assoc !metadata; + "spec", Assoc !spec; + ] in + + (* Return the YAML document. *) + Doc (Assoc body) diff --git a/output/create_kubevirt_yaml.mli b/output/create_kubevirt_yaml.mli new file mode 100644 index 0000000000..2d7eec1cc5 --- /dev/null +++ b/output/create_kubevirt_yaml.mli @@ -0,0 +1,27 @@ +(* virt-v2v + * Copyright (C) 2009-2020 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +(** Create kubevirt YAML for -o kubevirt *) + +val create_kubevirt_yaml : Types.source -> + Types.inspect -> Types.target_meta -> + (int -> string) -> string -> string -> + YAML.doc +(** [create_kubevirt_yaml source inspect target_meta + target_features outdisk_map output_format output_name] + creates the Kubevirt machine description YAML document. *) diff --git a/output/output_kubevirt.ml b/output/output_kubevirt.ml new file mode 100644 index 0000000000..63ee8197c0 --- /dev/null +++ b/output/output_kubevirt.ml @@ -0,0 +1,96 @@ +(* virt-v2v + * Copyright (C) 2009-2022 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +open Printf +open Unix + +open Std_utils +open Tools_utils +open Common_gettext.Gettext + +open Types +open Utils + +open Output +open Create_kubevirt_yaml + +module Kubevirt = struct + type poptions = output_allocation * string * string * string + + type t = unit + + let to_string options = + "-o kubevirt" ^ + match options.output_storage with + | Some os -> " -os " ^ os + | None -> "" + + let query_output_options () = + printf (f_"No output options can be used in this mode.\n") + + let parse_options options source = + if options.output_options <> [] then + error (f_"no -oo (output options) are allowed here"); + if options.output_password <> None then + error_option_cannot_be_used_in_output_mode "local" "-op"; + + (* -os must be set to a directory. *) + let output_storage = + match options.output_storage with + | None -> + error (f_"-o kubevirt: output directory was not specified, use '-os /dir'") + | Some d when not (is_directory d) -> + error (f_"-os %s: output directory does not exist or is not a directory") d + | Some d -> d in + + let output_name = Option.default source.s_name options.output_name in + + options.output_alloc, options.output_format, output_name, output_storage + + let setup dir options source = + let disks = get_disks dir in + let output_alloc, output_format, output_name, output_storage = options in + + List.iter ( + fun (i, size) -> + let socket = sprintf "%s/out%d" dir i in + On_exit.unlink socket; + + (* Create the actual output disk. *) + let outdisk = disk_path output_storage output_name i in + output_to_local_file output_alloc output_format outdisk size socket + ) disks + + let finalize dir options () source inspect target_meta = + let output_alloc, output_format, output_name, output_storage = options in + + let doc = create_kubevirt_yaml source inspect target_meta + (disk_path output_storage output_name) + output_format output_name in + + let file = output_storage // output_name ^ ".yaml" in + with_open_out file (fun chan -> YAML.doc_to_chan chan doc); + + if verbose () then ( + eprintf "resulting kubevirt YAML:\n"; + YAML.doc_to_chan Stdlib.stderr doc; + eprintf "\n%!"; + ) + + let request_size = None +end diff --git a/output/output_kubevirt.mli b/output/output_kubevirt.mli new file mode 100644 index 0000000000..a34aa33a5b --- /dev/null +++ b/output/output_kubevirt.mli @@ -0,0 +1,21 @@ +(* virt-v2v + * Copyright (C) 2009-2022 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +(** [-o kubevirt] output mode. *) + +module Kubevirt : Output.OUTPUT diff --git a/v2v/v2v.ml b/v2v/v2v.ml index 6df82cfce9..fcf5e2d4d0 100644 --- a/v2v/v2v.ml +++ b/v2v/v2v.ml @@ -193,6 +193,7 @@ let rec main () = error (f_"%s option used more than once on the command line") "-o"; match mode with | "glance" -> output_mode := `Glance + | "kubevirt" -> output_mode := `Kubevirt | "libvirt" -> output_mode := `Libvirt | "disk" | "local" -> output_mode := `Disk | "null" -> output_mode := `Null @@ -249,7 +250,7 @@ let rec main () = s_"Map network ‘in’ to ‘out’"; [ L"no-trim" ], Getopt.String ("-", no_trim_warning), s_"Ignored for backwards compatibility"; - [ S 'o' ], Getopt.String ("glance|libvirt|local|null|openstack|qemu|rhv|rhv-upload|vdsm", set_output_mode), + [ S 'o' ], Getopt.String ("glance|kubevirt|libvirt|local|null|openstack|qemu|rhv|rhv-upload|vdsm", set_output_mode), s_"Set output mode (default: libvirt)"; [ M"oa" ], Getopt.String ("sparse|preallocated", set_output_alloc), s_"Set output allocation mode"; @@ -389,6 +390,7 @@ read the man page virt-v2v(1). pr "input:ova\n"; pr "input:vmx\n"; pr "output:glance\n"; + pr "output:kubevirt\n"; pr "output:libvirt\n"; pr "output:local\n"; pr "output:null\n"; @@ -482,6 +484,7 @@ read the man page virt-v2v(1). | `Null -> (module Output_null.Null) | `QEmu -> (module Output_qemu.QEMU) | `Glance -> (module Output_glance.Glance) + | `Kubevirt -> (module Output_kubevirt.Kubevirt) | `Openstack -> (module Output_openstack.Openstack) | `RHV_Upload -> (module Output_rhv_upload.RHVUpload) | `RHV -> (module Output_rhv.RHV) -- 2.35.1