From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 247B996E02 for ; Tue, 16 Apr 2024 15:19:49 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id C02151BAA5 for ; Tue, 16 Apr 2024 15:19:25 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Tue, 16 Apr 2024 15:19:19 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 851ED45141 for ; Tue, 16 Apr 2024 15:19:16 +0200 (CEST) From: Dominik Csapak To: pve-devel@lists.proxmox.com Date: Tue, 16 Apr 2024 15:18:54 +0200 Message-Id: <20240416131909.2867605-2-d.csapak@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240416131909.2867605-1-d.csapak@proxmox.com> References: <20240416131909.2867605-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.361 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LOTSOFHASH 0.25 Emails with lots of hash-like gibberish SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URI_NOVOWEL 0.5 URI hostname has long non-vowel sequence Subject: [pve-devel] [PATCH storage 1/9] copy OVF.pm from qemu-server X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Apr 2024 13:19:49 -0000 copies the OVF.pm and relevant ovf tests from qemu-server. We need it here, and it uses PVE::Storage already, and since there is no intermediary package/repository we could put it, it seems fitting in here. Signed-off-by: Dominik Csapak --- src/PVE/Storage/Makefile | 1 + src/PVE/Storage/OVF.pm | 242 ++++++++++++++++++ src/test/Makefile | 5 +- src/test/ovf_manifests/Win10-Liz-disk1.vmdk | Bin 0 -> 65536 bytes src/test/ovf_manifests/Win10-Liz.ovf | 142 ++++++++++ .../ovf_manifests/Win10-Liz_no_default_ns.ovf | 142 ++++++++++ .../ovf_manifests/Win_2008_R2_two-disks.ovf | 145 +++++++++++ src/test/ovf_manifests/disk1.vmdk | Bin 0 -> 65536 bytes src/test/ovf_manifests/disk2.vmdk | Bin 0 -> 65536 bytes src/test/run_ovf_tests.pl | 71 +++++ 10 files changed, 747 insertions(+), 1 deletion(-) create mode 100644 src/PVE/Storage/OVF.pm create mode 100644 src/test/ovf_manifests/Win10-Liz-disk1.vmdk create mode 100755 src/test/ovf_manifests/Win10-Liz.ovf create mode 100755 src/test/ovf_manifests/Win10-Liz_no_default_ns.ovf create mode 100755 src/test/ovf_manifests/Win_2008_R2_two-disks.ovf create mode 100644 src/test/ovf_manifests/disk1.vmdk create mode 100644 src/test/ovf_manifests/disk2.vmdk create mode 100755 src/test/run_ovf_tests.pl diff --git a/src/PVE/Storage/Makefile b/src/PVE/Storage/Makefile index d5cc942..2daa0da 100644 --- a/src/PVE/Storage/Makefile +++ b/src/PVE/Storage/Makefile @@ -14,6 +14,7 @@ SOURCES= \ PBSPlugin.pm \ BTRFSPlugin.pm \ LvmThinPlugin.pm \ + OVF.pm \ ESXiPlugin.pm .PHONY: install diff --git a/src/PVE/Storage/OVF.pm b/src/PVE/Storage/OVF.pm new file mode 100644 index 0000000..90ca453 --- /dev/null +++ b/src/PVE/Storage/OVF.pm @@ -0,0 +1,242 @@ +# Open Virtualization Format import routines +# https://www.dmtf.org/standards/ovf +package PVE::Storage::OVF; + +use strict; +use warnings; + +use XML::LibXML; +use File::Spec; +use File::Basename; +use Data::Dumper; +use Cwd 'realpath'; + +use PVE::Tools; +use PVE::Storage; + +# map OVF resources types to descriptive strings +# this will allow us to explore the xml tree without using magic numbers +# http://schemas.dmtf.org/wbem/cim-html/2/CIM_ResourceAllocationSettingData.html +my @resources = ( + { id => 1, dtmf_name => 'Other' }, + { id => 2, dtmf_name => 'Computer System' }, + { id => 3, dtmf_name => 'Processor' }, + { id => 4, dtmf_name => 'Memory' }, + { id => 5, dtmf_name => 'IDE Controller', pve_type => 'ide' }, + { id => 6, dtmf_name => 'Parallel SCSI HBA', pve_type => 'scsi' }, + { id => 7, dtmf_name => 'FC HBA' }, + { id => 8, dtmf_name => 'iSCSI HBA' }, + { id => 9, dtmf_name => 'IB HCA' }, + { id => 10, dtmf_name => 'Ethernet Adapter' }, + { id => 11, dtmf_name => 'Other Network Adapter' }, + { id => 12, dtmf_name => 'I/O Slot' }, + { id => 13, dtmf_name => 'I/O Device' }, + { id => 14, dtmf_name => 'Floppy Drive' }, + { id => 15, dtmf_name => 'CD Drive' }, + { id => 16, dtmf_name => 'DVD drive' }, + { id => 17, dtmf_name => 'Disk Drive' }, + { id => 18, dtmf_name => 'Tape Drive' }, + { id => 19, dtmf_name => 'Storage Extent' }, + { id => 20, dtmf_name => 'Other storage device', pve_type => 'sata'}, + { id => 21, dtmf_name => 'Serial port' }, + { id => 22, dtmf_name => 'Parallel port' }, + { id => 23, dtmf_name => 'USB Controller' }, + { id => 24, dtmf_name => 'Graphics controller' }, + { id => 25, dtmf_name => 'IEEE 1394 Controller' }, + { id => 26, dtmf_name => 'Partitionable Unit' }, + { id => 27, dtmf_name => 'Base Partitionable Unit' }, + { id => 28, dtmf_name => 'Power' }, + { id => 29, dtmf_name => 'Cooling Capacity' }, + { id => 30, dtmf_name => 'Ethernet Switch Port' }, + { id => 31, dtmf_name => 'Logical Disk' }, + { id => 32, dtmf_name => 'Storage Volume' }, + { id => 33, dtmf_name => 'Ethernet Connection' }, + { id => 34, dtmf_name => 'DMTF reserved' }, + { id => 35, dtmf_name => 'Vendor Reserved'} +); + +sub find_by { + my ($key, $param) = @_; + foreach my $resource (@resources) { + if ($resource->{$key} eq $param) { + return ($resource); + } + } + return; +} + +sub dtmf_name_to_id { + my ($dtmf_name) = @_; + my $found = find_by('dtmf_name', $dtmf_name); + if ($found) { + return $found->{id}; + } else { + return; + } +} + +sub id_to_pve { + my ($id) = @_; + my $resource = find_by('id', $id); + if ($resource) { + return $resource->{pve_type}; + } else { + return; + } +} + +# returns two references, $qm which holds qm.conf style key/values, and \@disks +sub parse_ovf { + my ($ovf, $debug) = @_; + + my $dom = XML::LibXML->load_xml(location => $ovf, no_blanks => 1); + + # register the xml namespaces in a xpath context object + # 'ovf' is the default namespace so it will prepended to each xml element + my $xpc = XML::LibXML::XPathContext->new($dom); + $xpc->registerNs('ovf', 'http://schemas.dmtf.org/ovf/envelope/1'); + $xpc->registerNs('rasd', 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData'); + $xpc->registerNs('vssd', 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData'); + + + # hash to save qm.conf parameters + my $qm; + + #array to save a disk list + my @disks; + + # easy xpath + # walk down the dom until we find the matching XML element + my $xpath_find_name = "/ovf:Envelope/ovf:VirtualSystem/ovf:Name"; + my $ovf_name = $xpc->findvalue($xpath_find_name); + + if ($ovf_name) { + # PVE::QemuServer::confdesc requires a valid DNS name + ($qm->{name} = $ovf_name) =~ s/[^a-zA-Z0-9\-\.]//g; + } else { + warn "warning: unable to parse the VM name in this OVF manifest, generating a default value\n"; + } + + # middle level xpath + # element[child] search the elements which have this [child] + my $processor_id = dtmf_name_to_id('Processor'); + my $xpath_find_vcpu_count = "/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType=${processor_id}]/rasd:VirtualQuantity"; + $qm->{'cores'} = $xpc->findvalue($xpath_find_vcpu_count); + + my $memory_id = dtmf_name_to_id('Memory'); + my $xpath_find_memory = ("/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType=${memory_id}]/rasd:VirtualQuantity"); + $qm->{'memory'} = $xpc->findvalue($xpath_find_memory); + + # middle level xpath + # here we expect multiple results, so we do not read the element value with + # findvalue() but store multiple elements with findnodes() + my $disk_id = dtmf_name_to_id('Disk Drive'); + my $xpath_find_disks="/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType=${disk_id}]"; + my @disk_items = $xpc->findnodes($xpath_find_disks); + + # disks metadata is split in four different xml elements: + # * as an Item node of type DiskDrive in the VirtualHardwareSection + # * as an Disk node in the DiskSection + # * as a File node in the References section + # * each Item node also holds a reference to its owning controller + # + # we iterate over the list of Item nodes of type disk drive, and for each item, + # find the corresponding Disk node, and File node and owning controller + # when all the nodes has been found out, we copy the relevant information to + # a $pve_disk hash ref, which we push to @disks; + + foreach my $item_node (@disk_items) { + + my $disk_node; + my $file_node; + my $controller_node; + my $pve_disk; + + print "disk item:\n", $item_node->toString(1), "\n" if $debug; + + # from Item, find corresponding Disk node + # here the dot means the search should start from the current element in dom + my $host_resource = $xpc->findvalue('rasd:HostResource', $item_node); + my $disk_section_path; + my $disk_id; + + # RFC 3986 "2.3. Unreserved Characters" + my $valid_uripath_chars = qr/[[:alnum:]]|[\-\._~]/; + + if ($host_resource =~ m|^ovf:/(${valid_uripath_chars}+)/(${valid_uripath_chars}+)$|) { + $disk_section_path = $1; + $disk_id = $2; + } else { + warn "invalid host ressource $host_resource, skipping\n"; + next; + } + printf "disk section path: $disk_section_path and disk id: $disk_id\n" if $debug; + + # tricky xpath + # @ means we filter the result query based on a the value of an item attribute ( @ = attribute) + # @ needs to be escaped to prevent Perl double quote interpolation + my $xpath_find_fileref = sprintf("/ovf:Envelope/ovf:DiskSection/\ +ovf:Disk[\@ovf:diskId='%s']/\@ovf:fileRef", $disk_id); + my $fileref = $xpc->findvalue($xpath_find_fileref); + + my $valid_url_chars = qr@${valid_uripath_chars}|/@; + if (!$fileref || $fileref !~ m/^${valid_url_chars}+$/) { + warn "invalid host ressource $host_resource, skipping\n"; + next; + } + + # from Disk Node, find corresponding filepath + my $xpath_find_filepath = sprintf("/ovf:Envelope/ovf:References/ovf:File[\@ovf:id='%s']/\@ovf:href", $fileref); + my $filepath = $xpc->findvalue($xpath_find_filepath); + if (!$filepath) { + warn "invalid file reference $fileref, skipping\n"; + next; + } + print "file path: $filepath\n" if $debug; + + # from Item, find owning Controller type + my $controller_id = $xpc->findvalue('rasd:Parent', $item_node); + my $xpath_find_parent_type = sprintf("/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/\ +ovf:Item[rasd:InstanceID='%s']/rasd:ResourceType", $controller_id); + my $controller_type = $xpc->findvalue($xpath_find_parent_type); + if (!$controller_type) { + warn "invalid or missing controller: $controller_type, skipping\n"; + next; + } + print "owning controller type: $controller_type\n" if $debug; + + # extract corresponding Controller node details + my $adress_on_controller = $xpc->findvalue('rasd:AddressOnParent', $item_node); + my $pve_disk_address = id_to_pve($controller_type) . $adress_on_controller; + + # resolve symlinks and relative path components + # and die if the diskimage is not somewhere under the $ovf path + my $ovf_dir = realpath(dirname(File::Spec->rel2abs($ovf))); + my $backing_file_path = realpath(join ('/', $ovf_dir, $filepath)); + if ($backing_file_path !~ /^\Q${ovf_dir}\E/) { + die "error parsing $filepath, are you using a symlink ?\n"; + } + + if (!-e $backing_file_path) { + die "error parsing $filepath, file seems not to exist at $backing_file_path\n"; + } + + ($backing_file_path) = $backing_file_path =~ m|^(/.*)|; # untaint + + my $virtual_size = PVE::Storage::file_size_info($backing_file_path); + die "error parsing $backing_file_path, cannot determine file size\n" + if !$virtual_size; + + $pve_disk = { + disk_address => $pve_disk_address, + backing_file => $backing_file_path, + virtual_size => $virtual_size + }; + push @disks, $pve_disk; + + } + + return {qm => $qm, disks => \@disks}; +} + +1; diff --git a/src/test/Makefile b/src/test/Makefile index c54b10f..12991da 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,6 @@ all: test -test: test_zfspoolplugin test_disklist test_bwlimit test_plugin +test: test_zfspoolplugin test_disklist test_bwlimit test_plugin test_ovf test_zfspoolplugin: run_test_zfspoolplugin.pl ./run_test_zfspoolplugin.pl @@ -13,3 +13,6 @@ test_bwlimit: run_bwlimit_tests.pl test_plugin: run_plugin_tests.pl ./run_plugin_tests.pl + +test_ovf: run_ovf_tests.pl + ./run_ovf_tests.pl diff --git a/src/test/ovf_manifests/Win10-Liz-disk1.vmdk b/src/test/ovf_manifests/Win10-Liz-disk1.vmdk new file mode 100644 index 0000000000000000000000000000000000000000..662354a3d1333a2f6c4364005e53bfe7cd8b9044 GIT binary patch literal 65536 zcmeIvy>HV%7zbeUF`dK)46s{U!a5_FoJCkDB zKRozW{5{ByIY=etVNVcI$B zY@^?CwTN|j)tg?;i)G&AZFqPqoW(5P2K~XUq>9sqVVe!!?y@Y;)^#k~TefEvd2_XU z^M@5mfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk4^iOdL%ftb z5g~`p!f^fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N p0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK;Zui`~%h>XmtPp literal 0 HcmV?d00001 diff --git a/src/test/ovf_manifests/Win10-Liz.ovf b/src/test/ovf_manifests/Win10-Liz.ovf new file mode 100755 index 0000000..bf4b41a --- /dev/null +++ b/src/test/ovf_manifests/Win10-Liz.ovf @@ -0,0 +1,142 @@ + + + + + + + + Virtual disk information + + + + The list of logical networks + + The bridged network + + + + A virtual machine + Win10-Liz + + The kind of installed guest operating system + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + Win10-Liz + vmx-11 + + + hertz * 10^6 + Number of Virtual CPUs + 4 virtual CPU(s) + 1 + 3 + 4 + + + byte * 2^20 + Memory Size + 6144MB of memory + 2 + 4 + 6144 + + + 0 + SATA Controller + sataController0 + 3 + vmware.sata.ahci + 20 + + + 0 + USB Controller (XHCI) + usb3 + 4 + vmware.usb.xhci + 23 + + + 0 + USB Controller (EHCI) + usb + 5 + vmware.usb.ehci + 23 + + + + 0 + SCSI Controller + scsiController0 + 6 + lsilogicsas + 6 + + + true + serial0 + 7 + 21 + + + + 0 + disk0 + ovf:/disk/vmdisk1 + 8 + 6 + 17 + + + 2 + true + bridged + E1000e ethernet adapter on "bridged" + ethernet0 + 9 + E1000e + 10 + + + + false + sound + 10 + vmware.soundcard.hdaudio + 1 + + + false + video + 11 + 24 + + + + false + vmci + 12 + vmware.vmci + 1 + + + 1 + false + cdrom0 + 13 + 3 + 15 + + + + + + + + + diff --git a/src/test/ovf_manifests/Win10-Liz_no_default_ns.ovf b/src/test/ovf_manifests/Win10-Liz_no_default_ns.ovf new file mode 100755 index 0000000..b93540f --- /dev/null +++ b/src/test/ovf_manifests/Win10-Liz_no_default_ns.ovf @@ -0,0 +1,142 @@ + + + + + + + + Virtual disk information + + + + The list of logical networks + + The bridged network + + + + A virtual machine + Win10-Liz + + The kind of installed guest operating system + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + Win10-Liz + vmx-11 + + + hertz * 10^6 + Number of Virtual CPUs + 4 virtual CPU(s) + 1 + 3 + 4 + + + byte * 2^20 + Memory Size + 6144MB of memory + 2 + 4 + 6144 + + + 0 + SATA Controller + sataController0 + 3 + vmware.sata.ahci + 20 + + + 0 + USB Controller (XHCI) + usb3 + 4 + vmware.usb.xhci + 23 + + + 0 + USB Controller (EHCI) + usb + 5 + vmware.usb.ehci + 23 + + + + 0 + SCSI Controller + scsiController0 + 6 + lsilogicsas + 6 + + + true + serial0 + 7 + 21 + + + + 0 + disk0 + ovf:/disk/vmdisk1 + 8 + 6 + 17 + + + 2 + true + bridged + E1000e ethernet adapter on "bridged" + ethernet0 + 9 + E1000e + 10 + + + + false + sound + 10 + vmware.soundcard.hdaudio + 1 + + + false + video + 11 + 24 + + + + false + vmci + 12 + vmware.vmci + 1 + + + 1 + false + cdrom0 + 13 + 3 + 15 + + + + + + + + + diff --git a/src/test/ovf_manifests/Win_2008_R2_two-disks.ovf b/src/test/ovf_manifests/Win_2008_R2_two-disks.ovf new file mode 100755 index 0000000..a563aab --- /dev/null +++ b/src/test/ovf_manifests/Win_2008_R2_two-disks.ovf @@ -0,0 +1,145 @@ + + + + + + + + + Virtual disk information + + + + + The list of logical networks + + The bridged network + + + + A virtual machine + Win_2008-R2x64 + + The kind of installed guest operating system + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + Win_2008-R2x64 + vmx-11 + + + hertz * 10^6 + Number of Virtual CPUs + 1 virtual CPU(s) + 1 + 3 + 1 + + + byte * 2^20 + Memory Size + 2048MB of memory + 2 + 4 + 2048 + + + 0 + SATA Controller + sataController0 + 3 + vmware.sata.ahci + 20 + + + 0 + USB Controller (EHCI) + usb + 4 + vmware.usb.ehci + 23 + + + + 0 + SCSI Controller + scsiController0 + 5 + lsilogicsas + 6 + + + true + serial0 + 6 + 21 + + + + 0 + disk0 + ovf:/disk/vmdisk1 + 7 + 5 + 17 + + + 1 + disk1 + ovf:/disk/vmdisk2 + 8 + 5 + 17 + + + 2 + true + bridged + E1000 ethernet adapter on "bridged" + ethernet0 + 9 + E1000 + 10 + + + + false + sound + 10 + vmware.soundcard.hdaudio + 1 + + + false + video + 11 + 24 + + + + false + vmci + 12 + vmware.vmci + 1 + + + 1 + false + cdrom0 + 13 + 3 + 15 + + + + + + + + + + diff --git a/src/test/ovf_manifests/disk1.vmdk b/src/test/ovf_manifests/disk1.vmdk new file mode 100644 index 0000000000000000000000000000000000000000..8660602343a1a955f9bcf2e6beaed99316dd8167 GIT binary patch literal 65536 zcmeIvy>HV%7zbeUF`dK)46sz*Sy|tuS*)j3xo%d~*K!`iCRTO1T8@X|%lB-2b2}Q2@{gmi&a1d=x<|K%7N%9q zn|Qfh$8m45TCV10Gb^W)c4ZxVA@tMpzfJp2S{y#m?iwzx)01@a>+{9rJna?j=ZAyM zqPW{FznsOxiSi~-&+HV%7zbeUF`dK)46s)ntf&y(cMe*SJh-aTX?eH9+& z#z!O2Psc@dn~q~OEsJ%%D!&!;7&fu2iq&#-6u$l#k8ZBB&%=0f64qH6mv#5(X4k^B zj9DEow(B_REmq6byr^fzbkeM>VlRY#diJkw-bwTQ2bx{O`BgehC%?a(PtMX_-hBS! zV6(_?yX6%pcd>%ZCj`_<*{eCa6d4SQYmC$1K;F1Lf} zc3v#=CU3(J2jMJcc^4cVA0$#W-ahT}R7ZdS0RjXF5Fl_M z@c!W5Edc@q2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U eAV7cs0RjXF5FkK+009C72oNAZfB=F2DR2*l=VfOA literal 0 HcmV?d00001 diff --git a/src/test/run_ovf_tests.pl b/src/test/run_ovf_tests.pl new file mode 100755 index 0000000..1ef78cc --- /dev/null +++ b/src/test/run_ovf_tests.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use lib qw(..); # prepend .. to @INC so we use the local version of PVE packages + +use FindBin '$Bin'; +use PVE::Storage::OVF; +use Test::More; + +use Data::Dumper; + +my $test_manifests = join ('/', $Bin, 'ovf_manifests'); + +print "parsing ovfs\n"; + +my $win2008 = eval { PVE::Storage::OVF::parse_ovf("$test_manifests/Win_2008_R2_two-disks.ovf") }; +if (my $err = $@) { + fail('parse win2008'); + warn("error: $err\n"); +} else { + ok('parse win2008'); +} +my $win10 = eval { PVE::Storage::OVF::parse_ovf("$test_manifests/Win10-Liz.ovf") }; +if (my $err = $@) { + fail('parse win10'); + warn("error: $err\n"); +} else { + ok('parse win10'); +} +my $win10noNs = eval { PVE::Storage::OVF::parse_ovf("$test_manifests/Win10-Liz_no_default_ns.ovf") }; +if (my $err = $@) { + fail("parse win10 no default rasd NS"); + warn("error: $err\n"); +} else { + ok('parse win10 no default rasd NS'); +} + +print "testing disks\n"; + +is($win2008->{disks}->[0]->{disk_address}, 'scsi0', 'multidisk vm has the correct first disk controller'); +is($win2008->{disks}->[0]->{backing_file}, "$test_manifests/disk1.vmdk", 'multidisk vm has the correct first disk backing device'); +is($win2008->{disks}->[0]->{virtual_size}, 2048, 'multidisk vm has the correct first disk size'); + +is($win2008->{disks}->[1]->{disk_address}, 'scsi1', 'multidisk vm has the correct second disk controller'); +is($win2008->{disks}->[1]->{backing_file}, "$test_manifests/disk2.vmdk", 'multidisk vm has the correct second disk backing device'); +is($win2008->{disks}->[1]->{virtual_size}, 2048, 'multidisk vm has the correct second disk size'); + +is($win10->{disks}->[0]->{disk_address}, 'scsi0', 'single disk vm has the correct disk controller'); +is($win10->{disks}->[0]->{backing_file}, "$test_manifests/Win10-Liz-disk1.vmdk", 'single disk vm has the correct disk backing device'); +is($win10->{disks}->[0]->{virtual_size}, 2048, 'single disk vm has the correct size'); + +is($win10noNs->{disks}->[0]->{disk_address}, 'scsi0', 'single disk vm (no default rasd NS) has the correct disk controller'); +is($win10noNs->{disks}->[0]->{backing_file}, "$test_manifests/Win10-Liz-disk1.vmdk", 'single disk vm (no default rasd NS) has the correct disk backing device'); +is($win10noNs->{disks}->[0]->{virtual_size}, 2048, 'single disk vm (no default rasd NS) has the correct size'); + +print "\ntesting vm.conf extraction\n"; + +is($win2008->{qm}->{name}, 'Win2008-R2x64', 'win2008 VM name is correct'); +is($win2008->{qm}->{memory}, '2048', 'win2008 VM memory is correct'); +is($win2008->{qm}->{cores}, '1', 'win2008 VM cores are correct'); + +is($win10->{qm}->{name}, 'Win10-Liz', 'win10 VM name is correct'); +is($win10->{qm}->{memory}, '6144', 'win10 VM memory is correct'); +is($win10->{qm}->{cores}, '4', 'win10 VM cores are correct'); + +is($win10noNs->{qm}->{name}, 'Win10-Liz', 'win10 VM (no default rasd NS) name is correct'); +is($win10noNs->{qm}->{memory}, '6144', 'win10 VM (no default rasd NS) memory is correct'); +is($win10noNs->{qm}->{cores}, '4', 'win10 VM (no default rasd NS) cores are correct'); + +done_testing(); -- 2.39.2