From c0f7a321feb08727609a160ac0c0f2c0adea68f2 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 8 Jul 2024 09:56:54 +0100 Subject: [PATCH] RHEL: Remove -o rhv, -o rhv-upload and -o vdsm modes Fixes: https://issues.redhat.com/browse/RHEL-36712 --- docs/Makefile.am | 14 - docs/virt-v2v-output-rhv.pod | 232 -------- docs/virt-v2v.pod | 208 +------ output/Makefile.am | 54 +- output/output_rhv.ml | 317 ----------- output/output_rhv.mli | 21 - output/output_rhv_upload.ml | 520 ----------------- output/output_rhv_upload.mli | 21 - output/output_rhv_upload_cancel_source.mli | 19 - output/output_rhv_upload_createvm_source.mli | 19 - output/output_rhv_upload_finalize_source.mli | 19 - output/output_rhv_upload_plugin_source.mli | 19 - output/output_rhv_upload_precheck_source.mli | 19 - output/output_rhv_upload_transfer_source.mli | 19 - output/output_rhv_upload_vmcheck_source.mli | 19 - output/output_vdsm.ml | 237 -------- output/output_vdsm.mli | 21 - output/rhv-upload-cancel.py | 96 ---- output/rhv-upload-createvm.py | 137 ----- output/rhv-upload-finalize.py | 174 ------ output/rhv-upload-plugin.py | 525 ------------------ output/rhv-upload-precheck.py | 135 ----- output/rhv-upload-transfer.py | 298 ---------- output/rhv-upload-vmcheck.py | 72 --- tests/Makefile.am | 15 - tests/test-v2v-o-rhv-upload-module/imageio.py | 71 --- .../ovirtsdk4/__init__.py | 150 ----- .../ovirtsdk4/types.py | 184 ------ tests/test-v2v-o-rhv-upload-oo-query.sh | 41 -- tests/test-v2v-o-rhv-upload.sh | 74 --- tests/test-v2v-o-rhv.ovf.expected | 113 ---- tests/test-v2v-o-rhv.sh | 87 --- tests/test-v2v-o-vdsm-oo-query.sh | 41 -- tests/test-v2v-o-vdsm-options.ovf.expected | 113 ---- tests/test-v2v-o-vdsm-options.sh | 96 ---- v2v/v2v.ml | 31 +- 36 files changed, 5 insertions(+), 4226 deletions(-) delete mode 100644 docs/virt-v2v-output-rhv.pod delete mode 100644 output/output_rhv.ml delete mode 100644 output/output_rhv.mli delete mode 100644 output/output_rhv_upload.ml delete mode 100644 output/output_rhv_upload.mli delete mode 100644 output/output_rhv_upload_cancel_source.mli delete mode 100644 output/output_rhv_upload_createvm_source.mli delete mode 100644 output/output_rhv_upload_finalize_source.mli delete mode 100644 output/output_rhv_upload_plugin_source.mli delete mode 100644 output/output_rhv_upload_precheck_source.mli delete mode 100644 output/output_rhv_upload_transfer_source.mli delete mode 100644 output/output_rhv_upload_vmcheck_source.mli delete mode 100644 output/output_vdsm.ml delete mode 100644 output/output_vdsm.mli delete mode 100644 output/rhv-upload-cancel.py delete mode 100644 output/rhv-upload-createvm.py delete mode 100644 output/rhv-upload-finalize.py delete mode 100644 output/rhv-upload-plugin.py delete mode 100644 output/rhv-upload-precheck.py delete mode 100644 output/rhv-upload-transfer.py delete mode 100644 output/rhv-upload-vmcheck.py delete mode 100755 tests/test-v2v-o-rhv-upload-module/imageio.py delete mode 100644 tests/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py delete mode 100644 tests/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py delete mode 100755 tests/test-v2v-o-rhv-upload-oo-query.sh delete mode 100755 tests/test-v2v-o-rhv-upload.sh delete mode 100644 tests/test-v2v-o-rhv.ovf.expected delete mode 100755 tests/test-v2v-o-rhv.sh delete mode 100755 tests/test-v2v-o-vdsm-oo-query.sh delete mode 100644 tests/test-v2v-o-vdsm-options.ovf.expected delete mode 100755 tests/test-v2v-o-vdsm-options.sh diff --git a/docs/Makefile.am b/docs/Makefile.am index 214cfc24..2cbe9397 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -26,7 +26,6 @@ EXTRA_DIST = \ virt-v2v-inspector.pod \ virt-v2v-output-local.pod \ virt-v2v-output-openstack.pod \ - virt-v2v-output-rhv.pod \ virt-v2v-release-notes-1.42.pod \ virt-v2v-release-notes-2.0.pod \ virt-v2v-release-notes-2.2.pod \ @@ -44,7 +43,6 @@ man_MANS = \ virt-v2v-inspector.1 \ virt-v2v-output-local.1 \ virt-v2v-output-openstack.1 \ - virt-v2v-output-rhv.1 \ virt-v2v-release-notes-1.42.1 \ virt-v2v-release-notes-2.0.1 \ virt-v2v-release-notes-2.2.1 \ @@ -59,7 +57,6 @@ noinst_DATA = \ $(top_builddir)/website/virt-v2v-inspector.1.html \ $(top_builddir)/website/virt-v2v-output-local.1.html \ $(top_builddir)/website/virt-v2v-output-openstack.1.html \ - $(top_builddir)/website/virt-v2v-output-rhv.1.html \ $(top_builddir)/website/virt-v2v-release-notes-1.42.1.html \ $(top_builddir)/website/virt-v2v-release-notes-2.0.1.html \ $(top_builddir)/website/virt-v2v-release-notes-2.2.1.html \ @@ -146,17 +143,6 @@ stamp-virt-v2v-output-openstack.pod: virt-v2v-output-openstack.pod $< touch $@ -virt-v2v-output-rhv.1 $(top_builddir)/website/virt-v2v-output-rhv.1.html: stamp-virt-v2v-output-rhv.pod - -stamp-virt-v2v-output-rhv.pod: virt-v2v-output-rhv.pod - $(PODWRAPPER) \ - --man virt-v2v-output-rhv.1 \ - --html $(top_builddir)/website/virt-v2v-output-rhv.1.html \ - --license GPLv2+ \ - --warning safe \ - $< - touch $@ - virt-v2v-release-notes-1.42.1 $(top_builddir)/website/virt-v2v-release-notes-1.42.1.html: stamp-virt-v2v-release-notes-1.42.pod stamp-virt-v2v-release-notes-1.42.pod: virt-v2v-release-notes-1.42.pod diff --git a/docs/virt-v2v-output-rhv.pod b/docs/virt-v2v-output-rhv.pod deleted file mode 100644 index 2ce697f4..00000000 --- a/docs/virt-v2v-output-rhv.pod +++ /dev/null @@ -1,232 +0,0 @@ -=head1 NAME - -virt-v2v-output-rhv - Using virt-v2v to convert guests to oVirt or RHV - -=head1 SYNOPSIS - - virt-v2v [-i* options] -o rhv-upload [-oc ENGINE_URL] -os STORAGE - [-op PASSWORD] [-of raw] - [-oo rhv-cafile=FILE] - [-oo rhv-cluster=CLUSTER] - [-oo rhv-proxy] - [-oo rhv-disk-uuid=UUID ...] - [-oo rhv-verifypeer] - - virt-v2v [-i* options] -o rhv -os [esd:/path|/path] - - virt-v2v [-i* options] -o vdsm - [-oo vdsm-image-uuid=UUID] - [-oo vdsm-vol-uuid=UUID] - [-oo vdsm-vm-uuid=UUID] - [-oo vdsm-ovf-output=DIR] - -=head1 DESCRIPTION - -This page documents how to use L to convert guests to an -oVirt or RHV management instance. There are three output modes that -you can select, but only I<-o rhv-upload> should be used normally, the -other two are deprecated: - -=over 4 - -=item B<-o rhv-upload> B<-os> STORAGE - -Full description: L - -This is the modern method for uploading to oVirt/RHV via the REST API. -It requires oVirt/RHV E 4.2. - -=item B<-o rhv> B<-os> esd:/path - -=item B<-o rhv> B<-os> /path - -Full description: L - -This is the old method for uploading to oVirt/RHV via the -Export Storage Domain (ESD). The ESD can either be accessed -over NFS (using the I<-os esd:/path> form) or if you have -already NFS-mounted it somewhere specify the path to the mountpoint -as I<-os /path>. - -The Export Storage Domain was deprecated in oVirt 4, and so we expect -that this method will stop working at some point in the future. - -=item B<-o vdsm> - -This is the old method used internally by the RHV-M user interface. -It is never intended to be used directly by end users. - -=back - -=head1 OUTPUT TO RHV - -This new method to upload guests to oVirt or RHV directly via the REST -API requires oVirt/RHV E 4.2. - -You need to specify I<-o rhv-upload> as well as the following extra -parameters: - -=over 4 - -=item I<-oc> C - -The URL of the REST API which is usually the server name with -C appended, but might be different if you installed -oVirt Engine on a different path. - -You can optionally add a username and port number to the URL. If the -username is not specified then virt-v2v defaults to using -C which is the typical superuser account for oVirt -instances. - -=item I<-of raw> - -Currently you must use I<-of raw> and you cannot use I<-oa preallocated>. - -These restrictions will be loosened in a future version. - -=item I<-op> F - -A file containing a password to be used when connecting to the oVirt -engine. Note the file should contain the whole password, B, and for security the file should have mode -C<0600> so that others cannot read it. - -=item I<-os> C - -The storage domain. - -=item I<-oo rhv-cafile=>F - -The F file (Certificate Authority), copied from -F on the oVirt engine. - -If I<-oo rhv-verifypeer> is enabled then this option can -be used to control which CA is used to verify the client’s -identity. If this option is not used then the system’s -global trust store is used. - -=item I<-oo rhv-cluster=>C - -Set the RHV Cluster Name. If not given it uses C. - -=item I<-oo rhv-disk-uuid=>C - -This option can used to manually specify UUIDs for the disks when -creating the virtual machine. If not specified, the oVirt engine will -generate random UUIDs for the disks. Please note that: - -=over 4 - -=item * - -you B pass as many I<-oo rhv-disk-uuid=UUID> options as the -amount of disks in the guest - -=item * - -the specified UUIDs must not conflict with the UUIDs of existing disks - -=back - -=item I<-oo rhv-proxy> - -Proxy the upload through oVirt Engine. This is slower than uploading -directly to the oVirt node but may be necessary if you do not have -direct network access to the nodes. - -=item I<-oo rhv-verifypeer> - -Verify the oVirt/RHV server’s identity by checking the server‘s -certificate against the Certificate Authority. - -=back - -=head1 OUTPUT TO EXPORT STORAGE DOMAIN - -This section only applies to the I<-o rhv> output mode. If you use -virt-v2v from the RHV-M user interface, then behind the scenes the -import is managed by VDSM using the I<-o vdsm> output mode (which end -users should not try to use directly). - -You have to specify I<-o rhv> and an I<-os> option that points to the -RHV-M Export Storage Domain. You can either specify the NFS server -and mountpoint, eg. S>, or you can -mount that first and point to the directory where it is mounted, -eg. S>. Be careful not to point to the Data Storage -Domain by accident as that will not work. - -On successful completion virt-v2v will have written the new guest to -the Export Storage Domain, but it will not yet be ready to run. It -must be imported into RHV using the UI before it can be used. - -In RHV E 2.2 this is done from the Storage tab. Select the -export domain the guest was written to. A pane will appear underneath -the storage domain list displaying several tabs, one of which is "VM -Import". The converted guest will be listed here. Select the -appropriate guest an click "Import". See the RHV documentation for -additional details. - -If you export several guests, then you can import them all at the same -time through the UI. - -=head2 Testing RHV conversions - -If you do not have an oVirt or RHV instance to test against, then you -can test conversions by creating a directory structure which looks -enough like a RHV-M Export Storage Domain to trick virt-v2v: - - uuid=`uuidgen` - mkdir /tmp/rhv - mkdir /tmp/rhv/$uuid - mkdir /tmp/rhv/$uuid/images - mkdir /tmp/rhv/$uuid/master - mkdir /tmp/rhv/$uuid/master/vms - touch /tmp/rhv/$uuid/dom_md - virt-v2v [...] -o rhv -os /tmp/rhv - -=head2 Debugging RHV-M import failures - -When you export to the RHV-M Export Storage Domain, and then import -that guest through the RHV-M UI, you may encounter an import failure. -Diagnosing these failures is infuriatingly difficult as the UI -generally hides the true reason for the failure. - -There are several log files of interest: - -=over 4 - -=item F - -In oVirt E 4.1.0, VDSM preserves the virt-v2v log file for -30 days in this directory. - -This directory is found on the host which performed the conversion. -The host can be selected in the import dialog, or can be found under -the C tab in oVirt administration. - -=item F - -As above, this file is present on the host which performed the -conversion. It contains detailed error messages from low-level -operations executed by VDSM, and is useful if the error was not caused -by virt-v2v, but by VDSM. - -=item F - -This log file is stored on the RHV-M server. It contains more detail -for any errors caused by the oVirt GUI. - -=back - -=head1 SEE ALSO - -L. - -=head1 AUTHOR - -Richard W.M. Jones - -=head1 COPYRIGHT - -Copyright (C) 2009-2020 Red Hat Inc. diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod index b94fc8b5..f96fd69f 100644 --- a/docs/virt-v2v.pod +++ b/docs/virt-v2v.pod @@ -13,7 +13,7 @@ virt-v2v - Convert a guest to use KVM Virt-v2v converts a single guest from a foreign hypervisor to run on KVM. It can read Linux and Windows guests running on VMware, Hyper-V and some other hypervisors, and convert them to KVM managed by -libvirt, OpenStack, oVirt, Red Hat Virtualisation (RHV) or several +libvirt, OpenStack or several other targets. It can modify the guest to make it bootable on KVM and install virtio drivers so it will run quickly. @@ -45,8 +45,6 @@ L — Input from VMware. L — Output to local files or local libvirt. -L — Output to oVirt or RHV. - L — Output to OpenStack. L — Release notes for 1.42 release. @@ -74,21 +72,6 @@ disks to F. For more information see L. -=head2 Convert from VMware to RHV/oVirt - -This is the same as the previous example, except you want to send the -guest to a RHV Data Domain using the RHV REST API. Guest network -interface(s) are connected to the target network called C. - - virt-v2v -ic vpx://vcenter.example.com/Datacenter/esxi vmware_guest \ - -o rhv-upload -oc https://ovirt-engine.example.com/ovirt-engine/api \ - -os ovirt-data -op /tmp/ovirt-admin-password -of raw \ - -oo rhv-cafile=/tmp/ca.pem --bridge ovirtmgmt - -In this case the host running virt-v2v acts as a B. - -For more information see L. - =head2 Convert from ESXi hypervisor over SSH to local libvirt You have an ESXi hypervisor called C with SSH access @@ -468,14 +451,6 @@ no metadata is written. Set the output method to OpenStack. See L. -=item B<-o> B - -This is the same as I<-o rhv>. - -=item B<-o> B - -This is the same as I<-o rhv-upload>. - =item B<-o> B Set the output method to I. @@ -484,40 +459,6 @@ This is similar to I<-o local>, except that a shell script is written which you can use to boot the guest in qemu. The converted disks and shell script are written to the directory specified by I<-os>. -=item B<-o> B - -This is the same as I<-o rhv>. - -=item B<-o> B - -Set the output method to I. - -The converted guest is written to a RHV Export Storage Domain. The -I<-os> parameter must also be used to specify the location of the -Export Storage Domain. Note this does not actually import the guest -into RHV. You have to do that manually later using the UI. - -See L. - -=item B<-o> B - -Set the output method to I. - -The converted guest is written directly to a RHV Data Domain. -This is a faster method than I<-o rhv>, but requires oVirt -or RHV E 4.2. - -See L. - -=item B<-o> B - -Set the output method to I. - -This mode is similar to I<-o rhv>, but the full path to the -data domain must be given: -Fdata-center-uuidE/Edata-domain-uuidE>. -This mode is only used when virt-v2v runs under VDSM control. - =item B<-oa> B =item B<-oa> B @@ -580,117 +521,11 @@ For I<-o openstack> (L) only, set optional OpenStack authentication. For example I<-oo os-username=>NAME is equivalent to C. -=item B<-oo rhv-cafile=>F - -For I<-o rhv-upload> (L) only, the F file -(Certificate Authority), copied from F -on the oVirt engine. - -=item B<-oo rhv-cluster=>C - -For I<-o rhv-upload> (L) only, set the RHV Cluster -Name. If not given it uses C. - -=item B<-oo rhv-proxy> - -For I<-o rhv-upload> (L) only, proxy the -upload through oVirt Engine. This is slower than uploading directly -to the oVirt node but may be necessary if you do not have direct -network access to the nodes. - -=item B<-oo rhv-verifypeer> - -For I<-o rhv-upload> (L) only, verify the oVirt/RHV -server’s identity by checking the server‘s certificate against the -Certificate Authority. - =item B<-oo server-id=>C For I<-o openstack> (L) only, set the name of the conversion appliance where virt-v2v is running. -=item B<-oo vdsm-compat=0.10> - -=item B<-oo vdsm-compat=1.1> - -If I<-o vdsm> and the output format is qcow2, then we add the qcow2 -I option to the output file for compatibility with RHEL 6 -(see L). - -If I<-oo vdsm-compat=1.1> is used then modern qcow2 (I) -files are generated instead. - -Currently I<-oo vdsm-compat=0.10> is the default, but this will change -to I<-oo vdsm-compat=1.1> in a future version of virt-v2v (when we can -assume that everyone is using a modern version of qemu). - -B output>. All other output -modes (including I<-o rhv>) generate modern qcow2 I -files, always. - -If this option is available, then C will appear in -the I<--machine-readable> output. - -=item B<-oo vdsm-image-uuid=>UUID - -=item B<-oo vdsm-vol-uuid=>UUID - -=item B<-oo vdsm-vm-uuid=>UUID - -=item B<-oo vdsm-ovf-output=>DIR - -Normally the RHV output mode chooses random UUIDs for the target -guest. However VDSM needs to control the UUIDs and passes these -parameters when virt-v2v runs under VDSM control. The parameters -control: - -=over 4 - -=item * - -the image directory of each guest disk (I<-oo vdsm-image-uuid>) (this -option is passed once for each guest disk) - -=item * - -UUIDs for each guest disk (I<-oo vdsm-vol-uuid>) (this option -is passed once for each guest disk) - -=item * - -the OVF file name (I<-oo vdsm-vm-uuid>). - -=item * - -the OVF output directory (default current directory) (I<-oo vdsm-ovf-output>). - -=back - -The format of UUIDs is: C<12345678-1234-1234-1234-123456789abc> (each -hex digit can be C<0-9> or C), conforming to S. - -These options can only be used with I<-o vdsm>. - -=item B<-oo vdsm-ovf-flavour=>flavour - -This option controls the format of the OVF generated at the end of conversion. -Currently there are two possible flavours: - -=over 4 - -=item rhvexp - -The OVF format used in RHV export storage domain. - -=item ovirt - -The OVF format understood by oVirt REST API. - -=back - -For backward compatibility the default is I, but this may change in -the future. - =item B<-op> file Supply a file containing a password to be used when connecting to the @@ -708,28 +543,8 @@ For I<-o libvirt>, this is a libvirt directory pool For I<-o local> and I<-o qemu>, this is a directory name. The directory must exist. -For I<-o rhv-upload>, this is the name of the destination Storage -Domain. - For I<-o openstack>, this is the optional Cinder volume type. -For I<-o rhv>, this can be an NFS path of the Export Storage Domain -of the form ChostE:EpathE>, eg: - - rhv-storage.example.com:/rhv/export - -The NFS export must be mountable and writable by the user and host -running virt-v2v, since the virt-v2v program has to actually mount it -when it runs. So you probably have to run virt-v2v as C. - -B You can mount the Export Storage Domain yourself, and point -I<-os> to the mountpoint. Note that virt-v2v will still need to write -to this remote directory, so virt-v2v will still need to run as -C. - -You will get an error if virt-v2v is unable to mount/write to the -Export Storage Domain. - =item B<--print-source> Print information about the source guest and stop. This option is @@ -1287,26 +1102,6 @@ require either root or a special user: =over 4 -=item Mounting the Export Storage Domain - -When using I<-o rhv -os server:/esd> virt-v2v has to have sufficient -privileges to NFS mount the Export Storage Domain from C. - -You can avoid needing root here by mounting it yourself before running -virt-v2v, and passing I<-os /mountpoint> instead, but first of all -read the next S
- -=item Writing to the Export Storage Domain as 36:36 - -RHV-M cannot read files and directories from the Export Storage -Domain unless they have UID:GID 36:36. You will see VM import -problems if the UID:GID is not correct. - -When you run virt-v2v I<-o rhv> as root, virt-v2v attempts to create -files and directories with the correct ownership. If you run virt-v2v -as non-root, it will probably still work, but you will need to -manually change ownership after virt-v2v has finished. - =item Writing to libvirt When using I<-o libvirt>, you may need to run virt-v2v as root so that @@ -1413,7 +1208,6 @@ virt-v2v binary. Typical output looks like this: virt-v2v libguestfs-rewrite colours-option - vdsm-compat-option input:disk [...] output:local diff --git a/output/Makefile.am b/output/Makefile.am index 9663acb1..d53a2280 100644 --- a/output/Makefile.am +++ b/output/Makefile.am @@ -17,14 +17,7 @@ include $(top_srcdir)/subdir-rules.mk -BUILT_SOURCES = \ - output_rhv_upload_cancel_source.ml \ - output_rhv_upload_createvm_source.ml \ - output_rhv_upload_finalize_source.ml \ - output_rhv_upload_plugin_source.ml \ - output_rhv_upload_precheck_source.ml \ - output_rhv_upload_transfer_source.ml \ - output_rhv_upload_vmcheck_source.ml +BUILT_SOURCES = EXTRA_DIST = \ $(SOURCES_MLI) \ @@ -32,13 +25,6 @@ EXTRA_DIST = \ $(SOURCES_C) \ $(BUILT_SOURCES) \ embed.sh \ - rhv-upload-cancel.py \ - rhv-upload-createvm.py \ - rhv-upload-finalize.py \ - rhv-upload-plugin.py \ - rhv-upload-precheck.py \ - rhv-upload-transfer.py \ - rhv-upload-vmcheck.py \ test-v2v-python-syntax.sh SOURCES_MLI = \ @@ -54,16 +40,6 @@ SOURCES_MLI = \ output_null.mli \ output_openstack.mli \ output_qemu.mli \ - output_rhv.mli \ - output_rhv_upload.mli \ - output_vdsm.mli \ - output_rhv_upload_cancel_source.mli \ - output_rhv_upload_createvm_source.mli \ - output_rhv_upload_finalize_source.mli \ - output_rhv_upload_plugin_source.mli \ - output_rhv_upload_precheck_source.mli \ - output_rhv_upload_transfer_source.mli \ - output_rhv_upload_vmcheck_source.mli \ python_script.mli \ qemuopts.mli @@ -74,13 +50,6 @@ SOURCES_ML = \ create_kubevirt_yaml.ml \ qemuopts.ml \ openstack_image_properties.ml \ - output_rhv_upload_cancel_source.ml \ - output_rhv_upload_createvm_source.ml \ - output_rhv_upload_finalize_source.ml \ - output_rhv_upload_plugin_source.ml \ - output_rhv_upload_precheck_source.ml \ - output_rhv_upload_transfer_source.ml \ - output_rhv_upload_vmcheck_source.ml \ output.ml \ output_disk.ml \ output_glance.ml \ @@ -88,30 +57,11 @@ SOURCES_ML = \ output_libvirt.ml \ output_null.ml \ output_openstack.ml \ - output_qemu.ml \ - output_rhv.ml \ - output_rhv_upload.ml \ - output_vdsm.ml + output_qemu.ml SOURCES_C = \ qemuopts-c.c -# These files are generated and contain *.py embedded as an OCaml string. -output_rhv_upload_cancel_source.ml: $(srcdir)/rhv-upload-cancel.py - $(srcdir)/embed.sh code $^ $@ -output_rhv_upload_createvm_source.ml: $(srcdir)/rhv-upload-createvm.py - $(srcdir)/embed.sh code $^ $@ -output_rhv_upload_finalize_source.ml: $(srcdir)/rhv-upload-finalize.py - $(srcdir)/embed.sh code $^ $@ -output_rhv_upload_plugin_source.ml: $(srcdir)/rhv-upload-plugin.py - $(srcdir)/embed.sh code $^ $@ -output_rhv_upload_precheck_source.ml: $(srcdir)/rhv-upload-precheck.py - $(srcdir)/embed.sh code $^ $@ -output_rhv_upload_transfer_source.ml: $(srcdir)/rhv-upload-transfer.py - $(srcdir)/embed.sh code $^ $@ -output_rhv_upload_vmcheck_source.ml: $(srcdir)/rhv-upload-vmcheck.py - $(srcdir)/embed.sh code $^ $@ - # We pretend that we're building a C library. automake handles the # compilation of the C sources for us. At the end we take the C # objects and OCaml objects and link them into the OCaml library. diff --git a/output/output_rhv.ml b/output/output_rhv.ml deleted file mode 100644 index 13c2d8dc..00000000 --- a/output/output_rhv.ml +++ /dev/null @@ -1,317 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2021 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 Unix_utils -open Common_gettext.Gettext - -open Types -open Utils - -open Output - -module RHV = struct - type poptions = Types.output_allocation * string * string * string - - type t = string * string * string * string list * string list * int64 list - - let to_string options = "-o rhv" - - 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 "rhv" "-op"; - - (* -os must be set, but at this point we cannot check it. *) - let output_storage = - match options.output_storage with - | None -> error (f_"-o rhv: -os option was not specified") - | Some d -> d in - - let output_name = Option.value ~default:source.s_name options.output_name in - - (options.output_alloc, options.output_format, output_name, output_storage) - - let rec setup dir options source = - error_if_disk_count_gt dir 23; - let disks = get_disks dir in - let output_alloc, output_format, output_name, output_storage = options in - - (* UID:GID required for files and directories when writing to ESD. *) - let uid = 36 and gid = 36 in - - (* Create a UID-switching handle. If we're not root, create a dummy - * one because we cannot switch UIDs. - *) - let running_as_root = geteuid () = 0 in - let changeuid_t = - if running_as_root then - Changeuid.create ~uid ~gid () - else - Changeuid.create () in - - let esd_mp, esd_uuid = - mount_and_check_storage_domain (s_"Export Storage Domain") - output_storage in - debug "RHV: ESD mountpoint: %s\nRHV: ESD UUID: %s" esd_mp esd_uuid; - - (* See if we can write files as UID:GID 36:36. *) - let () = - let testfile = esd_mp // esd_uuid // String.random8 () in - Changeuid.make_file changeuid_t testfile ""; - let stat = stat testfile in - Changeuid.unlink changeuid_t testfile; - let actual_uid = stat.st_uid and actual_gid = stat.st_gid in - debug "RHV: actual UID:GID of new files is %d:%d" actual_uid actual_gid; - if uid <> actual_uid || gid <> actual_gid then ( - if running_as_root then - warning (f_"cannot write files to the NFS server as %d:%d, \ - even though we appear to be running as root. This \ - probably means the NFS client or idmapd is not \ - configured properly.\n\nYou will have to chown \ - the files that virt-v2v creates after the run, \ - otherwise RHV-M will not be able to import the VM.") - uid gid - else - warning (f_"cannot write files to the NFS server as %d:%d. \ - You might want to stop virt-v2v (^C) and rerun it \ - as root.") uid gid - ) in - - (* Create unique UUIDs for everything *) - let vm_uuid = uuidgen () in - (* Generate random image and volume UUIDs for each target disk. *) - let image_uuids = List.map (fun _ -> uuidgen ()) disks in - let vol_uuids = List.map (fun _ -> uuidgen ()) disks in - - (* We need to create the target image director(ies) so there's a place - * for the main program to copy the images to. However if image - * conversion fails for any reason then we delete this directory. - *) - let images_dir = esd_mp // esd_uuid // "images" in - List.iter ( - fun image_uuid -> - let d = images_dir // image_uuid in - Changeuid.mkdir changeuid_t d 0o755 - ) image_uuids; - On_exit.f ( - fun () -> - (* virt-v2v writes v2vdir/done on success only. *) - let success = Sys.file_exists (dir // "done") in - if not success then ( - List.iter ( - fun image_uuid -> - let d = images_dir // image_uuid in - let cmd = sprintf "rm -rf %s" (quote d) in - Changeuid.command changeuid_t cmd - ) image_uuids - ) - ); - - (* The final directory structure should look like this: - * ///images/ - * / # first disk - * /.meta # first disk - * / # second disk - * /.meta # second disk - * / # etc - * /.meta # - *) - - (* Generate the randomly named target files (just the names). - * The main code is what generates the files themselves. - *) - let filenames = - List.map ( - fun (image_uuid, vol_uuid) -> - let filename = images_dir // image_uuid // vol_uuid in - debug "RHV: disk: %s" filename; - filename - ) (List.combine image_uuids vol_uuids) in - - (* Generate the .meta file associated with each volume. *) - let sizes = List.map snd disks in - let metas = - Create_ovf.create_meta_files output_alloc output_format - esd_uuid image_uuids sizes in - List.iter ( - fun (filename, meta) -> - let meta_filename = filename ^ ".meta" in - Changeuid.make_file changeuid_t meta_filename meta - ) (List.combine filenames metas); - - (* Set up the NBD servers. *) - List.iter ( - fun ((i, size), filename) -> - let socket = sprintf "%s/out%d" dir i in - On_exit.unlink socket; - - (* Create the actual output disk. *) - let changeuid f = - Changeuid.func changeuid_t ( - fun () -> - (* Run the command to create the file. *) - f (); - (* Make the file sufficiently writable so that possibly root, or - * root squashed nbdkit will definitely be able to open it. - * An example of how root squashing nonsense makes everyone - * less secure. - *) - chmod filename 0o666 - ) - in - - (* We have to wait for the NBD server to exit rather than just - * killing it, otherwise it races with unmounting. See: - * https://bugzilla.redhat.com/show_bug.cgi?id=1953286#c26 - *) - let on_exit_kill = Output.KillAndWait in - - output_to_local_file ~changeuid ~on_exit_kill - output_alloc output_format filename size socket - ) (List.combine disks filenames); - - (* Save parameters since we need them during finalization. *) - let t = esd_mp, esd_uuid, vm_uuid, image_uuids, vol_uuids, sizes in - t - - and mount_and_check_storage_domain domain_class os = - (* The user can either specify -os nfs:/export, or a local directory - * which is assumed to be the already-mounted NFS export. - *) - match String.split ":/" os with - | mp, "" -> (* Already mounted directory. *) - check_storage_domain domain_class os mp - | server, export -> - let export = "/" ^ export in - - (* Create a mountpoint. Default mode is too restrictive for us - * when we need to write into the directory as 36:36. - *) - let mp = Mkdtemp.temp_dir "v2v." in - chmod mp 0o755; - - (* Try mounting it. *) - let cmd = [ "mount"; sprintf "%s:%s" server export; mp ] in - if run_command cmd <> 0 then - error (f_"mount command failed, see earlier errors.\n\nThis probably \ - means you didn't specify the right %s path [-os %s], or \ - else you need to rerun virt-v2v as root.") domain_class os; - - (* Make sure it is unmounted at exit, as late as possible (prio=9999) *) - On_exit.f ~prio:9999 ( - fun () -> - let cmd = [ "umount"; mp ] in - ignore (run_command cmd); - try rmdir mp with _ -> () - ); - - check_storage_domain domain_class os mp - - and check_storage_domain domain_class os mp = - (* Typical SD mountpoint looks like this: - * $ ls /tmp/mnt - * 39b6af0e-1d64-40c2-97e4-4f094f1919c7 __DIRECT_IO_TEST__ lost+found - * $ ls /tmp/mnt/39b6af0e-1d64-40c2-97e4-4f094f1919c7 - * dom_md images master - * We expect exactly one of those magic UUIDs. - *) - let entries = - try Sys.readdir mp - with Sys_error msg -> - error (f_"could not read the %s specified by the '-os %s' \ - parameter on the command line. Is it really an \ - OVirt or RHV-M %s? The original error is: %s") - domain_class os domain_class msg in - let entries = Array.to_list entries in - let uuids = List.filter ( - fun entry -> - String.length entry = 36 && - entry.[8] = '-' && entry.[13] = '-' && entry.[18] = '-' && - entry.[23] = '-' - ) entries in - let uuid = - match uuids with - | [uuid] -> uuid - | [] -> - error (f_"there are no UUIDs in the %s (%s). Is it really an \ - OVirt or RHV-M %s?") domain_class os domain_class - | _::_ -> - error (f_"there are multiple UUIDs in the %s (%s). This is \ - unexpected, and may be a bug in virt-v2v or OVirt.") - domain_class os in - - (* Check that the domain has been attached to a Data Center by - * checking that the master/vms directory exists. - *) - let () = - let master_vms_dir = mp // uuid // "master" // "vms" in - if not (is_directory master_vms_dir) then - error (f_"%s does not exist or is not a directory.\n\nMost likely \ - cause: Either the %s (%s) has not been attached to any \ - Data Center, or the path %s is not an %s at all.\n\n\ - You have to attach the %s to a Data Center using the \ - RHV-M / OVirt user interface first.\n\nIf you don’t \ - know what the %s mount point should be then you can \ - also find this out through the RHV-M user interface.") - master_vms_dir domain_class os os - domain_class domain_class domain_class in - - (* Looks good, so return the SD mountpoint and UUID. *) - (mp, uuid) - - let finalize dir options t source inspect target_meta = - let output_alloc, output_format, output_name, output_storage = options in - let esd_mp, esd_uuid, vm_uuid, image_uuids, vol_uuids, sizes = t in - - (* UID:GID required for files and directories when writing to ESD. *) - let uid = 36 and gid = 36 in - - (* Create a UID-switching handle. If we're not root, create a dummy - * one because we cannot switch UIDs. - *) - let running_as_root = geteuid () = 0 in - let changeuid_t = - if running_as_root then - Changeuid.create ~uid ~gid () - else - Changeuid.create () in - - (* Create the metadata. *) - let ovf = - Create_ovf.create_ovf source inspect target_meta sizes - output_alloc output_format output_name esd_uuid image_uuids vol_uuids - ~need_actual_sizes:true dir vm_uuid - Create_ovf.RHVExportStorageDomain in - - (* Write it to the metadata file. *) - let dir = esd_mp // esd_uuid // "master" // "vms" // vm_uuid in - Changeuid.mkdir changeuid_t dir 0o755; - let file = dir // vm_uuid ^ ".ovf" in - Changeuid.output changeuid_t file (fun chan -> DOM.doc_to_chan chan ovf) - - let request_size = None -end diff --git a/output/output_rhv.mli b/output/output_rhv.mli deleted file mode 100644 index 08f3f2d0..00000000 --- a/output/output_rhv.mli +++ /dev/null @@ -1,21 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2021 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 rhv] output mode. *) - -module RHV : Output.OUTPUT diff --git a/output/output_rhv_upload.ml b/output/output_rhv_upload.ml deleted file mode 100644 index 63624860..00000000 --- a/output/output_rhv_upload.ml +++ /dev/null @@ -1,520 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2021 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 - -module RHVUpload = struct - type poptions = string * string * string * string * string * - string option * string option * bool * bool * - string list option - - type t = int64 list * string list * string list * - Python_script.script * Python_script.script * - JSON.field list * string option * string option * - string option * string * int list ref - - let to_string options = - "-o rhv-upload" ^ - (match options.output_conn with - | Some oc -> " -oc " ^ oc - | None -> "") ^ - (match options.output_storage with - | Some os -> " -os " ^ os - | None -> "") - - let query_output_options () = - printf (f_"Output options (-oo) which can be used with -o rhv-upload: - - -oo rhv-cafile=CA.PEM Set ‘ca.pem’ certificate bundle filename. - -oo rhv-cluster=CLUSTERNAME Set RHV cluster name. - -oo rhv-proxy Connect via oVirt Engine proxy (default: false). - -oo rhv-verifypeer[=true|false] Verify server identity (default: false). - -You can override the UUIDs of the disks, instead of using autogenerated UUIDs -after their uploads (if you do, you must supply one for each disk): - - -oo rhv-disk-uuid=UUID Disk UUID -") - - let rec parse_options options source = - let output_conn = - match options.output_conn with - | None -> - error (f_"-o rhv-upload: use ‘-oc’ to point to the oVirt \ - or RHV server REST API URL, which is usually \ - https://servername/ovirt-engine/api") - | Some oc -> oc in - (* In theory we could make the password optional in future. *) - let output_password = - match options.output_password with - | None -> - error (f_"-o rhv-upload: output password file was not specified, \ - use ‘-op’ to point to a file which contains the password \ - used to connect to the oVirt or RHV server") - | Some op -> op in - let output_storage = - match options.output_storage with - | None -> - error (f_"-o rhv-upload: output storage was not specified, use ‘-os’"); - | Some os -> os in - - let rhv_cafile = ref None in - let rhv_cluster = ref None in - let rhv_direct = ref true in - let rhv_verifypeer = ref false in - let rhv_disk_uuids = ref None in - - List.iter ( - function - | "rhv-cafile", v -> - if !rhv_cafile <> None then - error (f_"-o rhv-upload: -oo rhv-cafile set more than once"); - rhv_cafile := Some v - | "rhv-cluster", v -> - if !rhv_cluster <> None then - error (f_"-o rhv-upload: -oo rhv-cluster set more than once"); - rhv_cluster := Some v - | "rhv-direct", "" -> rhv_direct := true - | "rhv-direct", v -> rhv_direct := bool_of_string v - | "rhv-proxy", "" -> rhv_direct := false - | "rhv-proxy", v -> rhv_direct := not (bool_of_string v) - | "rhv-verifypeer", "" -> rhv_verifypeer := true - | "rhv-verifypeer", v -> rhv_verifypeer := bool_of_string v - | "rhv-disk-uuid", v -> - if not (is_nonnil_uuid v) then - error (f_"-o rhv-upload: invalid UUID for -oo rhv-disk-uuid"); - rhv_disk_uuids := Some (v :: (Option.value ~default:[] !rhv_disk_uuids)) - | k, _ -> - error (f_"-o rhv-upload: unknown output option ‘-oo %s’") k - ) options.output_options; - - let rhv_cafile = !rhv_cafile in - let rhv_cluster = !rhv_cluster in - let rhv_direct = !rhv_direct in - let rhv_verifypeer = !rhv_verifypeer in - let rhv_disk_uuids = Option.map List.rev !rhv_disk_uuids in - - let output_name = Option.value ~default:source.s_name options.output_name in - - (output_conn, options.output_format, - output_password, output_name, output_storage, - rhv_cafile, rhv_cluster, rhv_direct, - rhv_verifypeer, rhv_disk_uuids) - - and is_nonnil_uuid uuid = - let nil_uuid = "00000000-0000-0000-0000-000000000000" in - let rex_uuid = lazy ( - let hex = "[a-fA-F0-9]" in - let str = sprintf "^%s{8}-%s{4}-%s{4}-%s{4}-%s{12}$" - hex hex hex hex hex in - PCRE.compile str - ) in - if uuid = nil_uuid then false - else PCRE.matches (Lazy.force rex_uuid) uuid - - let rec setup dir options source = - error_if_disk_count_gt dir 23; - let disks = get_disks dir in - let output_conn, output_format, - output_password, output_name, output_storage, - rhv_cafile, rhv_cluster, rhv_direct, - rhv_verifypeer, rhv_disk_uuids = options in - - (* We need nbdkit >= 1.22 for API_VERSION 2 and parallel threading model - * in the python plugin. - *) - let nbdkit_min_version = (1, 22, 0) in - let nbdkit_min_version_string = "1.22.0" in - - (* Check that the 'ovirtsdk4' Python module is available. *) - let error_unless_ovirtsdk4_module_available () = - let res = run_command [ Python_script.python; "-c"; - "import ovirtsdk4" ] in - if res <> 0 then - error (f_"the Python module ‘ovirtsdk4’ could not be loaded, \ - is it installed? See previous messages for problems.") - in - - (* Check that nbdkit is available and new enough. *) - let error_unless_nbdkit_working () = - if not (Nbdkit.is_installed ()) then - error (f_"nbdkit is not installed or not working. It is required \ - to use ‘-o rhv-upload’. See the virt-v2v-output-rhv(1) \ - manual.") - in - - let error_unless_nbdkit_min_version () = - let version = Nbdkit.version () in - if version < nbdkit_min_version then - error (f_"nbdkit is not new enough, you need to upgrade to nbdkit ≥ %s") - nbdkit_min_version_string - in - - (* Check that the python3 plugin is installed and working - * and can load the plugin script. - *) - let error_unless_nbdkit_python_plugin_working plugin_script = - let cmd = sprintf "nbdkit python %s --dump-plugin >/dev/null" - (quote (Python_script.path plugin_script)) in - debug "%s" cmd; - if Sys.command cmd <> 0 then - error (f_"nbdkit python plugin is not installed or not working. \ - It is required if you want to use ‘-o rhv-upload’. - -See also the virt-v2v-output-rhv(1) manual."); - in - - (* Check that nbdkit was compiled with SELinux support (for the - * --selinux-label option). - *) - let error_unless_nbdkit_compiled_with_selinux () = - if have_selinux then ( - let config = Nbdkit.config () in - let selinux = try List.assoc "selinux" config with Not_found -> "no" in - if selinux = "no" then - error (f_"nbdkit was compiled without SELinux support. You will \ - have to recompile nbdkit with libselinux-devel installed, \ - or else set SELinux to Permissive mode while doing the \ - conversion.") - ) - in - - Python_script.error_unless_python_interpreter_found (); - error_unless_ovirtsdk4_module_available (); - error_unless_nbdkit_working (); - error_unless_nbdkit_min_version (); - error_unless_nbdkit_compiled_with_selinux (); - - (* Python code. *) - let precheck_script = - Python_script.create ~name:"rhv-upload-precheck.py" - Output_rhv_upload_precheck_source.code in - let vmcheck_script = - Python_script.create ~name:"rhv-upload-vmcheck.py" - Output_rhv_upload_vmcheck_source.code in - let plugin_script = - Python_script.create ~name:"rhv-upload-plugin.py" - Output_rhv_upload_plugin_source.code in - let transfer_script = - Python_script.create ~name:"rhv-upload-transfer.py" - Output_rhv_upload_transfer_source.code in - let finalize_script = - Python_script.create ~name:"rhv-upload-finalize.py" - Output_rhv_upload_finalize_source.code in - let cancel_script = - Python_script.create ~name:"rhv-upload-cancel.py" - Output_rhv_upload_cancel_source.code in - let createvm_script = - Python_script.create ~name:"rhv-upload-createvm.py" - Output_rhv_upload_createvm_source.code in - - error_unless_nbdkit_python_plugin_working plugin_script; - - (* JSON parameters which are invariant between disks. *) - let json_params = [ - "verbose", JSON.Bool (verbose ()); - - "output_conn", JSON.String output_conn; - "output_password", JSON.String output_password; - "output_storage", JSON.String output_storage; - "rhv_cafile", json_optstring rhv_cafile; - "rhv_cluster", JSON.String (Option.value ~default:"Default" rhv_cluster); - "rhv_direct", JSON.Bool rhv_direct; - - (* The 'Insecure' flag seems to be a number with various possible - * meanings, however we just set it to True/False. - * - * https://github.com/oVirt/ovirt-engine-sdk/blob/19aa7070b80e60a4cfd910448287aecf9083acbe/sdk/lib/ovirtsdk4/__init__.py#L395 - *) - "insecure", JSON.Bool (not rhv_verifypeer); - ] in - - (* nbdkit command line which is invariant between disks. *) - let cmd = Nbdkit.create "python" in - Nbdkit.add_arg cmd "script" (Python_script.path plugin_script); - - (* Match number of parallel coroutines in qemu-img *) - Nbdkit.set_threads cmd 8; - - (* Python code prechecks. *) - let json_params = match rhv_disk_uuids with - | None -> json_params - | Some uuids -> - let ids = List.map (fun uuid -> JSON.String uuid) uuids in - ("rhv_disk_uuids", JSON.List ids) :: json_params - in - let precheck_json = dir // "v2vprecheck.json" in - let fd = Unix.openfile precheck_json [O_WRONLY; O_CREAT; O_TRUNC] 0o600 in - if Python_script.run_command ~stdout_fd:fd - precheck_script json_params [] <> 0 then - error (f_"failed server prechecks, see earlier errors"); - if verbose () then - debug "precheck output before parsing: %s" - (read_whole_file precheck_json); - let json = JSON_parser.json_parser_tree_parse_file precheck_json in - debug "precheck output parsed as: %s" - (JSON.string_of_doc ~fmt:JSON.Indented ["", json]); - let rhv_storagedomain_uuid = - Some (JSON_parser.object_get_string "rhv_storagedomain_uuid" json) in - let rhv_cluster_uuid = - Some (JSON_parser.object_get_string "rhv_cluster_uuid" json) in - let rhv_cluster_cpu_architecture = - Some (JSON_parser.object_get_string "rhv_cluster_cpu_architecture" json) in - - (* If the disk UUIDs were not provided, then generate them. - * This is simpler than letting RHV generate them and trying - * to read them back from RHV. - *) - let disk_uuids = - match rhv_disk_uuids with - | Some uuids -> - let nr_disks = List.length disks in - if List.length uuids <> nr_disks then - error (f_"the number of ‘-oo rhv-disk-uuid’ parameters passed on \ - the command line has to match the number of guest \ - disk images (for this guest: %d)") nr_disks; - uuids - | None -> List.map (fun _ -> uuidgen ()) disks in - - (* This will accumulate the list of transfer IDs from the transfer - * script. - *) - let transfer_ids = ref [] in - - let rhv_cluster_name = - match List.assoc "rhv_cluster" json_params with - | JSON.String s -> s - | _ -> assert false in - - let json_params = - ("output_name", JSON.String output_name) :: json_params in - - (* Check that the VM does not exist. This can't run in #precheck because - * we need to know the name of the virtual machine. - *) - if Python_script.run_command vmcheck_script json_params [] <> 0 then - error (f_"failed vmchecks, see earlier errors"); - - (* Cancel the transfer and delete disks. - * - * This ignores errors since the only time we are doing this is on - * the failure path. - *) - let cancel transfer_ids disk_uuids = - let ids = List.map (fun id -> JSON.String id) transfer_ids in - let json_params = ("transfer_ids", JSON.List ids) :: json_params in - let ids = List.map (fun uuid -> JSON.String uuid) disk_uuids in - let json_params = ("disk_uuids", JSON.List ids) :: json_params in - ignore (Python_script.run_command cancel_script json_params []) - in - - (* Set up an at-exit handler to perform some cleanups. - * - Kill nbdkit PIDs (only before finalization). - * - Delete the orphan disks (only on conversion failure). - *) - let nbdkit_pids = ref [] in - On_exit.f ( - fun () -> - (* Kill the nbdkit PIDs. *) - List.iter ( - fun pid -> - try kill pid Sys.sigterm - with exn -> debug "%s" (Printexc.to_string exn) - ) !nbdkit_pids; - nbdkit_pids := []; - - (* virt-v2v writes v2vdir/done on success only. *) - let success = Sys.file_exists (dir // "done") in - if not success then ( - if disk_uuids <> [] then - cancel !transfer_ids disk_uuids - ) - ); - - (* Create an nbdkit instance for each disk and set the - * target URI to point to the NBD socket. - *) - List.iter ( - fun ((i, size), uuid) -> - let socket = sprintf "%s/out%d" dir i in - On_exit.unlink socket; - - let disk_name = sprintf "%s-%03d" output_name i in - let json_params = - ("disk_name", JSON.String disk_name) :: json_params in - - let disk_format = - match output_format with - | "raw" as fmt -> fmt - | "qcow2" as fmt -> fmt - | _ -> - error (f_"rhv-upload: -of %s: Only output format ‘raw’ or ‘qcow2’ \ - is supported. If the input is in a different format \ - then force one of these output formats by adding \ - either ‘-of raw’ or ‘-of qcow2’ on the command line.") - output_format in - let json_params = - ("disk_format", JSON.String disk_format) :: json_params in - - let json_params = - ("disk_size", JSON.Int size) :: json_params in - - let json_params = - ("disk_uuid", JSON.String uuid) :: json_params in - - (* Write the JSON parameters to a file. *) - let json_param_file = dir // sprintf "out.params%d.json" i in - with_open_out - json_param_file - (fun chan -> output_string chan (JSON.string_of_doc json_params)); - - (* Start the transfer. *) - let transfer_json = dir // sprintf "v2vtransfer%d.json" i in - let fd = - Unix.openfile transfer_json [O_WRONLY; O_CREAT; O_TRUNC] 0o600 in - if Python_script.run_command ~stdout_fd:fd - transfer_script json_params [] <> 0 then - error (f_"failed to start transfer, see earlier errors"); - if verbose () then - debug "transfer output before parsing: %s" - (read_whole_file transfer_json); - let json = JSON_parser.json_parser_tree_parse_file transfer_json in - debug "transfer output parsed as: %s" - (JSON.string_of_doc ~fmt:JSON.Indented ["", json]); - let destination_url = - JSON_parser.object_get_string "destination_url" json in - let transfer_id = - JSON_parser.object_get_string "transfer_id" json in - List.push_back transfer_ids transfer_id; - let is_ovirt_host = - JSON_parser.object_get_bool "is_ovirt_host" json in - - (* Create the nbdkit instance. *) - Nbdkit.add_arg cmd "size" (Int64.to_string size); - Nbdkit.add_arg cmd "url" destination_url; - Option.iter (Nbdkit.add_arg cmd "cafile") rhv_cafile; - if not rhv_verifypeer then - Nbdkit.add_arg cmd "insecure" "true"; - if is_ovirt_host then - Nbdkit.add_arg cmd "is_ovirt_host" "true"; - let _, pid = Nbdkit.run_unix socket cmd in - List.push_front pid nbdkit_pids - ) (List.combine disks disk_uuids); - - (* Stash some data we will need during finalization. *) - let disk_sizes = List.map snd disks in - let t = (disk_sizes : int64 list), disk_uuids, !transfer_ids, - finalize_script, createvm_script, json_params, - rhv_storagedomain_uuid, rhv_cluster_uuid, - rhv_cluster_cpu_architecture, rhv_cluster_name, nbdkit_pids in - t - - and json_optstring = function - | Some s -> JSON.String s - | None -> JSON.Null - - let finalize dir options t source inspect target_meta = - let output_conn, output_format, - output_password, output_name, output_storage, - rhv_cafile, rhv_cluster, rhv_direct, - rhv_verifypeer, rhv_disk_uuids = options in - let disk_sizes, disk_uuids, transfer_ids, - finalize_script, createvm_script, json_params, - rhv_storagedomain_uuid, rhv_cluster_uuid, - rhv_cluster_cpu_architecture, rhv_cluster_name, - nbdkit_pids = t in - - (* Check the cluster CPU arch matches what we derived about the - * guest during conversion. - *) - (match rhv_cluster_cpu_architecture with - | None -> assert false - | Some arch -> - if arch <> target_meta.guestcaps.gcaps_arch then - error (f_"the cluster ‘%s’ does not support the architecture %s \ - but %s") - rhv_cluster_name target_meta.guestcaps.gcaps_arch arch - ); - - (* We must kill all our nbdkit instances before finalizing the - * transfer. See: - * https://listman.redhat.com/archives/libguestfs/2022-February/msg00111.html - * - * We want to fail here if the kill fails because nbdkit - * died already, as that would be unexpected. - *) - let () = - let pids = !nbdkit_pids in - List.iter (fun pid -> kill pid Sys.sigterm) pids; - List.iter (fun pid -> ignore (waitpid [] pid)) pids; - nbdkit_pids := [] (* Don't kill them again in the On_exit handler. *) in - - (* Finalize all the transfers. *) - let json_params = - let ids = List.map (fun id -> JSON.String id) transfer_ids in - let json_params = ("transfer_ids", JSON.List ids) :: json_params in - let ids = List.map (fun uuid -> JSON.String uuid) disk_uuids in - let json_params = ("disk_uuids", JSON.List ids) :: json_params in - json_params in - if Python_script.run_command finalize_script json_params [] <> 0 then - error (f_"failed to finalize the transfers, see earlier errors"); - - (* The storage domain UUID. *) - let sd_uuid = - match rhv_storagedomain_uuid with - | None -> assert false - | Some uuid -> uuid in - - (* The volume and VM UUIDs are made up. *) - let vol_uuids = List.map (fun _ -> uuidgen ()) disk_sizes - and vm_uuid = uuidgen () in - - (* Create the metadata. *) - let ovf = - Create_ovf.create_ovf source inspect target_meta disk_sizes - Sparse output_format output_name - sd_uuid disk_uuids vol_uuids dir vm_uuid OVirt in - let ovf = DOM.doc_to_string ovf in - - let json_params = - match rhv_cluster_uuid with - | None -> assert false - | Some uuid -> ("rhv_cluster_uuid", JSON.String uuid) :: json_params in - - let ovf_file = dir // "vm.ovf" in - with_open_out ovf_file (fun chan -> output_string chan ovf); - if Python_script.run_command createvm_script json_params [ovf_file] <> 0 - then - error (f_"failed to create virtual machine, see earlier errors") - - (* The imageio server has high overhead per request. Using 4 MiB - * request size is 1.8x times faster compared with nbdcopy default - * request size (256k). - *) - let request_size = Some (4*1024*1024) -end diff --git a/output/output_rhv_upload.mli b/output/output_rhv_upload.mli deleted file mode 100644 index 35457596..00000000 --- a/output/output_rhv_upload.mli +++ /dev/null @@ -1,21 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2021 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 rhv-upload] output mode. *) - -module RHVUpload : Output.OUTPUT diff --git a/output/output_rhv_upload_cancel_source.mli b/output/output_rhv_upload_cancel_source.mli deleted file mode 100644 index aa33bc54..00000000 --- a/output/output_rhv_upload_cancel_source.mli +++ /dev/null @@ -1,19 +0,0 @@ -(* virt-v2v - * Copyright (C) 2019 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. - *) - -val code : string diff --git a/output/output_rhv_upload_createvm_source.mli b/output/output_rhv_upload_createvm_source.mli deleted file mode 100644 index c1bafa15..00000000 --- a/output/output_rhv_upload_createvm_source.mli +++ /dev/null @@ -1,19 +0,0 @@ -(* virt-v2v - * Copyright (C) 2018 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. - *) - -val code : string diff --git a/output/output_rhv_upload_finalize_source.mli b/output/output_rhv_upload_finalize_source.mli deleted file mode 100644 index aa33bc54..00000000 --- a/output/output_rhv_upload_finalize_source.mli +++ /dev/null @@ -1,19 +0,0 @@ -(* virt-v2v - * Copyright (C) 2019 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. - *) - -val code : string diff --git a/output/output_rhv_upload_plugin_source.mli b/output/output_rhv_upload_plugin_source.mli deleted file mode 100644 index c1bafa15..00000000 --- a/output/output_rhv_upload_plugin_source.mli +++ /dev/null @@ -1,19 +0,0 @@ -(* virt-v2v - * Copyright (C) 2018 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. - *) - -val code : string diff --git a/output/output_rhv_upload_precheck_source.mli b/output/output_rhv_upload_precheck_source.mli deleted file mode 100644 index aa33bc54..00000000 --- a/output/output_rhv_upload_precheck_source.mli +++ /dev/null @@ -1,19 +0,0 @@ -(* virt-v2v - * Copyright (C) 2019 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. - *) - -val code : string diff --git a/output/output_rhv_upload_transfer_source.mli b/output/output_rhv_upload_transfer_source.mli deleted file mode 100644 index aa33bc54..00000000 --- a/output/output_rhv_upload_transfer_source.mli +++ /dev/null @@ -1,19 +0,0 @@ -(* virt-v2v - * Copyright (C) 2019 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. - *) - -val code : string diff --git a/output/output_rhv_upload_vmcheck_source.mli b/output/output_rhv_upload_vmcheck_source.mli deleted file mode 100644 index c1bafa15..00000000 --- a/output/output_rhv_upload_vmcheck_source.mli +++ /dev/null @@ -1,19 +0,0 @@ -(* virt-v2v - * Copyright (C) 2018 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. - *) - -val code : string diff --git a/output/output_vdsm.ml b/output/output_vdsm.ml deleted file mode 100644 index 3052fb9c..00000000 --- a/output/output_vdsm.ml +++ /dev/null @@ -1,237 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2021 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 - -module VDSM = struct - type poptions = Types.output_allocation * string * string * string * - string list * string list * string * string * - string * Create_ovf.ovf_flavour - - type t = string * string * int64 list - - let to_string options = "-o vdsm" - - let query_output_options () = - let ovf_flavours_str = String.concat "|" Create_ovf.ovf_flavours in - - printf (f_"Output options (-oo) which can be used with -o vdsm: - - -oo vdsm-compat=0.10|1.1 Write qcow2 with compat=0.10|1.1 - (default: 0.10) - -oo vdsm-vm-uuid=UUID VM UUID (required) - -oo vdsm-ovf-output=DIR OVF metadata directory (required) - -oo vdsm-ovf-flavour=%s - Set the type of generated OVF (default: rhvexp) - -For each disk you must supply one of each of these options: - - -oo vdsm-image-uuid=UUID Image directory UUID - -oo vdsm-vol-uuid=UUID Disk volume UUID -") ovf_flavours_str - - let parse_options options source = - if options.output_password <> None then - error_option_cannot_be_used_in_output_mode "vdsm" "-op"; - - let vm_uuid = ref None in - let ovf_output = ref None in (* default "." *) - let compat = ref "0.10" in - let ovf_flavour = ref Create_ovf.RHVExportStorageDomain in - let image_uuids = ref [] in - let vol_uuids = ref [] in - - List.iter ( - function - | "vdsm-compat", "0.10" -> compat := "0.10" - | "vdsm-compat", "1.1" -> compat := "1.1" - | "vdsm-compat", v -> - error (f_"-o vdsm: unknown vdsm-compat level ‘%s’") v - | "vdsm-vm-uuid", v -> - if !vm_uuid <> None then - error (f_"-o vdsm: -oo vdsm-vm-uuid set more than once"); - vm_uuid := Some v; - | "vdsm-ovf-output", v -> - if !ovf_output <> None then - error (f_"-o vdsm: -oo vdsm-ovf-output set more than once"); - ovf_output := Some v; - | "vdsm-ovf-flavour", v -> - ovf_flavour := Create_ovf.ovf_flavour_of_string v - | "vdsm-image-uuid", v -> - List.push_front v image_uuids - | "vdsm-vol-uuid", v -> - List.push_front v vol_uuids - | k, _ -> - error (f_"-o vdsm: unknown output option ‘-oo %s’") k - ) options.output_options; - - let compat = !compat in - let image_uuids = List.rev !image_uuids in - let vol_uuids = List.rev !vol_uuids in - if image_uuids = [] || vol_uuids = [] then - error (f_"-o vdsm: either -oo vdsm-vol-uuid or \ - -oo vdsm-vm-uuid was not specified"); - let vm_uuid = - match !vm_uuid with - | None -> - error (f_"-o vdsm: -oo vdsm-image-uuid was not specified") - | Some uuid -> uuid in - let ovf_output = Option.value ~default:"." !ovf_output in - let ovf_flavour = !ovf_flavour in - - (* -os must be set, but at this point we cannot check it. *) - let output_storage = - match options.output_storage with - | None -> error (f_"-o vdsm: -os option was not specified") - | 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.value ~default:source.s_name options.output_name in - - (options.output_alloc, options.output_format, - output_name, output_storage, - image_uuids, vol_uuids, vm_uuid, ovf_output, - compat, ovf_flavour) - - let setup dir options source = - error_if_disk_count_gt dir 23; - let disks = get_disks dir in - let output_alloc, output_format, - output_name, output_storage, - image_uuids, vol_uuids, vm_uuid, ovf_output, - compat, ovf_flavour = options in - - if List.length image_uuids <> List.length disks || - List.length vol_uuids <> List.length disks then - error (f_"the number of ‘-oo vdsm-image-uuid’ and ‘-oo vdsm-vol-uuid’ \ - parameters passed on the command line has to match the \ - number of guest disk images (for this guest: %d)") - (List.length disks); - - let dd_mp, dd_uuid = - let fields = - String.nsplit "/" output_storage in (* ... "data-center" "UUID" *) - let fields = List.rev fields in (* "UUID" "data-center" ... *) - let fields = List.dropwhile ((=) "") fields in - match fields with - | uuid :: rest when String.length uuid = 36 -> - let mp = String.concat "/" (List.rev rest) in - mp, uuid - | _ -> - error (f_"vdsm: invalid -os parameter \ - does not contain a valid UUID: %s") - output_storage in - - debug "VDSM: DD mountpoint: %s\nVDSM: DD UUID: %s" dd_mp dd_uuid; - - (* Note that VDSM has to create all these directories. *) - let images_dir = dd_mp // dd_uuid // "images" in - List.iter ( - fun image_uuid -> - let d = images_dir // image_uuid in - if not (is_directory d) then - error (f_"image directory (%s) does not exist or is not a directory") - d - ) image_uuids; - - (* Note that VDSM has to create this directory too. *) - if not (is_directory ovf_output) then - error (f_"OVF (metadata) directory (%s) does not exist or \ - is not a directory") - ovf_output; - - debug "VDSM: OVF (metadata) directory: %s" ovf_output; - - (* The final directory structure should look like this: - * ///images/ - * / # first disk - * /.meta # first disk - * / # second disk - * /.meta # second disk - * / # etc - * /.meta # - *) - - (* Create the target filenames. *) - let filenames = - List.map ( - fun (image_uuid, vol_uuid) -> - let filename = images_dir // image_uuid // vol_uuid in - debug "VDSM: disk: %s" filename; - filename - ) (List.combine image_uuids vol_uuids) in - - (* Generate the .meta files associated with each volume. *) - let sizes = List.map snd disks in - let metas = - Create_ovf.create_meta_files output_alloc output_format - dd_uuid image_uuids sizes in - List.iter ( - fun (filename, meta) -> - let meta_filename = filename ^ ".meta" in - with_open_out meta_filename (fun chan -> output_string chan meta) - ) (List.combine filenames metas); - - (* Set up the NBD servers. *) - List.iter ( - fun ((i, size), filename) -> - let socket = sprintf "%s/out%d" dir i in - On_exit.unlink socket; - - (* Create the actual output disk. *) - output_to_local_file output_alloc output_format filename size socket - ) (List.combine disks filenames); - - (* Save parameters since we need them during finalization. *) - let t = dd_mp, dd_uuid, sizes in - t - - let finalize dir options t source inspect target_meta = - let output_alloc, output_format, - output_name, output_storage, - image_uuids, vol_uuids, vm_uuid, ovf_output, - compat, ovf_flavour = options in - let dd_mp, dd_uuid, sizes = t in - - (* Create the metadata. *) - let ovf = Create_ovf.create_ovf source inspect target_meta sizes - output_alloc output_format output_name dd_uuid - image_uuids - vol_uuids - dir - vm_uuid - ovf_flavour in - - (* Write it to the metadata file. *) - let file = ovf_output // vm_uuid ^ ".ovf" in - with_open_out file (fun chan -> DOM.doc_to_chan chan ovf) - - let request_size = None -end diff --git a/output/output_vdsm.mli b/output/output_vdsm.mli deleted file mode 100644 index 2260d7e6..00000000 --- a/output/output_vdsm.mli +++ /dev/null @@ -1,21 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2021 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 vdsm] output mode. *) - -module VDSM : Output.OUTPUT diff --git a/output/rhv-upload-cancel.py b/output/rhv-upload-cancel.py deleted file mode 100644 index b36e1904..00000000 --- a/output/rhv-upload-cancel.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- python -*- -# oVirt or RHV upload cancel used by ‘virt-v2v -o rhv-upload’ -# Copyright (C) 2019-2021 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. - -import json -import logging -import sys -from contextlib import closing -from urllib.parse import urlparse, urlunparse - -import ovirtsdk4 as sdk -import ovirtsdk4.types as types - - -def debug(s): - if params['verbose']: - print(s, file=sys.stderr) - sys.stderr.flush() - - -# Parameters are passed in via a JSON doc from the OCaml code. -# Because this Python code ships embedded inside virt-v2v there -# is no formal API here. -params = None - -if len(sys.argv) != 2: - raise RuntimeError("incorrect number of parameters") - -# Parameters are passed in via a JSON document. -with open(sys.argv[1], 'r') as fp: - params = json.load(fp) - -# What is passed in is a password file, read the actual password. -with open(params['output_password'], 'r') as fp: - output_password = fp.read() -output_password = output_password.rstrip() - -# Parse out the username from the output_conn URL. -parsed = urlparse(params['output_conn']) -username = parsed.username or "admin@internal" -netloc = f"{parsed.hostname:parsed.port}" if parsed.port else parsed.hostname - -# Connect to the server. -connection = sdk.Connection( - url=urlunparse(parsed._replace(netloc=netloc)), - username=username, - password=output_password, - ca_file=params['rhv_cafile'], - log=logging.getLogger(), - insecure=params['insecure'], -) - -with closing(connection): - system_service = connection.system_service() - image_transfers_service = system_service.image_transfers_service() - - # Try to cancel the transfers. This should delete the associated disk. - for id in params['transfer_ids']: - try: - transfer_service = \ - image_transfers_service.image_transfer_service(id) - transfer_service.cancel() - except sdk.NotFoundError: - debug("unexpected error: transfer id %s not found" % id) - except Exception: - if params['verbose']: - traceback.print_exc() - - disks_service = system_service.disks_service() - - # In case we didn't associate a disk with a transfer and as a last - # resort, delete the disk too. - for uuid in params['disk_uuids']: - try: - disk_service = disks_service.disk_service(uuid) - disk_service.remove() - except (sdk.NotFoundError, sdk.Error): - # We expect these exceptions so ignore them. - pass - except Exception: - if params['verbose']: - traceback.print_exc() diff --git a/output/rhv-upload-createvm.py b/output/rhv-upload-createvm.py deleted file mode 100644 index 9af2c167..00000000 --- a/output/rhv-upload-createvm.py +++ /dev/null @@ -1,137 +0,0 @@ -# -*- python -*- -# oVirt or RHV upload create VM used by ‘virt-v2v -o rhv-upload’ -# Copyright (C) 2018 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. - -import json -import logging -import sys -import time -import uuid - -from urllib.parse import urlparse, urlunparse - -import ovirtsdk4 as sdk -import ovirtsdk4.types as types - - -def debug(s): - if params['verbose']: - print(s, file=sys.stderr) - sys.stderr.flush() - - -def jobs_completed(system_service, correlation_id): - jobs_service = system_service.jobs_service() - - try: - jobs = jobs_service.list( - search="correlation_id=%s" % correlation_id) - except sdk.Error as e: - debug( - "Error searching for jobs with correlation id %s: %s" % - (correlation_id, e)) - # We don't know, assume that jobs did not complete yet. - return False - - # STARTED is the only "in progress" status, anything else means the job - # has already terminated. - if all(job.status != types.JobStatus.STARTED for job in jobs): - failed_jobs = [(job.description, str(job.status)) - for job in jobs - if job.status != types.JobStatus.FINISHED] - if failed_jobs: - raise RuntimeError( - "Failed to create a VM! Failed jobs: %r" % failed_jobs) - return True - else: - running_jobs = [(job.description, str(job.status)) for job in jobs] - debug("Some jobs with correlation id %s are running: %s" % - (correlation_id, running_jobs)) - return False - - -# Seconds to wait for the VM import job to complete in oVirt. -timeout = 3 * 60 - -# Parameters are passed in via a JSON doc from the OCaml code. -# Because this Python code ships embedded inside virt-v2v there -# is no formal API here. -params = None -ovf = None # OVF file - -if len(sys.argv) != 3: - raise RuntimeError("incorrect number of parameters") - -# Parameters are passed in via a JSON document. -with open(sys.argv[1], 'r') as fp: - params = json.load(fp) - -# What is passed in is a password file, read the actual password. -with open(params['output_password'], 'r') as fp: - output_password = fp.read() -output_password = output_password.rstrip() - -# Read the OVF document. -with open(sys.argv[2], 'r') as fp: - ovf = fp.read() - -# Parse out the username from the output_conn URL. -parsed = urlparse(params['output_conn']) -username = parsed.username or "admin@internal" -netloc = f"{parsed.hostname:parsed.port}" if parsed.port else parsed.hostname - -# Connect to the server. -connection = sdk.Connection( - url=urlunparse(parsed._replace(netloc=netloc)), - username=username, - password=output_password, - ca_file=params['rhv_cafile'], - log=logging.getLogger(), - insecure=params['insecure'], -) - -system_service = connection.system_service() - -# Get the cluster. -cluster = system_service.clusters_service().cluster_service(params['rhv_cluster_uuid']) -cluster = cluster.get() - -correlation_id = str(uuid.uuid4()) -vms_service = system_service.vms_service() -vm = vms_service.add( - types.Vm( - cluster=cluster, - initialization=types.Initialization( - configuration=types.Configuration( - type=types.ConfigurationType.OVA, - data=ovf, - ) - ) - ), - query={'correlation_id': correlation_id}, -) - -# Wait for the import job to finish. -endt = time.monotonic() + timeout -while True: - time.sleep(10) - if jobs_completed(system_service, correlation_id): - break - if time.monotonic() > endt: - raise RuntimeError( - "Timed out waiting for VM creation!" - " Jobs still running for correlation id %s" % correlation_id) diff --git a/output/rhv-upload-finalize.py b/output/rhv-upload-finalize.py deleted file mode 100644 index 12fd39ec..00000000 --- a/output/rhv-upload-finalize.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- python -*- -# oVirt or RHV upload finalize used by ‘virt-v2v -o rhv-upload’ -# Copyright (C) 2018-2021 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. - -import json -import logging -import sys -import time -from urllib.parse import urlparse, urlunparse - -import ovirtsdk4 as sdk -import ovirtsdk4.types as types - -# Timeout to wait for oVirt disks to change status, or the transfer -# object to finish initializing [seconds]. -timeout = 5 * 60 - - -def debug(s): - if params['verbose']: - print(s, file=sys.stderr) - sys.stderr.flush() - - -def finalize_transfer(connection, transfer_id, disk_id): - """ - Finalize a transfer, making the transfer disk available. - - If finalizing succeeds, the transfer's disk status will change to OK - and transfer's phase will change to FINISHED_SUCCESS. Unfortunately, - the disk status is modified before the transfer finishes, and oVirt - may still hold a lock on the disk at this point. - - The only way to make sure that the disk is unlocked, is to wait - until the transfer phase switches FINISHED_SUCCESS. Unfortunately - oVirt makes this hard to use because the transfer is removed shortly - after switching the phase to the final phase. However if the - transfer was removed, we can be sure that the disk is not locked, - since oVirt releases the locks before removing the transfer. - - On errors, the transfer's phase will change to FINISHED_FAILURE and - the disk status will change to ILLEGAL and it will be removed. Again - the transfer will be removed shortly after that. - - If oVirt fails to finalize the transfer, transfer's phase will - change to PAUSED_SYSTEM. In this case the disk's status will change - to ILLEGAL and it will not be removed. - - oVirt 4.4.7 made waiting for transfer easier by keeping transfers - after they complete, but we must support older versions so we have - generic code that work with any version. - - For more info see: - - http://ovirt.github.io/ovirt-engine-api-model/4.4/#services/image_transfer - - http://ovirt.github.io/ovirt-engine-sdk/master/types.m.html#ovirtsdk4.types.ImageTransfer - """ - debug("finalizing transfer %s" % transfer_id) - transfer_service = (connection.system_service() - .image_transfers_service() - .image_transfer_service(transfer_id)) - - start = time.monotonic() - - transfer_service.finalize() - - while True: - time.sleep(1) - try: - transfer = transfer_service.get() - except sdk.NotFoundError: - # Transfer was removed (ovirt < 4.4.7). We need to check the - # disk status to understand if the transfer was successful. - # Due to the way oVirt does locking, we know that the disk - # is unlocked at this point so we can check only once. - - debug("transfer %s was removed, checking disk %s status" - % (transfer_id, disk_id)) - - disk_service = (connection.system_service() - .disks_service() - .disk_service(disk_id)) - - try: - disk = disk_service.get() - except sdk.NotFoundError: - raise RuntimeError( - "transfer %s failed: disk %s was removed" - % (transfer_id, disk_id)) - - debug("disk %s is %s" % (disk.id, disk.status)) - - if disk.status == types.DiskStatus.OK: - break - - raise RuntimeError( - "transfer %s failed: disk is %s" % (transfer_id, disk.status)) - else: - # Transfer exists, check if it reached one of the final - # phases, or we timed out. - - debug("transfer %s is %s" % (transfer.id, transfer.phase)) - - if transfer.phase == types.ImageTransferPhase.FINISHED_SUCCESS: - break - - if transfer.phase == types.ImageTransferPhase.FINISHED_FAILURE: - raise RuntimeError( - "transfer %s has failed" % (transfer_id,)) - - if transfer.phase == types.ImageTransferPhase.PAUSED_SYSTEM: - raise RuntimeError( - "transfer %s was paused by system" % (transfer.id,)) - - if time.monotonic() > start + timeout: - raise RuntimeError( - "timed out waiting for transfer %s to finalize, " - "transfer is %s" - % (transfer.id, transfer.phase)) - - debug("transfer %s finalized in %.3f seconds" - % (transfer_id, time.monotonic() - start)) - - -# Parameters are passed in via a JSON doc from the OCaml code. -# Because this Python code ships embedded inside virt-v2v there -# is no formal API here. -params = None - -if len(sys.argv) != 2: - raise RuntimeError("incorrect number of parameters") - -# Parameters are passed in via a JSON document. -with open(sys.argv[1], 'r') as fp: - params = json.load(fp) - -# What is passed in is a password file, read the actual password. -with open(params['output_password'], 'r') as fp: - output_password = fp.read() -output_password = output_password.rstrip() - -# Parse out the username from the output_conn URL. -parsed = urlparse(params['output_conn']) -username = parsed.username or "admin@internal" -netloc = f"{parsed.hostname:parsed.port}" if parsed.port else parsed.hostname - -# Connect to the server. -connection = sdk.Connection( - url=urlunparse(parsed._replace(netloc=netloc)), - username=username, - password=output_password, - ca_file=params['rhv_cafile'], - log=logging.getLogger(), - insecure=params['insecure'], -) - -# Finalize all the transfers. -for (transfer_id, disk_id) in zip(params['transfer_ids'], params['disk_uuids']): - finalize_transfer(connection, transfer_id, disk_id) - -connection.close() diff --git a/output/rhv-upload-plugin.py b/output/rhv-upload-plugin.py deleted file mode 100644 index 8bc79a4a..00000000 --- a/output/rhv-upload-plugin.py +++ /dev/null @@ -1,525 +0,0 @@ -# -*- python -*- -# oVirt or RHV upload nbdkit plugin used by ‘virt-v2v -o rhv-upload’ -# Copyright (C) 2018-2021 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. - -import json -import queue -import socket -import ssl -import threading -import time - -from contextlib import contextmanager -from http.client import HTTPSConnection, HTTPConnection -from urllib.parse import urlparse - -import nbdkit - -# Using version 2 supporting the buffer protocol for better performance. -API_VERSION = 2 - -# Maximum number of connection to imageio server. Based on testing with imageio -# client, this give best performance. -MAX_CONNECTIONS = 4 - -# Maximum idle time allowed for imageio connections. -IDLE_TIMEOUT = 30 - -# Required parameters. -size = None -url = None - -# Optional parameters. -cafile = None -insecure = False -is_ovirt_host = False - -# List of options read from imageio server. -options = None - -# Pool of HTTP connections. -pool = None - -# Set when plugin is cleaning up. -done = threading.Event() - -# Set when periodic flush request fails. -pool_error = None - - -# Parse parameters. -def config(key, value): - global cafile, url, is_ovirt_host, insecure, size - - if key == "cafile": - cafile = value - elif key == "insecure": - insecure = value.lower() in ['true', '1'] - elif key == "is_ovirt_host": - is_ovirt_host = value.lower() in ['true', '1'] - elif key == "size": - size = int(value) - elif key == "url": - url = urlparse(value) - else: - raise RuntimeError("unknown configuration key '%s'" % key) - - -def config_complete(): - # These parameters are required. - if url is None: - raise RuntimeError("url parameter was not set") - if size is None: - raise RuntimeError("size parameter was not set") - - -def after_fork(): - global options, pool - - http = create_http(url) - options = get_options(http, url) - http.close() - - nbdkit.debug("imageio features: flush=%(can_flush)r " - "zero=%(can_zero)r unix_socket=%(unix_socket)r " - "max_readers=%(max_readers)r max_writers=%(max_writers)r" - % options) - - pool = create_http_pool(url, options) - - t = threading.Thread(target=pool_keeper, name="poolkeeper") - t.daemon = True - t.start() - - -# This function is not actually defined before nbdkit 1.28, but it -# doesn't particularly matter if we don't close the pool because -# clients should call flush(). -def cleanup(): - nbdkit.debug("cleaning up") - done.set() - close_http_pool(pool) - - -def thread_model(): - """ - Using parallel model to speed up transfer with multiple connections to - imageio server. - """ - return nbdkit.THREAD_MODEL_PARALLEL - - -def open(readonly): - return 1 - - -def can_trim(h): - return False - - -def can_flush(h): - return options['can_flush'] - - -def can_fua(h): - # imageio flush feature is is compatible with NBD_CMD_FLAG_FUA. - return options['can_flush'] - - -def can_multi_conn(h): - # We can always handle multiple connections, and the number of NBD - # connections is independent of the number of HTTP clients in the - # pool. - return True - - -def get_size(h): - return size - - -# Any unexpected HTTP response status from the server will end up calling this -# function which logs the full error, and raises a RuntimeError exception. -def request_failed(r, msg): - status = r.status - reason = r.reason - try: - body = r.read() - except EnvironmentError as e: - body = "(Unable to read response body: %s)" % e - - # Log the full error if we're verbose. - nbdkit.debug("unexpected response from imageio server:") - nbdkit.debug(msg) - nbdkit.debug("%d: %s" % (status, reason)) - nbdkit.debug(body) - - # Only a short error is included in the exception. - raise RuntimeError("%s: %d %s: %r" % (msg, status, reason, body[:200])) - - -# For documentation see: -# https://github.com/oVirt/ovirt-imageio/blob/master/docs/random-io.md -# For examples of working code to read/write from the server, see: -# https://github.com/oVirt/ovirt-imageio/blob/master/daemon/test/server_test.py -def pread(h, buf, offset, flags): - count = len(buf) - headers = {"Range": "bytes=%d-%d" % (offset, offset + count - 1)} - - with http_context(pool) as http: - http.request("GET", url.path, headers=headers) - - r = http.getresponse() - # 206 = HTTP Partial Content. - if r.status != 206: - request_failed(r, - "could not read sector offset %d size %d" % - (offset, count)) - - content_length = int(r.getheader("content-length")) - if content_length != count: - # Should never happen. - request_failed(r, - "unexpected Content-Length offset %d size %d got %d" % - (offset, count, content_length)) - - with memoryview(buf) as view: - got = 0 - while got < count: - n = r.readinto(view[got:]) - if n == 0: - request_failed(r, - "short read offset %d size %d got %d" % - (offset, count, got)) - got += n - - -def pwrite(h, buf, offset, flags): - count = len(buf) - - flush = "y" if (options['can_flush'] and (flags & nbdkit.FLAG_FUA)) else "n" - - with http_context(pool) as http: - http.putrequest("PUT", url.path + "?flush=" + flush) - # The oVirt server only uses the first part of the range, and the - # content-length. - http.putheader("Content-Range", "bytes %d-%d/*" % - (offset, offset + count - 1)) - http.putheader("Content-Length", str(count)) - http.endheaders() - - try: - http.send(buf) - except BrokenPipeError: - pass - - r = http.getresponse() - if r.status != 200: - request_failed(r, - "could not write sector offset %d size %d" % - (offset, count)) - - r.read() - - -def zero(h, count, offset, flags): - # Unlike the trim and flush calls, there is no 'can_zero' method - # so nbdkit could call this even if the server doesn't support - # zeroing. If this is the case we must emulate. - if not options['can_zero']: - emulate_zero(h, count, offset, flags) - return - - flush = bool(options['can_flush'] and (flags & nbdkit.FLAG_FUA)) - - # Construct the JSON request for zeroing. - buf = json.dumps({'op': "zero", - 'offset': offset, - 'size': count, - 'flush': flush}).encode() - - headers = {"Content-Type": "application/json", - "Content-Length": str(len(buf))} - - with http_context(pool) as http: - http.request("PATCH", url.path, body=buf, headers=headers) - - r = http.getresponse() - if r.status != 200: - request_failed(r, - "could not zero sector offset %d size %d" % - (offset, count)) - - r.read() - - -def emulate_zero(h, count, offset, flags): - flush = "y" if (options['can_flush'] and (flags & nbdkit.FLAG_FUA)) else "n" - - with http_context(pool) as http: - http.putrequest("PUT", url.path + "?flush=" + flush) - http.putheader("Content-Range", - "bytes %d-%d/*" % (offset, offset + count - 1)) - http.putheader("Content-Length", str(count)) - http.endheaders() - - try: - buf = bytearray(128 * 1024) - while count > len(buf): - http.send(buf) - count -= len(buf) - http.send(memoryview(buf)[:count]) - except BrokenPipeError: - pass - - r = http.getresponse() - if r.status != 200: - request_failed(r, - "could not write zeroes offset %d size %d" % - (offset, count)) - - r.read() - - -def flush(h, flags): - if pool_error: - raise pool_error - - # Wait until all inflight requests are completed, and send a flush - # request for all imageio connections. - locked = [] - - # Lock the pool by taking all connections out. - while len(locked) < pool.maxsize: - locked.append(pool.get()) - - try: - for item in locked: - send_flush(item.http) - item.last_used = time.monotonic() - finally: - # Unlock the pool by puting the connection back. - for item in locked: - pool.put(item) - - -def send_flush(http): - # Construct the JSON request for flushing. - buf = json.dumps({'op': "flush"}).encode() - - headers = {"Content-Type": "application/json", - "Content-Length": str(len(buf))} - - http.request("PATCH", url.path, body=buf, headers=headers) - - r = http.getresponse() - if r.status != 200: - request_failed(r, "could not flush") - - r.read() - - -# Modify http.client.HTTPConnection to work over a Unix domain socket. -# Derived from uhttplib written by Erik van Zijst under an MIT license. -# (https://pypi.org/project/uhttplib/) -# Ported to Python 3 by Irit Goihman. -class UnixHTTPConnection(HTTPConnection): - def __init__(self, path, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): - self.path = path - HTTPConnection.__init__(self, "localhost", timeout=timeout) - - def connect(self): - self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: - self.sock.settimeout(timeout) - self.sock.connect(self.path) - - -class PoolItem: - - def __init__(self, http): - self.http = http - self.last_used = None - - -# Connection pool. -def create_http_pool(url, options): - count = min(options["max_readers"], - options["max_writers"], - MAX_CONNECTIONS) - - nbdkit.debug("creating http pool connections=%d" % count) - - unix_socket = options["unix_socket"] if is_ovirt_host else None - - pool = queue.Queue(count) - - for i in range(count): - http = create_http(url, unix_socket=unix_socket) - pool.put(PoolItem(http)) - - return pool - - -def pool_keeper(): - """ - Thread flushing idle connections, keeping them alive. - - If a connection does not send any request for 60 seconds, imageio - server closes the connection. Recovering from closed connection is - hard and unsafe, so this thread ensure that connections never - becomes idle by sending a flush request if the connection is idle - for too much time. - - In normal conditions, all connections are busy most of the time, so - the keeper will find no idle connections. If there short delays in - nbdcopy, the keeper will find some idle connections, but will - quickly return them back to the pool. In the pathological case when - nbdcopy is blocked for 3 minutes on vddk input, the keeper will send - a flush request on all connections every ~30 seconds, until nbdcopy - starts communicating again. - """ - global pool_error - - nbdkit.debug("poolkeeper: started") - - while not done.wait(IDLE_TIMEOUT / 2): - idle = [] - - while True: - try: - idle.append(pool.get_nowait()) - except queue.Empty: - break - - if idle: - now = time.monotonic() - for item in idle: - if item.last_used and now - item.last_used > IDLE_TIMEOUT: - nbdkit.debug("poolkeeper: flushing idle connection") - try: - send_flush(item.http) - item.last_used = now - except Exception as e: - # We will report this error on the next request. - pool_error = e - item.last_used = None - - pool.put(item) - - nbdkit.debug("poolkeeper: stopped") - - -@contextmanager -def http_context(pool): - """ - Context manager yielding an imageio http connection from the pool. Blocks - until a connection is available. - """ - if pool_error: - raise pool_error - - item = pool.get() - try: - yield item.http - finally: - item.last_used = time.monotonic() - pool.put(item) - - -def close_http_pool(pool): - """ - Wait until all inflight requests are done, close all connections and remove - them from the pool. - - No request can be served by the pool after this call. - """ - nbdkit.debug("closing http pool") - - locked = [] - - while len(locked) < pool.maxsize: - locked.append(pool.get()) - - for item in locked: - item.http.close() - - -def create_http(url, unix_socket=None): - """ - Create http connection for transfer url. - - Returns HTTPConnection. - """ - if unix_socket: - nbdkit.debug("creating unix http connection socket=%r" % unix_socket) - try: - return UnixHTTPConnection(unix_socket) - except Exception as e: - # Very unlikely, but we can recover by using https. - nbdkit.debug("cannot create unix socket connection: %s" % e) - - if url.scheme == "https": - context = \ - ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, - cafile=cafile) - if insecure: - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - - nbdkit.debug("creating https connection host=%s port=%s" % - (url.hostname, url.port)) - return HTTPSConnection(url.hostname, url.port, context=context) - elif url.scheme == "http": - nbdkit.debug("creating http connection host=%s port=%s" % - (url.hostname, url.port)) - return HTTPConnection(url.hostname, url.port) - else: - raise RuntimeError("unknown URL scheme (%s)" % url.scheme) - - -def get_options(http, url): - """ - Send OPTIONS request to imageio server and return options dict. - """ - http.request("OPTIONS", url.path) - r = http.getresponse() - data = r.read() - - if r.status == 200: - j = json.loads(data) - features = j["features"] - return { - "can_flush": "flush" in features, - "can_zero": "zero" in features, - "unix_socket": j.get('unix_socket'), - "max_readers": j.get("max_readers", 1), - "max_writers": j.get("max_writers", 1), - } - - elif r.status == 405 or r.status == 204: - # Old imageio servers returned either 405 Method Not Allowed or - # 204 No Content (with an empty body). - return { - "can_flush": False, - "can_zero": False, - "unix_socket": None, - "max_readers": 1, - "max_writers": 1, - } - else: - raise RuntimeError("could not use OPTIONS request: %d: %s" % - (r.status, r.reason)) diff --git a/output/rhv-upload-precheck.py b/output/rhv-upload-precheck.py deleted file mode 100644 index 0bbb738d..00000000 --- a/output/rhv-upload-precheck.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- python -*- -# oVirt or RHV pre-upload checks used by ‘virt-v2v -o rhv-upload’ -# Copyright (C) 2018-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. - -import json -import logging -import re -import sys - -from urllib.parse import urlparse, urlunparse - -import ovirtsdk4 as sdk -import ovirtsdk4.types as types - -# Parameters are passed in via a JSON doc from the OCaml code. -# Because this Python code ships embedded inside virt-v2v there -# is no formal API here. -params = None - -if len(sys.argv) != 2: - raise RuntimeError("incorrect number of parameters") - -# Parameters are passed in via a JSON document. -with open(sys.argv[1], 'r') as fp: - params = json.load(fp) - -# What is passed in is a password file, read the actual password. -with open(params['output_password'], 'r') as fp: - output_password = fp.read() -output_password = output_password.rstrip() - -# Parse out the username from the output_conn URL. -parsed = urlparse(params['output_conn']) -username = parsed.username or "admin@internal" -netloc = f"{parsed.hostname:parsed.port}" if parsed.port else parsed.hostname - -# Check the storage domain name is valid -# (https://bugzilla.redhat.com/show_bug.cgi?id=1986386#c1) -# Also this means it cannot contain spaces or glob symbols, so -# the search below is valid. -output_storage = params['output_storage'] -if not re.match('^[-a-zA-Z0-9_]+$', output_storage): - raise RuntimeError("The storage domain (-os) parameter ‘%s’ is not valid" % - output_storage) - -# Connect to the server. -connection = sdk.Connection( - url=urlunparse(parsed._replace(netloc=netloc)), - username=username, - password=output_password, - ca_file=params['rhv_cafile'], - log=logging.getLogger(), - insecure=params['insecure'], -) - -system_service = connection.system_service() - -# Check whether there is a datacenter for the specified storage. -data_centers = system_service.data_centers_service().list( - search='storage.name=%s' % output_storage, - case_sensitive=True, -) -if len(data_centers) == 0: - storage_domains = system_service.storage_domains_service().list( - search='name=%s' % output_storage, - case_sensitive=True, - ) - if len(storage_domains) == 0: - # The storage domain does not even exist. - raise RuntimeError("The storage domain ‘%s’ does not exist" % - output_storage) - - # The storage domain is not attached to a datacenter - # (shouldn't happen, would fail on disk creation). - raise RuntimeError("The storage domain ‘%s’ is not attached to a DC" % - output_storage) -datacenter = data_centers[0] - -# Get the storage domain. -storage_domains = connection.follow_link(datacenter.storage_domains) -try: - storage_domain = [sd for sd in storage_domains - if sd.name == output_storage][0] -except IndexError: - raise RuntimeError("The storage domain ‘%s’ does not exist" % - output_storage) - -# Get the cluster. -clusters = connection.follow_link(datacenter.clusters) -clusters = [cluster for cluster in clusters if cluster.name == params['rhv_cluster']] -if len(clusters) == 0: - raise RuntimeError("The cluster ‘%s’ is not part of the DC ‘%s’, " - "where the storage domain ‘%s’ is" % - (params['rhv_cluster'], datacenter.name, - output_storage)) -cluster = clusters[0] -cpu = cluster.cpu -if cpu.architecture == types.Architecture.UNDEFINED: - raise RuntimeError("The cluster ‘%s’ has an unknown architecture" % - (params['rhv_cluster'])) - -# Find if any disk already exists with specified UUID. -# Only used with -oo rhv-disk-uuid. It is assumed that the -# random UUIDs that we generate are unlikely to conflict. -disks_service = system_service.disks_service() - -for uuid in params.get('rhv_disk_uuids', []): - try: - disk_service = disks_service.disk_service(uuid).get() - raise RuntimeError("Disk with the UUID '%s' already exists" % uuid) - except sdk.NotFoundError: - pass - -# Otherwise everything is OK, print a JSON with the results. -results = { - "rhv_storagedomain_uuid": storage_domain.id, - "rhv_cluster_uuid": cluster.id, - "rhv_cluster_cpu_architecture": cpu.architecture.value, -} - -json.dump(results, sys.stdout) diff --git a/output/rhv-upload-transfer.py b/output/rhv-upload-transfer.py deleted file mode 100644 index ed96153b..00000000 --- a/output/rhv-upload-transfer.py +++ /dev/null @@ -1,298 +0,0 @@ -# -*- python -*- -# oVirt or RHV upload start transfer used by ‘virt-v2v -o rhv-upload’ -# Copyright (C) 2018-2021 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. - -import inspect -import json -import logging -import sys -import time -from contextlib import closing -from urllib.parse import urlparse, urlunparse - -import ovirtsdk4 as sdk -import ovirtsdk4.types as types - -# Timeout to wait for oVirt disks to change status, or the transfer -# object to finish initializing [seconds]. -timeout = 5 * 60 - - -def debug(s): - if params['verbose']: - print(s, file=sys.stderr) - sys.stderr.flush() - - -def find_host(connection): - """Return the current host object or None.""" - try: - with open("/etc/vdsm/vdsm.id") as f: - vdsm_id = f.readline().strip() - except FileNotFoundError: - # Expected condition when running on non-oVirt host. - debug("not an oVirt host, using non-oVirt host") - return None - except Exception as e: - # Unexpected but we can degrade to remote transfer. - debug(f"warning: cannot read host id, using non-oVirt host: {e}") - return None - - debug("hw_id = %r" % vdsm_id) - - system_service = connection.system_service() - storage_name = params['output_storage'] - data_centers = system_service.data_centers_service().list( - search='storage.name=%s' % storage_name, - case_sensitive=True, - ) - if len(data_centers) == 0: - # The storage domain is not attached to a datacenter - # (shouldn't happen, would fail on disk creation). - debug("storange domain (%s) is not attached to a DC" % storage_name) - return None - - datacenter = data_centers[0] - debug("datacenter = %s" % datacenter.name) - - hosts_service = system_service.hosts_service() - hosts = hosts_service.list( - search="hw_id=%s and datacenter=%s and status=Up" - % (vdsm_id, datacenter.name), - case_sensitive=True, - ) - if len(hosts) == 0: - # Couldn't find a host that's fulfilling the following criteria: - # - 'hw_id' equals to 'vdsm_id' - # - Its status is 'Up' - # - Belongs to the storage domain's datacenter - debug("cannot find a running host with hw_id=%r, " - "that belongs to datacenter '%s', " - "using any host" % (vdsm_id, datacenter.name)) - return None - - host = hosts[0] - debug("host.id = %r" % host.id) - - return types.Host(id=host.id) - - -def create_disk(connection): - """ - Create a new disk for the transfer and wait until the disk is ready. - - Returns disk object. - """ - system_service = connection.system_service() - disks_service = system_service.disks_service() - - if params['disk_format'] == "raw": - disk_format = types.DiskFormat.RAW - else: - disk_format = types.DiskFormat.COW - - disk = disks_service.add( - disk=types.Disk( - id=params['disk_uuid'], - name=params['disk_name'], - description="Uploaded by virt-v2v", - format=disk_format, - # XXX For qcow2 disk on block storage, we should use the estimated - # size, based on qemu-img measure of the overlay. - initial_size=params['disk_size'], - provisioned_size=params['disk_size'], - # Handling this properly will be complex, see: - # https://www.redhat.com/archives/libguestfs/2018-March/msg00177.html - sparse=True, - storage_domains=[ - types.StorageDomain( - name=params['output_storage'], - ) - ], - ) - ) - - debug("disk.id = %r" % disk.id) - - # Wait till the disk moved from LOCKED state to OK state, as the transfer - # can't start if the disk is locked. - - disk_service = disks_service.disk_service(disk.id) - endt = time.monotonic() + timeout - while True: - time.sleep(1) - disk = disk_service.get() - if disk.status == types.DiskStatus.OK: - break - if time.monotonic() > endt: - raise RuntimeError( - "timed out waiting for disk %s to become unlocked" % disk.id) - - return disk - - -def create_transfer(connection, disk, host): - """ - Create image transfer and wait until the transfer is ready. - - Returns a transfer object. - """ - system_service = connection.system_service() - transfers_service = system_service.image_transfers_service() - - extra = {} - if transfer_supports_format(): - extra["format"] = types.DiskFormat.RAW - - transfer = transfers_service.add( - types.ImageTransfer( - disk=types.Disk(id=disk.id), - host=host, - inactivity_timeout=3600, - **extra, - ) - ) - - # At this point the transfer owns the disk and will delete the disk if the - # transfer is canceled, or if finalizing the transfer fails. - - debug("transfer.id = %r" % transfer.id) - - # Get a reference to the created transfer service. - transfer_service = transfers_service.image_transfer_service(transfer.id) - - # Wait until transfer's phase change from INITIALIZING to TRANSFERRING. On - # errors transfer's phase can change to PAUSED_SYSTEM or FINISHED_FAILURE. - # If the transfer was paused, we need to cancel it to remove the disk, - # otherwise the system will remove the disk and transfer shortly after. - - endt = time.monotonic() + timeout - while True: - time.sleep(1) - try: - transfer = transfer_service.get() - except sdk.NotFoundError: - # The system has removed the disk and the transfer. - raise RuntimeError("transfer %s was removed" % transfer.id) - - if transfer.phase == types.ImageTransferPhase.FINISHED_FAILURE: - # The system will remove the disk and the transfer soon. - raise RuntimeError( - "transfer %s has failed" % transfer.id) - - if transfer.phase == types.ImageTransferPhase.PAUSED_SYSTEM: - transfer_service.cancel() - raise RuntimeError( - "transfer %s was paused by system" % transfer.id) - - if transfer.phase == types.ImageTransferPhase.TRANSFERRING: - break - - if transfer.phase != types.ImageTransferPhase.INITIALIZING: - transfer_service.cancel() - raise RuntimeError( - "unexpected transfer %s phase %s" - % (transfer.id, transfer.phase)) - - if time.monotonic() > endt: - transfer_service.cancel() - raise RuntimeError( - "timed out waiting for transfer %s" % transfer.id) - - return transfer - - -def transfer_supports_format(): - """ - Return True if transfer supports the "format" argument, enabing the NBD - bakend on imageio side, which allows uploading to qcow2 images. - - This feature was added in ovirt 4.3. We assume that the SDK version matches - engine version. - """ - sig = inspect.signature(types.ImageTransfer) - return "format" in sig.parameters - - -def get_transfer_url(transfer): - """ - Returns the transfer url, preferring direct transfer if possible. - """ - if params['rhv_direct']: - if transfer.transfer_url is None: - raise RuntimeError("direct upload to host not supported, " - "requires ovirt-engine >= 4.2 and only works " - "when virt-v2v is run within the oVirt/RHV " - "environment, eg. on an oVirt node.") - return transfer.transfer_url - else: - return transfer.proxy_url - - -# Parameters are passed in via a JSON doc from the OCaml code. -# Because this Python code ships embedded inside virt-v2v there -# is no formal API here. -params = None - -if len(sys.argv) != 2: - raise RuntimeError("incorrect number of parameters") - -# Parameters are passed in via a JSON document. -with open(sys.argv[1], 'r') as fp: - data = fp.read() - -try: - params = json.loads(data) -except ValueError as e: - raise RuntimeError(f"Cannot parse params {data!r}: {e}").with_traceback( - e.__traceback__ - ) from None - -# What is passed in is a password file, read the actual password. -with open(params['output_password'], 'r') as fp: - output_password = fp.read() -output_password = output_password.rstrip() - -# Parse out the username from the output_conn URL. -parsed = urlparse(params['output_conn']) -username = parsed.username or "admin@internal" -netloc = f"{parsed.hostname:parsed.port}" if parsed.port else parsed.hostname - -connection = sdk.Connection( - url=urlunparse(parsed._replace(netloc=netloc)), - username=username, - password=output_password, - ca_file=params['rhv_cafile'], - log=logging.getLogger(), - insecure=params['insecure'], -) - -with closing(connection): - # Use the local host if possible. - host = find_host(connection) if params['rhv_direct'] else None - disk = create_disk(connection) - - transfer = create_transfer(connection, disk, host) - destination_url = get_transfer_url(transfer) - -# Send the destination URL, transfer ID, and host flag back to OCaml code. -results = { - "transfer_id": transfer.id, - "destination_url": destination_url, - "is_ovirt_host": host is not None, -} -json.dump(results, sys.stdout) diff --git a/output/rhv-upload-vmcheck.py b/output/rhv-upload-vmcheck.py deleted file mode 100644 index cd500574..00000000 --- a/output/rhv-upload-vmcheck.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- python -*- -# oVirt or RHV VM existence check used by ‘virt-v2v -o rhv-upload’ -# Copyright (C) 2018-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. - -import json -import logging -import sys - -from urllib.parse import urlparse, urlunparse - -import ovirtsdk4 as sdk -import ovirtsdk4.types as types - -# Parameters are passed in via a JSON doc from the OCaml code. -# Because this Python code ships embedded inside virt-v2v there -# is no formal API here. -params = None - -if len(sys.argv) != 2: - raise RuntimeError("incorrect number of parameters") - -# Parameters are passed in via a JSON document. -with open(sys.argv[1], 'r') as fp: - params = json.load(fp) - -# What is passed in is a password file, read the actual password. -with open(params['output_password'], 'r') as fp: - output_password = fp.read() -output_password = output_password.rstrip() - -# Parse out the username from the output_conn URL. -parsed = urlparse(params['output_conn']) -username = parsed.username or "admin@internal" -netloc = f"{parsed.hostname:parsed.port}" if parsed.port else parsed.hostname - -# Connect to the server. -connection = sdk.Connection( - url=urlunparse(parsed._replace(netloc=netloc)), - username=username, - password=output_password, - ca_file=params['rhv_cafile'], - log=logging.getLogger(), - insecure=params['insecure'], -) - -system_service = connection.system_service() - -# Find if a virtual machine already exists with that name. -vms_service = system_service.vms_service() -vms = vms_service.list( - search=("name=%s" % params['output_name']), -) -if len(vms) > 0: - vm = vms[0] - raise RuntimeError("VM already exists with name ‘%s’, id ‘%s’" % - (params['output_name'], vm.id)) - -# Otherwise everything is OK, exit with no error. diff --git a/tests/Makefile.am b/tests/Makefile.am index 1ec1a702..955d08a0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -70,8 +70,6 @@ TESTS = \ test-v2v-i-ova-two-disks.sh \ test-v2v-i-vmx.sh \ test-v2v-it-vddk-io-query.sh \ - test-v2v-o-rhv-upload-oo-query.sh \ - test-v2v-o-vdsm-oo-query.sh \ test-v2v-bad-networks-and-bridges.sh \ test-v2v-cdrom.sh \ test-v2v-floppy.sh \ @@ -89,9 +87,6 @@ TESTS = \ test-v2v-o-null.sh \ test-v2v-o-openstack.sh \ test-v2v-o-qemu.sh \ - test-v2v-o-rhv.sh \ - test-v2v-o-rhv-upload.sh \ - test-v2v-o-vdsm-options.sh \ test-v2v-oa-option-qcow2.sh \ test-v2v-oa-option-raw.sh \ test-v2v-of-option.sh \ @@ -256,16 +251,6 @@ EXTRA_DIST += \ test-v2v-o-null.sh \ test-v2v-o-openstack.sh \ test-v2v-o-qemu.sh \ - test-v2v-o-rhv.ovf.expected \ - test-v2v-o-rhv.sh \ - test-v2v-o-rhv-upload.sh \ - test-v2v-o-rhv-upload-module/imageio.py \ - test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py \ - test-v2v-o-rhv-upload-module/ovirtsdk4/types.py \ - test-v2v-o-rhv-upload-oo-query.sh \ - test-v2v-o-vdsm-oo-query.sh \ - test-v2v-o-vdsm-options.ovf.expected \ - test-v2v-o-vdsm-options.sh \ test-v2v-oa-option-qcow2.sh \ test-v2v-oa-option-raw.sh \ test-v2v-of-option.sh \ diff --git a/tests/test-v2v-o-rhv-upload-module/imageio.py b/tests/test-v2v-o-rhv-upload-module/imageio.py deleted file mode 100755 index b9a491d7..00000000 --- a/tests/test-v2v-o-rhv-upload-module/imageio.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 -# -*- python -*- -# Copyright (C) 2018-2021 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. - -# Fake imageio web server used as a test harness. -# See v2v/test-v2v-o-rhv-upload.sh - -import sys -import threading -from http.server import HTTPServer, BaseHTTPRequestHandler - -class RequestHandler(BaseHTTPRequestHandler): - protocol_version = 'HTTP/1.1' - - def do_OPTIONS(self): - self.discard_request() - - # Advertize only flush and zero support. - content = b'''{ "features": [ "flush", "zero" ] }''' - length = len(content) - - self.send_response(200) - self.send_header("Content-type", "application/json; charset=UTF-8") - self.send_header("Content-Length", length) - self.end_headers() - self.wfile.write(content) - - # eg. zero request. Just ignore it. - def do_PATCH(self): - self.discard_request() - self.send_response(200) - self.send_header("Content-Length", "0") - self.end_headers() - - # Flush request. Ignore it. - def do_PUT(self): - self.discard_request() - self.send_response(200) - self.send_header("Content-Length", "0") - self.end_headers() - - def discard_request(self): - length = self.headers.get('Content-Length') - if length: - length = int(length) - content = self.rfile.read(length) - -server_address = ("", 0) -# XXX This should test HTTPS, not HTTP, because we are testing a -# different path through the main code. -httpd = HTTPServer(server_address, RequestHandler) -imageio_port = httpd.server_address[1] - -print("port: %d" % imageio_port) -sys.stdout.flush() - -httpd.serve_forever() diff --git a/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py b/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py deleted file mode 100644 index e33d0714..00000000 --- a/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py +++ /dev/null @@ -1,150 +0,0 @@ -# -*- python -*- -# Copyright (C) 2018 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. - -# Fake ovirtsdk4 module used as a test harness. -# See v2v/test-v2v-o-rhv-upload.sh - -class Error(Exception): - pass - - -class NotFoundError(Error): - pass - - -class Connection(object): - def __init__( - self, - url=None, - username=None, - password=None, - ca_file=None, - log=None, - insecure=False, - debug=True, - ): - pass - - def close(self): - pass - - def follow_link(self, objs): - return objs - - def system_service(self): - return SystemService() - - -class SystemService(object): - def clusters_service(self): - return ClustersService() - - def data_centers_service(self): - return DataCentersService() - - def disks_service(self): - return DisksService() - - def jobs_service(self): - return JobsService() - - def image_transfers_service(self): - return ImageTransfersService() - - def storage_domains_service(self): - return StorageDomainsService() - - def vms_service(self): - return VmsService() - - -class ClusterService(object): - def get(self): - return types.Cluster() - - -class ClustersService(object): - def cluster_service(self, id): - return ClusterService() - - -class DataCentersService(object): - def list(self, search=None, case_sensitive=False): - return [types.DataCenter()] - - -class DiskService(object): - def __init__(self, disk_id): - self._disk_id = disk_id - - def get(self): - return types.Disk(id=self._disk_id) - - def remove(self): - pass - - -class DisksService(object): - def add(self, disk=None): - disk.id = "756d81b0-d5c0-41bc-9bbe-b343c3fa3490" - return disk - - def disk_service(self, disk_id): - return DiskService(disk_id) - - -class JobsService(object): - def list(self, search=None): - return [types.Job()] - - -class ImageTransferService(object): - def __init__(self): - self._finalized = False - - def cancel(self): - pass - - def get(self): - if self._finalized: - raise NotFoundError - else: - return types.ImageTransfer() - - def finalize(self): - self._finalized = True - - -class ImageTransfersService(object): - def add(self, transfer): - return transfer - - def image_transfer_service(self, id): - return ImageTransferService() - - -class StorageDomainsService(object): - def list(self, search=None, case_sensitive=False): - return [StorageDomain()] - - -class VmsService(object): - def add(self, vm, query=None): - return vm - - def list(self, search=None): - return [] diff --git a/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py b/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py deleted file mode 100644 index 38d89573..00000000 --- a/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py +++ /dev/null @@ -1,184 +0,0 @@ -# -*- python -*- -# Copyright (C) 2018 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. - -# Fake ovirtsdk4 module used as a test harness. -# See v2v/test-v2v-o-rhv-upload.sh - -import os -from enum import Enum - -imageio_port = os.getenv("IMAGEIO_PORT") -assert imageio_port is not None - - -class Architecture(Enum): - UNDEFINED = "undefined" - X86_64 = "x86_64" - - def __init__(self, arch): - self._arch = arch - - def __str__(self): - return self._arch - - -class Cpu(object): - architecture = Architecture.X86_64 - - -class Cluster(object): - id = "2e97537b-a783-4706-af9e-75cb2e032dcd" - name = "Default" - cpu = Cpu() - - -class Configuration(object): - def __init__(self, type=None, data=None): - pass - - -class ConfigurationType(Enum): - OVA = 'ova' - OVF = 'ovf' - - def __init__(self, image): - self._image = image - - def __str__(self): - return self._image - - -class DiskFormat(Enum): - COW = "cow" - RAW = "raw" - - def __init__(self, image): - self._image = image - - def __str__(self): - return self._image - - -class DiskStatus(Enum): - ILLEGAL = "illegal" - LOCKED = "locked" - OK = "ok" - - def __init__(self, image): - self._image = image - - def __str__(self): - return self._image - - -class Disk(object): - def __init__( - self, - id=None, - name=None, - description=None, - format=None, - initial_size=None, - provisioned_size=None, - sparse=False, - storage_domains=None - ): - self.id = id - - status = DiskStatus.OK - - -class ImageTransferPhase(Enum): - CANCELLED = 'cancelled' - FINALIZING_FAILURE = 'finalizing_failure' - FINALIZING_SUCCESS = 'finalizing_success' - FINISHED_FAILURE = 'finished_failure' - FINISHED_SUCCESS = 'finished_success' - INITIALIZING = 'initializing' - PAUSED_SYSTEM = 'paused_system' - PAUSED_USER = 'paused_user' - RESUMING = 'resuming' - TRANSFERRING = 'transferring' - UNKNOWN = 'unknown' - - def __init__(self, image): - self._image = image - - def __str__(self): - return self._image - - -class ImageTransfer(object): - def __init__( - self, - disk=None, - host=None, - inactivity_timeout=None, - ): - pass - - id = "e26ac8ab-7090-4d5e-95ad-e707b511a359" - phase = ImageTransferPhase.TRANSFERRING - transfer_url = "http://localhost:" + imageio_port + "/" - - -class Initialization(object): - def __init__(self, configuration): - pass - - -class JobStatus(Enum): - ABORTED = "aborted" - FAILED = "failed" - FINISHED = "finished" - STARTED = "started" - UNKNOWN = "unknown" - - def __init__(self, image): - self._image = image - - def __str__(self): - return self._image - - -class Job(object): - description = "Fake job" - status = JobStatus.FINISHED - - -class StorageDomain(object): - def __init__(self, name=None): - pass - - id = "ba87af68-b630-4211-a73a-694c1a689405" - name = "Storage" - - -class Vm(object): - def __init__( - self, - cluster=None, - initialization=None - ): - pass - - -class DataCenter(object): - id = "31d8c73b-554b-4958-bb04-9ce97f0849e1" - name = "DC" - storage_domains = [StorageDomain()] - clusters = [Cluster()] diff --git a/tests/test-v2v-o-rhv-upload-oo-query.sh b/tests/test-v2v-o-rhv-upload-oo-query.sh deleted file mode 100755 index 5ef56b90..00000000 --- a/tests/test-v2v-o-rhv-upload-oo-query.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# libguestfs virt-v2v test script -# Copyright (C) 2018 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. - -# Test -oo "?" option. - -set -e - -source ./functions.sh -set -e -set -x - -skip_if_skipped - -export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" -export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win" - -f=test-v2v-o-rhv-upload-oo-query.actual -rm -f $f - -$VG virt-v2v --debug-gc \ - -o rhv-upload -oo "?" > $f - -grep -- "-oo rhv-cafile" $f -grep -- "-oo rhv-verifypeer" $f - -rm $f diff --git a/tests/test-v2v-o-rhv-upload.sh b/tests/test-v2v-o-rhv-upload.sh deleted file mode 100755 index 15d5d028..00000000 --- a/tests/test-v2v-o-rhv-upload.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -# libguestfs virt-v2v test script -# Copyright (C) 2018 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. - -# Test -o rhv-upload. -# -# These uses a test harness (see -# tests/test-v2v-o-rhv-upload-module/ovirtsdk4) to fake responses from -# oVirt. - -set -e -set -x - -source ./functions.sh -set -e -set -x - -skip_if_skipped -requires python3 --version -requires nbdkit $VIRT_V2V_NBDKIT_PYTHON_PLUGIN --version -requires test -f ../test-data/phony-guests/windows.img - -libvirt_uri="test://$abs_top_builddir/test-data/phony-guests/guests.xml" -f=../test-data/phony-guests/windows.img - -export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" -export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win" -export PYTHONPATH=$srcdir/test-v2v-o-rhv-upload-module:$PYTHONPATH - -# Run the imageio process and get the port number. -log=test-v2v-o-rhv-upload.webserver.log -rm -f $log -cleanup_fn rm -f $log -$srcdir/test-v2v-o-rhv-upload-module/imageio.py >$log 2>&1 & -pid=$! -cleanup_fn kill $pid -export IMAGEIO_PORT= -for i in {1..5}; do - IMAGEIO_PORT=$( grep "^port:" $log | awk '{print $2}' ) - if [ -n "$IMAGEIO_PORT" ]; then break; fi - sleep 3 -done -if [ ! -n "$IMAGEIO_PORT" ]; then - echo "$0: imageio process did not start up" - cat $log - exit 1 -fi -echo IMAGEIO_PORT=$IMAGEIO_PORT - -# Run virt-v2v -o rhv-upload. -# -# The fake ovirtsdk4 module doesn't care about most of the options -# like -oc, -oo rhv-cafile, -op etc. Any values may be used. -$VG virt-v2v --debug-gc -v -x \ - -i libvirt -ic "$libvirt_uri" windows \ - -o rhv-upload \ - -oc https://example.com/ovirt-engine/api \ - -oo rhv-cafile=/dev/null \ - -op /dev/null \ - -os Storage diff --git a/tests/test-v2v-o-rhv.ovf.expected b/tests/test-v2v-o-rhv.ovf.expected deleted file mode 100644 index 25e492fd..00000000 --- a/tests/test-v2v-o-rhv.ovf.expected +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - -
- List of networks - -
-
- List of Virtual Disks - -
- - windows - 00000000-0000-0000-0000-000000000000 - Blank - generated by virt-v2v - - #DATE# - True - False - - False - 0 - 2 - 1 -
- Microsoft Windows 7 Phony Edition - Windows7 -
-
- 1 CPU, 1024 Memory - - 1 virtual cpu - Number of virtual CPU - 1 - 3 - 1 - 1 - - - 1024 MB of memory - Memory Size - 2 - 4 - MegaBytes - 1024 - - - USB Controller - 3 - 23 - Disabled - - - Graphical Controller - #UUID# - 20 - video - 1 - vga - - - RNG Device - #UUID# - 0 - rng - virtio - - urandom - - - - Memory Ballooning Device - #UUID# - 0 - balloon - memballoon - - virtio - - - - Drive 1 - #VOL_ID# - 17 - disk - #DISK_ID#/#VOL_ID# - 00000000-0000-0000-0000-000000000000 - 00000000-0000-0000-0000-000000000000 - - 12345678-1234-1234-1234-123456789abc - 00000000-0000-0000-0000-000000000000 - #DATE# - #DATE# - #DATE# - 1 - - - #UUID# - Ethernet adapter on default - 10 - 3 - interface - default - eth0 - 00:11:22:33:44:55 - -
-
-
diff --git a/tests/test-v2v-o-rhv.sh b/tests/test-v2v-o-rhv.sh deleted file mode 100755 index e6ec7c61..00000000 --- a/tests/test-v2v-o-rhv.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash - -# libguestfs virt-v2v test script -# Copyright (C) 2014 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. - -# Test -o rhv. - -set -e - -source ./functions.sh -set -e -set -x - -skip_if_skipped -requires test -f ../test-data/phony-guests/windows.img - -libvirt_uri="test://$abs_top_builddir/test-data/phony-guests/guests.xml" -f=../test-data/phony-guests/windows.img - -export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" -export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win" - -d=test-v2v-o-rhv.d -rm -rf $d -cleanup_fn rm -r $d -mkdir $d - -# Create a dummy Export Storage Domain. -mkdir $d/12345678-1234-1234-1234-123456789abc -mkdir $d/12345678-1234-1234-1234-123456789abc/images -mkdir $d/12345678-1234-1234-1234-123456789abc/master -mkdir $d/12345678-1234-1234-1234-123456789abc/master/vms - -# $VG - XXX Disabled because the forking used to write files in -o rhv -# mode confuses valgrind. -virt-v2v --debug-gc -v -x \ - -i libvirt -ic "$libvirt_uri" windows \ - -o rhv -os $d - -# Test the OVF metadata was created. -test -f $d/12345678-1234-1234-1234-123456789abc/master/vms/*/*.ovf - -pushd $d/12345678-1234-1234-1234-123456789abc/images/* - -# Test the disk .meta was created. -test -f *.meta - -# Test the disk file was created. -vol=`basename *.meta .meta` -test -f $vol - -popd - -# Compare resulting OVF -VM_ID=$(basename $(ls -1d $d/12345678-1234-1234-1234-123456789abc/master/vms/*)) -DISK_ID=$(basename $(ls -1d $d/12345678-1234-1234-1234-123456789abc/images/*)) -VOL_ID=$(basename $(ls -1d $d/12345678-1234-1234-1234-123456789abc/images/$DISK_ID/*.meta) .meta) -OVF=$(ls -1d $d/12345678-1234-1234-1234-123456789abc/master/vms/$VM_ID/$VM_ID.ovf) - -RE_UUID='\<[0-9a-fA-F]\{8\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{12\}\>' - -# Filter variable strings -sed -i \ - -e "s/$DISK_ID/#DISK_ID#/g" \ - -e "s/$VM_ID/#VM_ID#/g" \ - -e "s/$VOL_ID/#VOL_ID#/g" \ - -e "s/\('"$RE_UUID"'#UUID#[^<]*#DATE# $f - -grep -- "-oo vdsm-compat" $f -grep -- "-oo vdsm-image-uuid" $f - -rm $f diff --git a/tests/test-v2v-o-vdsm-options.ovf.expected b/tests/test-v2v-o-vdsm-options.ovf.expected deleted file mode 100644 index 23ca180f..00000000 --- a/tests/test-v2v-o-vdsm-options.ovf.expected +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - List of networks - - - - List of Virtual Disks - - - - windows - 00000000-0000-0000-0000-000000000000 - Blank - generated by virt-v2v - - #DATE# - True - False - - False - 0 - 2 - 1 - - Microsoft Windows 7 Phony Edition - Windows7 - - - 1 CPU, 1024 Memory - - 1 virtual cpu - Number of virtual CPU - 1 - 3 - 1 - 1 - - - 1024 MB of memory - Memory Size - 2 - 4 - MegaBytes - 1024 - - - USB Controller - 3 - 23 - Disabled - - - Graphical Controller - #UUID# - 32768 - video - 1 - vga - - - RNG Device - #UUID# - 0 - rng - virtio - - urandom - - - - Memory Ballooning Device - #UUID# - 0 - balloon - memballoon - - virtio - - - - Drive 1 - VOL - 17 - disk - VOL - 00000000-0000-0000-0000-000000000000 - 00000000-0000-0000-0000-000000000000 - - 12345678-1234-1234-1234-123456789abc - 00000000-0000-0000-0000-000000000000 - #DATE# - #DATE# - #DATE# - 1 - - - #UUID# - Ethernet adapter on default - 10 - 3 - interface - default - eth0 - 00:11:22:33:44:55 - - - - diff --git a/tests/test-v2v-o-vdsm-options.sh b/tests/test-v2v-o-vdsm-options.sh deleted file mode 100755 index e8f8c538..00000000 --- a/tests/test-v2v-o-vdsm-options.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/bin/bash - -# libguestfs virt-v2v test script -# Copyright (C) 2014-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. - -# Test -o vdsm options -oo vdsm-*-uuid - -set -e -set -x - -source ./functions.sh -set -e -set -x - -skip_if_skipped -requires test -f ../test-data/phony-guests/windows.img - -libvirt_uri="test://$abs_top_builddir/test-data/phony-guests/guests.xml" -f=../test-data/phony-guests/windows.img - -export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" -export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win" - -d=test-v2v-o-vdsm-options.d -rm -rf $d -cleanup_fn rm -r $d -mkdir $d - -# Create a dummy Export Storage Domain. -mkdir $d/12345678-1234-1234-1234-123456789abc -mkdir $d/12345678-1234-1234-1234-123456789abc/images -mkdir $d/12345678-1234-1234-1234-123456789abc/images/IMAGE -mkdir $d/12345678-1234-1234-1234-123456789abc/master -mkdir $d/12345678-1234-1234-1234-123456789abc/master/vms -mkdir $d/12345678-1234-1234-1234-123456789abc/master/vms/VM - -# The -oo vdsm-*-uuid options don't actually check that the -# parameter is a UUID, which is useful here. - -$VG virt-v2v --debug-gc \ - -i libvirt -ic "$libvirt_uri" windows \ - -o vdsm -os $d/12345678-1234-1234-1234-123456789abc \ - -of qcow2 \ - -oo vdsm-image-uuid=IMAGE \ - -oo vdsm-vol-uuid=VOL \ - -oo vdsm-vm-uuid=VM \ - -oo vdsm-ovf-output=$d/12345678-1234-1234-1234-123456789abc/master/vms/VM \ - -oo vdsm-compat=1.1 \ - -oo vdsm-ovf-flavour=ovirt - -# Test the OVF metadata was created. -test -f $d/12345678-1234-1234-1234-123456789abc/master/vms/VM/VM.ovf - -pushd $d/12345678-1234-1234-1234-123456789abc/images/IMAGE - -# Test the disk .meta was created. -test -f VOL.meta - -# Test the disk file was created. -test -f VOL - -# Test that a qcow2 file with compat=1.1 was generated. -test "$(guestfish disk-format VOL)" = "qcow2" -qemu-img info VOL | grep 'compat: 1.1' - -popd - -# Compare resulting OVF -OVF="$d/12345678-1234-1234-1234-123456789abc/master/vms/VM/VM.ovf" - -RE_UUID='\<[0-9a-fA-F]\{8\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{12\}\>' - -# Filter variable strings -sed -i \ - -e "s/\('"$RE_UUID"'#UUID#[^<]*#DATE# output_mode := `Disk | "null" -> output_mode := `Null | "openstack" | "osp" | "rhosp" -> output_mode := `Openstack - | "ovirt" | "rhv" | "rhev" -> output_mode := `RHV - | "ovirt-upload" | "ovirt_upload" | "rhv-upload" | "rhv_upload" -> - output_mode := `RHV_Upload | "qemu" -> output_mode := `QEmu - | "vdsm" -> output_mode := `VDSM | s -> error (f_"unknown -o option: %s") s in @@ -245,7 +241,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 ("kubevirt|libvirt|local|null|openstack|qemu|rhv|rhv-upload|vdsm", set_output_mode), + [ S 'o' ], Getopt.String ("kubevirt|libvirt|local|null|openstack|qemu", set_output_mode), s_"Set output mode (default: libvirt)"; [ M"oa" ], Getopt.String ("sparse|preallocated", set_output_alloc), s_"Set output allocation mode"; @@ -283,18 +279,6 @@ let rec main () = s_"Same as ‘-io vddk-thumbprint=thumbprint’"; [ L"vddk-transports" ], Getopt.String ("transports", set_input_option_compat "vddk-transports"), s_"Same as ‘-io vddk-transports=transports’"; - [ L"vdsm-compat" ], Getopt.String ("0.10|1.1", set_output_option_compat "vdsm-compat"), - s_"Same as ‘-oo vdsm-compat=0.10|1.1’"; - [ L"vdsm-image-uuid" ], Getopt.String ("uuid", set_output_option_compat "vdsm-image-uuid"), - s_"Same as ‘-oo vdsm-image-uuid=uuid’"; - [ L"vdsm-vol-uuid" ], Getopt.String ("uuid", set_output_option_compat "vdsm-vol-uuid"), - s_"Same as ‘-oo vdsm-vol-uuid=uuid’"; - [ L"vdsm-vm-uuid" ], Getopt.String ("uuid", set_output_option_compat "vdsm-vm-uuid"), - s_"Same as ‘-oo vdsm-vm-uuid=uuid’"; - [ L"vdsm-ovf-output" ], Getopt.String ("dir", set_output_option_compat "vdsm-ovf-output"), - s_"Same as ‘-oo vdsm-ovf-output=dir’"; - [ L"vdsm-ovf-flavour" ], Getopt.String ("ovirt|rhvexp", set_output_option_compat "vdsm-ovf-flavour"), - s_"Same as ‘-oo vdsm-ovf-flavour=flavour’"; [ L"vmtype" ], Getopt.String ("-", vmtype_warning), s_"Ignored for backwards compatibility"; ] in @@ -306,9 +290,6 @@ let rec main () = virt-v2v -ic vpx://vcenter.example.com/Datacenter/esxi -os imported esx_guest -virt-v2v -ic vpx://vcenter.example.com/Datacenter/esxi esx_guest \ - -o rhv -os rhv.nfs:/export_domain --network ovirtmgmt - virt-v2v -i libvirtxml guest-domain.xml -o local -os /var/tmp virt-v2v -i disk disk.img -o local -os /var/tmp @@ -370,7 +351,6 @@ read the man page virt-v2v(1). pr "vcenter-https\n"; pr "vddk\n"; pr "colours-option\n"; - pr "vdsm-compat-option\n"; pr "io/oo\n"; pr "mac-option\n"; pr "bandwidth-option\n"; @@ -386,9 +366,6 @@ read the man page virt-v2v(1). pr "output:null\n"; pr "output:openstack\n"; pr "output:qemu\n"; - pr "output:rhv\n"; - pr "output:rhv-upload\n"; - pr "output:vdsm\n"; pr "convert:linux\n"; pr "convert:windows\n"; List.iter (pr "ovf:%s\n") Create_ovf.ovf_flavours; @@ -473,10 +450,7 @@ read the man page virt-v2v(1). | `Null -> (module Output_null.Null) | `QEmu -> (module Output_qemu.QEMU) | `Kubevirt -> (module Output_kubevirt.Kubevirt) - | `Openstack -> (module Output_openstack.Openstack) - | `RHV_Upload -> (module Output_rhv_upload.RHVUpload) - | `RHV -> (module Output_rhv.RHV) - | `VDSM -> (module Output_vdsm.VDSM) in + | `Openstack -> (module Output_openstack.Openstack) in let output_options = { Output.output_alloc = output_alloc; @@ -501,7 +475,6 @@ read the man page virt-v2v(1). *) let remove_serial_console = match output_mode with - | `RHV | `VDSM -> true | _ -> false in (* Get the conversion options. *)