Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 1/9] Convert config file to XML, and translate networks/bridge for all connections
Previously, only the LibVirtXML connection translated network and bridge names in imported metadata. This change moves this functionality in Converter, making it available to LibVirt connections as well. At the same time, the format of the config file is switched to XML. The primary driver for this is that the allowable syntax of a foreign network/bridge name is not known. Rather than create a new format which deals with this, I have switched to an existing one. Note that this change doesn't update GuestOS's use of the config file. Until this is restored it is not possible to install software in a guest, and therefore not possible to convert a PV xen guest. --- lib/Sys/VirtV2V/Connection/LibVirtXML.pm | 73 +------- lib/Sys/VirtV2V/Converter.pm | 81 +++++++++- v2v/virt-v2v.conf | 89 ++++++---- v2v/virt-v2v.conf.pod | 280 +++++++++++++++++++----------- v2v/virt-v2v.pl | 29 ++-- 5 files changed, 345 insertions(+), 207 deletions(-) diff --git a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm index 6867a9b..5d0ebbc 100644 --- a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm @@ -39,7 +39,7 @@ Sys::VirtV2V::Connection::LibVirtXML - Read libvirt XML from a file use Sys::VirtV2V::Connection::LibVirtXML; - $conn = Sys::VirtV2V::Connection::LibVirtXML->new($config, $path); + $conn = Sys::VirtV2V::Connection::LibVirtXML->new($path); $dom = $conn->get_dom(); =head1 DESCRIPTION @@ -52,10 +52,9 @@ file. =over -=item new(config, path) +=item new(path) -Create a new LibVirtXML connection. Configuration for transforming the metadata -is taken from I<config>, and the metadata itself is read from I<path>. +Create a new LibVirtXML connection. The metadata itself is read from I<path>. =cut @@ -63,38 +62,13 @@ sub new { my $class = shift; - my ($config, $path) = @_; + my ($path) = @_; my %obj = (); my $self = \%obj; bless($self, $class); - if(defined($config)) { - my %bridges; - my %networks; - - $self->{bridges} = \%bridges; - $self->{networks} = \%networks; - - # Split bridges and networks into separate hashes - foreach my $directive (keys(%$config)) { - if($directive =~ /^bridge\.(.*)$/) { - $bridges{$1} = $config->{$directive}; - } - - elsif($directive =~ /^network\.(.*)$/) { - $networks{$1} = $config->{$directive}; - } - - else { - die(__x("WARNING: unknown configuration directive ". - "{directive} in {name} section.", - directive => $directive, name => 'libvirtxml')); - } - } - } - $self->_get_dom($path); # No transfer methods defined yet @@ -109,12 +83,9 @@ sub _get_dom # Open the input file my $xml; # Implicitly closed on function exit - if(!open($xml, '<', $self->{path})) { - print STDERR user_message - (__x("Failed to open {path}: {error}", - path => $self->{path}, error => $!)); - return undef; - } + open($xml, '<', $self->{path}) + or die(user_message(__x("Failed to open {path}: {error}", + path => $self->{path}, error => $!))); # Parse the input file my $parser = new XML::DOM::Parser; @@ -122,34 +93,8 @@ sub _get_dom eval { $dom = $parser->parse ($xml); }; # Display any parse errors - if ($@) { - print STDERR user_message - (__x("Unable to parse {path}: {error}", - path => $self->{path}, error => $@)); - return undef; - } - - # Rewrite bridge names - foreach my $bridge - ($dom->findnodes("/domain/devices/interface[\@type='bridge']/". - "source/\@bridge")) - { - my $name = $bridge->getNodeValue(); - if(exists($self->{bridges}->{$name})) { - $bridge->setNodeValue($self->{bridges}->{$name}); - } - } - - # Rewrite network names - foreach my $network - ($dom->findnodes("/domain/devices/interface[\@type='network']/". - "source/\@network")) - { - my $name = $network->getNodeValue(); - if(exists($self->{networks}->{$name})) { - $network->setNodeValue($self->{networks}->{$name}); - } - } + die(user_message(__x("Unable to parse {path}: {error}", + path => $self->{path}, error => $@))) if ($@); return $dom; } diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm index 81abb02..4b11efd 100644 --- a/lib/Sys/VirtV2V/Converter.pm +++ b/lib/Sys/VirtV2V/Converter.pm @@ -130,9 +130,10 @@ sub convert { my $class = shift; - my ($vmm, $guestos, $dom, $desc) = @_; + my ($vmm, $guestos, $config, $dom, $desc) = @_; carp("convert called without vmm argument") unless defined($vmm); carp("convert called without guestos argument") unless defined($guestos); + carp("convert called without config argument") unless defined($config); carp("convert called without dom argument") unless defined($dom); carp("convert called without desc argument") unless defined($desc); @@ -149,6 +150,9 @@ sub convert die(user_message(__"Unable to find a module to convert this guest")) unless (defined($guestcaps)); + # Map network names from config + _map_networks($dom, $config); + # Convert the metadata _convert_metadata($vmm, $dom, $desc, $guestcaps); @@ -469,6 +473,81 @@ sub _unconfigure_xen_metadata # /domain/bootloader_args } +sub _map_networks +{ + my ($dom, $config) = @_; + + # Iterate over interfaces + foreach my $if ($dom->findnodes('/domain/devices/interface')) + { + my $type = $if->getAttribute('type'); + + my $name; + if ($type eq 'bridge') { + ($name) = $if->findnodes('source/@bridge'); + } elsif ($type eq 'network') { + ($name) = $if->findnodes('source/@network'); + } else { + print STDERR user_message (__x("Unknown interface type {type} in ". + "domain XML: {domain}", + type => $type, + domain => $dom->toString())); + exit(1); + } + + _update_interface($if, $name, $type, $config); + } +} + +sub _update_interface +{ + my ($if, $oldname, $oldtype, $config) = @_; + + my $oldnameval = $oldname->getValue(); + my ($mapping) = $config->findnodes + ("/virt-v2v/network[\@type='$oldtype' and \@name='$oldnameval']". + "/network"); + + unless (defined($mapping)) { + print STDERR user_message(__x("No mapping found for '{type}' ". + "interface: {name}", + type => $oldtype, + name => $oldnameval)); + next; + } + + my $newtype = $mapping->getAttributeNode('type'); + $newtype &&= $newtype->getValue(); + my $newname = $mapping->getAttributeNode('name'); + $newname &&= $newname->getValue(); + + # Check type and name are defined for the mapping + unless (defined($newtype) && defined($newname)) { + print STDERR user_message(__x("WARNING: Invalid network ". + "mapping in config: {config}", + config => $mapping->toString())); + return; + } + + # Check type is something we recognise + unless ($newtype eq 'network' || $newtype eq 'bridge') { + print STDERR user_message(__x("WARNING: Unknown interface type ". + "{type} in network mapping: {config}", + type => $newtype, + config => $mapping->toString())); + } + + my ($source) = $if->findnodes('source'); + + # Replace @bridge or @network in the source element with the correct mapped + # attribute name and value + $source->removeAttributeNode($oldname); + $source->setAttribute($newtype, $newname); + + # Update the type of the interface + $if->setAttribute('type', $newtype); +} + =back =head1 COPYRIGHT diff --git a/v2v/virt-v2v.conf b/v2v/virt-v2v.conf index 86e0b02..7101e1e 100644 --- a/v2v/virt-v2v.conf +++ b/v2v/virt-v2v.conf @@ -1,35 +1,62 @@ -[aliases] -#### RHEL 5 -# Install a regular kernel in place of a xen kernel -rhel.5.kernel-xen=kernel -rhel.4.kernel-xenU=kernel +<virt-v2v> + <path-root>/var/lib/virt-v2v/software</path-root> + <iso-path>/var/lib/virt-v2v/transfer.iso</iso-path> -[files] -rhel.5.i686.kernel=/var/lib/virt-v2v/kernel-2.6.18-128.1.14.el5.i686.rpm -rhel.5.x86_64.kernel=/var/lib/virt-v2v/kernel-2.6.18-128.4.1.el5.x86_64.rpm + <!-- RHEL 5 + All of these RPMS are from RHEL 5.3, which was the first version of RHEL + 5 to support VirtIO --> + <app os='rhel' major='5' arch='i686' name='kernel'> + <path>rhel/5/kernel-2.6.18-128.el5.i686.rpm</path> + <dep>rhel/5/ecryptfs-utils-56-8.el5.i386.rpm</dep> + <dep>rhel/5/lvm2-2.02.40-6.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-1.02.28-2.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-event-1.02.28-2.el5.i386.rpm</dep> + </app> + <app os='rhel' major='5' arch='i686' name='kernel-PAE'> + <path>rhel/5/kernel-PAE-2.6.18-128.el5.i686.rpm</path> + <dep>rhel/5/ecryptfs-utils-56-8.el5.i386.rpm</dep> + <dep>rhel/5/lvm2-2.02.40-6.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-1.02.28-2.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-event-1.02.28-2.el5.i386.rpm</dep> + </app> + <app os='rhel' major='5' arch='x86_64' name='kernel'> + <path>rhel/5/kernel-2.6.18-128.el5.x86_64.rpm</path> + <dep>rhel/5/ecryptfs-utils-56-8.el5.x86_64.rpm</dep> + <dep>rhel/5/lvm2-2.02.40-6.el5.x86_64.rpm</dep> + <dep>rhel/5/device-mapper-1.02.28-2.el5.x86_64.rpm</dep> + <dep>rhel/5/device-mapper-event-1.02.28-2.el5.x86_64.rpm</dep> + </app> -# The RHEL 5.3 kernel conflicts with older versions of ecryptfs-utils -rhel.5.i386.ecryptfs-utils=/var/lib/virt-v2v/ecryptfs-utils-56-8.el5.i386.rpm + <!-- RHEL 4 + All of these RPMs are from RHEL 4.8, which was the first version of RHEL + 4 to support VirtIO --> + <app os='rhel' major='4' arch='i686' name='kernel'> + <path>rhel/4/kernel-2.6.9-89.EL.i686.rpm</path> + </app> + <app os='rhel' major='4' arch='i686' name='kernel-smp'> + <path>rhel/4/kernel-smp-2.6.9-89.EL.i686.rpm</path> + </app> + <app os='rhel' major='4' arch='i686' name='kernel-hugemem'> + <path>rhel/4/kernel-hugemem-2.6.9-89.EL.i686.rpm</path> + </app> + <app os='rhel' major='4' arch='x86_64' name='kernel'> + <path>rhel/4/kernel-2.6.9-89.EL.x86_64.rpm</path> + </app> + <app os='rhel' major='4' arch='x86_64' name='kernel-smp'> + <path>rhel/4/kernel-smp-2.6.9-89.EL.x86_64.rpm</path> + </app> + <app os='rhel' major='4' arch='x86_64' name='kernel-largesmp'> + <path>rhel/4/kernel-largesmp-2.6.9-89.EL.x86_64.rpm</path> + </app> -# The following userspace packages are required on RHEL 5 prior to RHEL 5.3 to -# suport virtio -rhel.5.i386.lvm2=/var/lib/virt-v2v/lvm2-2.02.40-6.el5.i386.rpm -rhel.5.i386.device-mapper=/var/lib/virt-v2v/device-mapper-1.02.28-2.el5.i386.rpm -rhel.5.i386.device-mapper-event=/var/lib/virt-v2v/device-mapper-event-1.02.28-2.el5.i386.rpm + <!-- Networks --> + <!-- The default Xen bridge name --> + <network type='bridge' name='xenbr1'> + <network type='network' name='default'/> + </network> -#### RHEL 4 -rhel.4.i686.kernel=/var/lib/virt-v2v/kernel-2.6.9-89.EL.i686.rpm -rhel.4.x86_64.kernel=/var/lib/virt-v2v/kernel-2.6.9-89.0.3.EL.x86_64.rpm - -[deps] -# Only update userspace on RHEL 5 prior to RHEL 5.3 -rhel.5.2.kernel=ecryptfs-utils lvm2 -rhel.5.1.kernel=ecryptfs-utils lvm2 -rhel.5.0.kernel=ecryptfs-utils lvm2 - -# RPM version dependencies -rhel.5.lvm2=device-mapper -rhel.5.device-mapper=device-mapper-event - -[libvirtxml] -bridge.xenbr1=virbr0 + <!-- The default ESX bridge name --> + <network type='bridge' name='VM Network'> + <network type='network' name='default'/> + </network> +</virt-v2v> diff --git a/v2v/virt-v2v.conf.pod b/v2v/virt-v2v.conf.pod index 7252e09..7c56875 100644 --- a/v2v/virt-v2v.conf.pod +++ b/v2v/virt-v2v.conf.pod @@ -8,162 +8,244 @@ virt-v2v.conf - configuration file for virt-v2v C<virt-v2v.conf> describes: +=over + =item * -software which can be installed by virt-v2v during the conversion process. +how to map virtual network interface connections when importing them from +another environment. =item * -how to rename networks and bridges when importing them from another environment. +software which can be installed by virt-v2v during the conversion process. -=head1 EXAMPLE +=back -The following is an example virt-v2v configuration file which is sufficient to -convert RHEL 5 guests to run on KVM with virtio drivers enabled: +=head1 FORMAT - [files] - rhel.5.i686.kernel=/var/lib/virt-v2v/kernel-2.6.18-128.1.el5.i686.rpm - rhel.5.x86_64.kernel=/var/lib/virt-v2v/kernel-2.6.18-128.4.1.el5.x86_64. +The configuration file is an XML document whose root element is +E<lt>virt-v2vE<gt>. -This section specifies i686 and x86_64 RHEL 5 kernel packages. +=head2 Mapping network interface connections - # The RHEL 5.3 kernel conflicts with older versions of ecryptfs-utils - rhel.5.i386.ecryptfs-utils=/var/lib/virt-v2v/ecryptfs-utils-56-8.el5.i38 +When importing a guest from a different machine and/or hypervisor, it is likely +that the name of the virtual interface its network devices were connected to +will change. For example, a typical Xen guest will be connected to a bridge +device called xenbrN. This bridge is created by Xen and will not exist locally +by default. - # The following userspace packages are required on RHEL 5 prior to RHEL - # 5.3 to suport virtio - rhel.5.i386.lvm2=/var/lib/virt-v2v/lvm2-2.02.40-6.el5.i386.rpm - rhel.5.i386.device-mapper=/var/lib/virt-v2v/device-mapper-1.02.28-2.el5. - rhel.5.i386.device-mapper-event=/var/lib/virt-v2v/device-mapper-event-1. +virt-v2v can change these on import to connect to an appropriate local +interface. The mapping is specified by the E<lt>networkE<gt> element, which +is a child of the root element. The configuration can specify any number of +E<lt>networkE<gt> elements. E<lt>networkE<gt> has 2 attributes: -This section specifies some additional userspace packages for i386 RHEL 5. See -below for how these can be used. +=over - [deps] - # Only update userspace on RHEL 5 prior to RHEL 5.3 - rhel.5.2.kernel=ecryptfs-utils lvm2 - rhel.5.1.kernel=ecryptfs-utils lvm2 - rhel.5.0.kernel=ecryptfs-utils lvm2 +=item type -This section specifies that when installing C<kernel> on RHEL 5.0, RHEL 5.1 or -RHEL 5.2, virt-v2v must also install C<ecryptfs-utils> and C<lvm2>. +type is either 'bridge', which specifies a bridge to a local interface, or +'network', which specifies a locally managed virtual network. For Xen and ESX +guests the source type will typically be 'bridge'. - # RPM version dependencies - rhel.5.lvm2=device-mapper - rhel.5.device-mapper=device-mapper-event +=item name -Dependencies can be specified to any depth. The above specifies that C<lvm2> -depends on C<device-mapper>, which in turn depends on C<device-mapper-event>. +name specifies the name of the given network or bridge. - [aliases] - # Install a regular kernel in place of a xen kernel - rhel.5.kernel-xen=kernel +=back -The above section specifies that if virt-v2v is looking for a kernel called -C<kernel-xen> on RHEL 5 it should instead look for a label called C<kernel>. +The mapping is specified by a nested E<lt>networkE<gt> element. - [libvirtxml] - bridge.xenbr1=virbr0 +The following example specifies that a guest interface which bridges to 'xenbr1' +should be change to connect to the local managed network called 'default': -The above section specifies that if a guest connects to a bridge on the host -called C<xenbr1>, the converted guest should instead connect to a bridge called -C<virbr0>. + <network type='bridge' name='xenbr1'> + <network type='network' name='default'/> + </network> -=head1 INSTALLING FILES +=head2 Specifying software to be installed -Because different guests may need different files to be installed to satisfy a -given requirement, files are installed by I<label> rather than by file name. -Labels are specified in the [files] section of the virt-v2v configuration file. +virt-v2v may have to install software in a guest during the conversion process +to ensure it boots. An example is replacing a Xen paravirtualised kernel with a +normal kernel. This software will be specific to the guest operating system. -When choosing which file to install, the requested label name will be considered -along with 4 aspects of the guest: +Software to be installed is specified in the E<lt>appE<gt> element, which is a +child of the root element. The configuration can specify any number of +E<lt>appE<gt> elements. E<lt>appE<gt> can have 5 attributes: =over -=item distro +=item name + +The symbolic name of the software virt-v2v is looking for. name is a mandatory +attribute. + +=item os -The distribution name discovered by L<Sys::Guestfs::Lib>, e.g. 'rhel'. +The name of the guest operating system, as returned by libguestfs. -=item major +=item major -The major version number of the distribution. +The major version name of the guest operating system, as returned by +libguestfs. =item minor -The minor version number of the distribution. +The minor version name of the guest operating system, as returned by libguestfs. =item arch -The required architecture of the file to be installed. +The guest architecture, as returned by libguestfs. =back -GuestOS will search for a matching label in the following order: +virt-v2v requests a file from the configuration by its symbolic name, searching +based on its additional attributes. If an attribute is missing from the +E<lt>appE<gt> element, it will match any value. If multiple E<lt>appE<gt> +elements would match a given search, virt-v2v will choose the most specific +match. Specifically, it searches in the following order: -1. distro.major.minor.arch.label -2. distro.major.minor.label -3. distro.major.arch.label -4. distro.major.label -5. distro.arch.label -6. distro.label +=over -So, if the guest is RHEL 5.3 x86_64 and the given label is 'udev', you can -specify any of the following: +=item * - [files] - rhel.5.3.x86_64.udev=<udev rpm> - rhel.5.3.udev=<udev rpm> - rhel.5.x86_64.udev=<udev rpm> - rhel.5.udev=<udev rpm> - rhel.x86_64.udev=<udev rpm> - rhel.udev=<udev rpm> +os, major, minor, arch -Which I<should> be specified depends on the applicability of the target file. In -this case it would be I<rhel.5.x86_64.udev>. +=item * -=head1 INSTALLING DEPENDENCIES +os, major, minor -virt-v2v requires that all necessary files are made available before it is -invoked. This includes dependencies of new files which are to be installed into -a guest. Dependencies must be specified manually in the [deps] section of the -virt-v2v configuration file. +=item * + +os, major, arch + +=item * + +os, major + +=item * + +os + +=back + +If virt-v2v doesn't find a matching E<lt>appE<gt>, it will quit with an error +describing what it was looking for. -Dependencies are defined on labels, and specify new labels. Labels are resolved -as described in L</INSTALLING FILES>. +The E<lt>appE<gt> element must contain a E<lt>pathE<gt> element, which specifies +the path to the software. It may also contain any number of E<lt>depE<gt> +elements, which specify the paths to dependencies of the application. -So, for example, to specify that when installing a new kernel on RHEL 5.2 x86_64 -you also need to install new versions of ecryptfs-utils and lvm2, add the -following: +virt-v2v will attempt to install dependencies first. A dependency will only be +installed if it is not already installed, or the installed version is older than +the specified version. - [deps] - rhel.5.2.kernel="ecryptfs-utils lvm2" +Paths given in both the E<lt>pathE<gt> and E<lt>depE<gt> must be absolute, +unless there is a top level E<lt>path-rootE<gt> element. If it exists, all +E<lt>pathE<gt> and E<lt>depE<gt> elements will be relative to +E<lt>path-rootE<gt>. -This will cause GuestOS to first resolve both labels ecryptfs-utils and lvm2 for -the current guest, then check that the requested package is both installed, and -at the same or a greater version number that the given package. If this is not -the case the package will be installed or upgraded. +virt-v2v passes software to the guest by creating an iso image and passing it to +the guest as a cd-rom drive. The path to this iso image must be specified in a +top level E<lt>iso-pathE<gt> element. -Dependencies can be specified recursively to any depth. +The following example specifies the location of 'kernel' for RHEL 5, all minor +versions, on i686: -=head1 ALIASES + <path-root>/var/lib/virt-v2v/software</path-root> + <iso-path>/var/lib/virt-v2v/transfer.iso</iso-path> -Aliases can be used to specify that when a particular label has been requested, -a different label should be used instead. Aliases are specified in the [aliases] -section of the virt-v2v configuration file. + <app os='rhel' major='5' arch='i686' name='kernel'> + <path>rhel/5/kernel-2.6.18-128.el5.i686.rpm</path> + <dep>rhel/5/ecryptfs-utils-56-8.el5.i386.rpm</dep> + <dep>rhel/5/lvm2-2.02.40-6.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-1.02.28-2.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-event-1.02.28-2.el5.i386.rpm</dep> + </app> -For example to specify that when looking for a replacement for 'kernel-xenU' on -RHEL 4, 'kernel' should be used instead, add the following: +The kernel can be found at +/var/lib/virt-v2v/software/rhel/5/kernel-2.6.18-128.el5.i686.rpm. It has 4 +dependencies, which will be installed if they are not present, or are too old. +All dependency paths are also relative to /var/lib/virt-v2v/software. virt-v2v +will create a transfer iso image containing all paths and dependencies at +/var/lib/virt-v2v/transfer.iso. - [aliases] - rhel.4.kernel-xenU=kernel +=head1 EXAMPLE -Aliases are resolved as described in L</INSTALLING FILES>. Thus a label can have -different aliases in different contexts. An alias will be used both when -installing a file, and when resolving its dependencies. +The following example is the default example configuration file included in the +virt-v2v distribution. The majority of the file specifies the locations of +replacement FV kernels for RHEL 4 and RHEL 5. These will be required when +converting Xen guests which use a PV kernel. + +It also specifies that guests using a bridge called either 'xenbr1' (the Xen +default) or 'VM Network' (the VMware ESX default) should be mapped to the local +managed network called 'default'. + + <virt-v2v> + <path-root>/var/lib/virt-v2v/software</path-root> + <iso-path>/var/lib/virt-v2v/transfer.iso</iso-path> + + <!-- RHEL 5 + All of these RPMS are from RHEL 5.3, which was the first version of RHEL + 5 to support VirtIO --> + <app os='rhel' major='5' arch='i686' name='kernel'> + <path>rhel/5/kernel-2.6.18-128.el5.i686.rpm</path> + <dep>rhel/5/ecryptfs-utils-56-8.el5.i386.rpm</dep> + <dep>rhel/5/lvm2-2.02.40-6.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-1.02.28-2.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-event-1.02.28-2.el5.i386.rpm</dep> + </app> + <app os='rhel' major='5' arch='i686' name='kernel-PAE'> + <path>rhel/5/kernel-PAE-2.6.18-128.el5.i686.rpm</path> + <dep>rhel/5/ecryptfs-utils-56-8.el5.i386.rpm</dep> + <dep>rhel/5/lvm2-2.02.40-6.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-1.02.28-2.el5.i386.rpm</dep> + <dep>rhel/5/device-mapper-event-1.02.28-2.el5.i386.rpm</dep> + </app> + <app os='rhel' major='5' arch='x86_64' name='kernel'> + <path>rhel/5/kernel-2.6.18-128.el5.x86_64.rpm</path> + <dep>rhel/5/ecryptfs-utils-56-8.el5.x86_64.rpm</dep> + <dep>rhel/5/lvm2-2.02.40-6.el5.x86_64.rpm</dep> + <dep>rhel/5/device-mapper-1.02.28-2.el5.x86_64.rpm</dep> + <dep>rhel/5/device-mapper-event-1.02.28-2.el5.x86_64.rpm</dep> + </app> + + <!-- RHEL 4 + All of these RPMs are from RHEL 4.8, which was the first version of RHEL + 4 to support VirtIO --> + <app os='rhel' major='4' arch='i686' name='kernel'> + <path>rhel/4/kernel-2.6.9-89.EL.i686.rpm</path> + </app> + <app os='rhel' major='4' arch='i686' name='kernel-smp'> + <path>rhel/4/kernel-smp-2.6.9-89.EL.i686.rpm</path> + </app> + <app os='rhel' major='4' arch='i686' name='kernel-hugemem'> + <path>rhel/4/kernel-hugemem-2.6.9-89.EL.i686.rpm</path> + </app> + <app os='rhel' major='4' arch='x86_64' name='kernel'> + <path>rhel/4/kernel-2.6.9-89.EL.x86_64.rpm</path> + </app> + <app os='rhel' major='4' arch='x86_64' name='kernel-smp'> + <path>rhel/4/kernel-smp-2.6.9-89.EL.x86_64.rpm</path> + </app> + <app os='rhel' major='4' arch='x86_64' name='kernel-largesmp'> + <path>rhel/4/kernel-largesmp-2.6.9-89.EL.x86_64.rpm</path> + </app> + + <!-- Networks --> + <!-- The default Xen bridge name --> + <network type='bridge' name='xenbr1'> + <network type='network' name='default'/> + </network> + + <!-- The default ESX bridge name --> + <network type='bridge' name='VM Network'> + <network type='network' name='default'/> + </network> + </virt-v2v> =head1 COPYRIGHT -Copyright (C) 2009 Red Hat Inc. +Copyright (C) 2009,2010 Red Hat Inc. =head1 SEE ALSO diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl index cd23514..b1516c3 100755 --- a/v2v/virt-v2v.pl +++ b/v2v/virt-v2v.pl @@ -212,17 +212,21 @@ GetOptions ("help|?" => sub { ) or pod2usage(2); # Read the config file if one was given -my $config = {}; +my $config; if(defined($config_file)) { - $config = Config::Tiny->read($config_file); + # Check we can access the config file + die(user_message(__x("Config file {path} doesn't exist", + path => $config_file))) unless (-e $config_file); - # Check we were able to read it - if(!defined($config)) { - print STDERR user_message(__x("Unable to parse {file}: {error}", - file => $config_file, - error => Config::Tiny->errstr)); - exit(1); - } + die(user_message(__x("Don't have permissions to read {path}", + path => $config_file))) unless (-r $config_file); + + eval { + $config = new XML::DOM::Parser->parsefile($config_file); + }; + + die(user_message(__x("Unable to parse config file {path}: {error}", + path => $config_file, error => $@))) if ($@); } # Connect to target libvirt @@ -246,7 +250,7 @@ eval { modulename => 'libvirtxml')); } - $conn = Sys::VirtV2V::Connection::LibVirtXML->new($config, $path); + $conn = Sys::VirtV2V::Connection::LibVirtXML->new($path); } elsif ($input_method eq "libvirt") { @@ -293,7 +297,8 @@ if ($@) { } # Configure GuestOS ([files] and [deps] sections) -Sys::VirtV2V::GuestOS->configure($config); +# Need to fix GuestOS's usage of config for installing applications +Sys::VirtV2V::GuestOS->configure({}); ############################################################################### @@ -316,7 +321,7 @@ my $os = inspect_guest($g); my $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $os); # Modify the guest and its metadata for the target hypervisor -Sys::VirtV2V::Converter->convert($vmm, $guestos, $dom, $os); +Sys::VirtV2V::Converter->convert($vmm, $guestos, $config, $dom, $os); $g->umount_all(); $g->sync(); -- 1.6.6
Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 2/9] Try hard to clean up on unclean shutdown
Set autosync on the libguestfs handle, install signal handlers for SIGINT and SIGQUIT which explicitly close the handle, and add an END { } block which closes the handle in virt-v2v.pl. Note that these measures still don't work when the user kills virt-v2v with Ctrl-C. We suppose this is because qemu is also receiving the SIGINT and shutting down before it can be shut down cleanly by libguestfs. However, the above changes should improve matters if this can be fixed. --- v2v/virt-v2v.pl | 24 ++++++++++++++++++++---- 1 files changed, 20 insertions(+), 4 deletions(-) diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl index b1516c3..cf78523 100755 --- a/v2v/virt-v2v.pl +++ b/v2v/virt-v2v.pl @@ -312,7 +312,10 @@ exit(1) unless(defined($dom)); my @storage = $conn->get_local_storage(); # Open a libguestfs handle on the guest's storage devices -my $g = get_guestfs_handle(@storage); +my $g = get_guestfs_handle(\@storage, $transferiso); + +$SIG{'INT'} = \&close_guest_handle; +$SIG{'QUIT'} = \&close_guest_handle; # Inspect the guest my $os = inspect_guest($g); @@ -323,16 +326,26 @@ my $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $os); # Modify the guest and its metadata for the target hypervisor Sys::VirtV2V::Converter->convert($vmm, $guestos, $config, $dom, $os); -$g->umount_all(); -$g->sync(); - $vmm->define_domain($dom->toString()); exit(0); +# We should always attempt to shut down the guest gracefully +END { + close_guest_handle(); +} + ############################################################################### ## Helper functions +sub close_guest_handle +{ + if (defined($g)) { + $g->umount_all(); + $g->sync(); + } +} + sub get_guestfs_handle { my $g = open_guest(\@_, rw => 1); @@ -343,6 +356,9 @@ sub get_guestfs_handle # Enable selinux in the guest $g->set_selinux(1); + # Enable autosync to defend against data corruption on unclean shutdown + $g->set_autosync(1); + $g->launch (); return $g; -- 1.6.6
Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 3/9] LibVirtXML: Fix errors introduced by 78f88208
dom and path weren't being stored in the newly constructed object. --- lib/Sys/VirtV2V/Connection/LibVirtXML.pm | 12 ++++-------- 1 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm index 5d0ebbc..874946a 100644 --- a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm @@ -64,8 +64,8 @@ sub new my ($path) = @_; - my %obj = (); - my $self = \%obj; + my $self = {}; + $self->{path} = $path; bless($self, $class); @@ -88,15 +88,11 @@ sub _get_dom path => $self->{path}, error => $!))); # Parse the input file - my $parser = new XML::DOM::Parser; - my $dom; - eval { $dom = $parser->parse ($xml); }; + eval { $self->{dom} = new XML::DOM::Parser->parse ($xml); }; # Display any parse errors - die(user_message(__x("Unable to parse {path}: {error}", + die(user_message(__x("Unable to parse domain from file {path}: {error}", path => $self->{path}, error => $@))) if ($@); - - return $dom; } =back -- 1.6.6
Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 4/9] Converter: Remove disk driver elements other than 'qemu'
QEMU only currently supports the qemu storage driver in libvirt. Remove any other driver element. --- lib/Sys/VirtV2V/Converter.pm | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm index 4b11efd..edc6589 100644 --- a/lib/Sys/VirtV2V/Converter.pm +++ b/lib/Sys/VirtV2V/Converter.pm @@ -436,6 +436,13 @@ sub _unconfigure_hvs $emulator->getParent()->removeChild($emulator); } + # Remove any disk driver element other than 'qemu' + foreach my $driver + ($dom->findnodes('/domain/devices/disk/driver[@name != \'qemu\']')) + { + $driver->getParentNode()->removeChild($driver); + } + _unconfigure_xen_metadata($dom, $default_dom); } -- 1.6.6
Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 5/9] Fix application installation by GuestOS
Rewrite the code to create the transfer ISO to use the new XML config file format, and move it out of GuestOS in to virt-v2v.pl --- lib/Sys/VirtV2V/GuestOS.pm | 217 +++++++++++++++------------- lib/Sys/VirtV2V/GuestOS/RedHat.pm | 294 ++++++++++++++++--------------------- v2v/virt-v2v.pl | 94 +++++++++++- 3 files changed, 328 insertions(+), 277 deletions(-) diff --git a/lib/Sys/VirtV2V/GuestOS.pm b/lib/Sys/VirtV2V/GuestOS.pm index 1db7590..539659e 100644 --- a/lib/Sys/VirtV2V/GuestOS.pm +++ b/lib/Sys/VirtV2V/GuestOS.pm @@ -43,7 +43,7 @@ Sys::VirtV2V::GuestOS - Manipulate and query a Guest OS use Sys::VirtV2V::GuestOS; - $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $desc); + $guestos = Sys::VirtV2V::GuestOS->new($g, $desc, $dom, $config); =head1 DESCRIPTION @@ -57,25 +57,11 @@ implements methods to access backends. Sys::VirtV2V::GuestOS uses L<Module::Pluggable> to automatically discover backends under Sys::VirtV2V::GuestOS. -=cut - -# A map of file labels to their paths relative to the transfer device -my %files; - -# A map of file labels to their dependencies -my %deps; - -# A map of file labels aliases -my %aliases; - -# The path (on the host) to the transfer iso -my $transferiso; - =head1 METHODS =over -=item instantiate(g, desc) +=item new(g, desc, dom, config) Instantiate a GuestOS object capable of manipulating the target OS. @@ -89,123 +75,162 @@ A L<Sys::Guestfs> handle. An OS description created by L<Sys::Guestfs::Lib>. +=item dom + +An XML::DOM object containing the guest's libvirt domain XML prior to +conversion. + +=item config + +An XML::DOM object containing the virt-v2v configuration. + =back -Returns a capable Sys::VirtV2V::GuestOS backend if one is found. +Returns a capable Sys::VirtV2V::GuestOS if one is found. Returns undef otherwise. =cut -sub instantiate +sub new { my $class = shift; - my ($g, $desc) = @_; - defined($g) or carp("get_instance called without g argument"); - defined($desc) or carp("get_instance called without desc argument"); + my ($g, $desc, $dom, $config) = @_; + defined($g) or carp("instantiate called without g argument"); + defined($desc) or carp("instantiate called without desc argument"); + defined($dom) or carp("instantiate called without dom argument"); + defined($config) or carp("instantiate called without config argument"); + + my $self = {}; + + $self->{g} = $g; + $self->{desc} = $desc; + $self->{dom} = $dom; + $self->{config} = $config; foreach my $module ($class->modules()) { - return $module->new($g, $desc, \%files, \%deps, \%aliases) - if($module->can_handle($desc)); + return $module->new($self) + if($module->can_handle($desc)); } return undef; } -=item configure(config) +=item get_ncpus -=over +Return the number of CPUS which are available to this guest -=item config +=cut -The parsed virt-v2v config file, as returned by Config::Tiny. +sub get_ncpus +{ + my $self = shift; -=back + my ($ncpus) = $self->{dom}->findnodes('/domain/vcpu/text()'); + if (defined($ncpus)) { + return $ncpus->getData(); + } else { + return 1; + } +} + +=item get_memory_kb -Read the [files], [deps] and [aliases] sections of the virt-v2v config file. -Create the transfer iso from the contents of [files]. +Return the amount of memory, in KB, which is available to this guest =cut -sub configure +sub get_memory_kb { - my $class = shift; + my $self = shift; - my $config = shift; + my ($mem_kb) = $self->{dom}->findnodes('/domain/memory/text()'); - carp("configure called without config argument") unless(defined($config)); + return $mem_kb->getData(); +} - # Lookup the [files] config section - my $files_conf = $config->{files}; +=item match_app - # Do nothing if there is no [files] config section - return unless(defined($files_conf)); +Return a matching app entry from the virt-v2v configuration. The entry is +returned as a hashref containing 2 entries. I<path> contains the path to the +application itself. I<deps> contains an arrayref containing the paths of all the +app's listed dependencies. - # A hash, whose labels are filenames to be added to the transfer iso. We use - # a hash here to remove duplicates. - my %paths = (); - foreach my $label (keys(%$files_conf)) { - my $path = $files_conf->{$label}; +=cut - unless(-f $path && -r $path) { - print STDERR user_message(__x("WARNING: unable to access {path}.", - path => $path)); - next; - } +sub match_app +{ + my $self = shift; - $paths{$path} = 1; + my ($name, $arch) = @_; - # As transfer directory hierarchy is flat, remove all directory - # components from paths - my (undef, undef, $filename) = File::Spec->splitpath($path); - $files{$label} = $filename; - } + my $config = $self->{config}; - # Do nothing if there are no files defined - return if(keys(%paths) == 0); - - $transferiso = File::Temp->new(UNLINK => 1, SUFFIX => '.iso'); - my $eh = Sys::VirtV2V::ExecHelper->run - ('mkisofs', '-o', $transferiso, '-r', '-J', - '-V', '__virt-v2v_transfer__', keys(%paths)); - if($eh->status() != 0) { - print STDERR user_message(__x("Failed to create transfer iso. Command ". - "output was:\n{output}", - output => $eh->output())); - } + my $desc = $self->{desc}; + my $distro = $desc->{distro}; + my $major = $desc->{major_version}; + my $minor = $desc->{minor_version}; + + # Check we've got at least a distro from OS detection + die(user_message(__"Didn't detect OS distribution")) + unless (defined($distro)); + + # Create a list of xpath queries against the config which look for a + # matching <app> config entry in descending order of specificity - # Populate deps from the [deps] config section - my $deps_conf = $config->{deps}; + my $prefix = "/virt-v2v/app[\@os='$distro' and \@name='$name'"; - if(defined($deps_conf)) { - # Copy the deps_conf hash into %deps - foreach my $label (keys(%$deps_conf)) { - $deps{$label} = $deps_conf->{$label}; + my @queries; + if (defined($major)) { + if (defined($minor)) { + push(@queries, $prefix." and \@major='$major' ". + "and \@minor='$minor' and \@arch='$arch']"); + push(@queries, $prefix." and \@major='$major' ". + "and \@minor='$minor']"); } + + push(@queries, $prefix." and \@major='$major' and \@arch='$arch']"); + push(@queries, $prefix." and \@major='$major']"); } - # Populate aliases from the [aliases] config section - my $aliases_conf = $config->{aliases}; + push(@queries, $prefix." and \@arch='$arch']"); + push(@queries, $prefix."]"); - if(defined($aliases_conf)) { - # Copy the aliases_conf hash into %aliases - foreach my $label (keys(%$aliases_conf)) { - $aliases{$label} = $aliases_conf->{$label}; - } + # Use the results of the first query which returns a result + my $app; + foreach my $query (@queries) { + ($app) = $config->findnodes($query); + last if (defined($app)); } -} -=item get_transfer_iso + unless (defined($app)) { + my $search = "distro='$distro' name='$name'"; + $search .= " major='$major'" if (defined($major)); + $search .= " minor='$minor'" if (defined($minor)); + $search .= " arch='$arch'"; -Return the path (on the host) to the transfer iso image. L</configure> must have -been called first. + die(user_message(__x("No app in config matches {search}", + search => $search))); + } -=cut + my %app; + my ($path) = $app->findnodes('path/text()'); + die(user_message(__x("app entry in config doesn't contain a path: {xml}", + xml => $app->toString()))) unless (defined($path)); + $path = $path->getData(); -sub get_transfer_iso -{ - return $transferiso; + my @deps; + foreach my $dep ($app->findnodes('dep/text()')) { + push(@deps, $dep->getData()); + } + + # Return a hash containing the application path and its dependencies + my %ret; + $ret{path} = $path; + $ret{deps} = \@deps; + + return \%ret; } =back @@ -242,21 +267,15 @@ A L<Sys::Guestfs> handle. An OS description created by L<Sys::Guestfs::Lib>. -=item files - -A hash containing 'label => filename' mappings. These mappings are consulted -when a guest needs to install a specific application. +=item dom -=item deps +A parsed XML::DOM containing the libvirt domain XML for this guest prior to any +conversion. -A hash containing 'label => C<space separated dependency list>'. The -dependencies are given as labels rather than specific files. This is used to -install dependencies when installing an application in the guest. - -=item aliases +=item config -A hack containing 'label => alias'. Aliases are given as labels rather than -specific files. This is used to substitute packages during installation. +A parsed XML::DOM containing the virt-v2v configuration, or undef if there is +no config. =back diff --git a/lib/Sys/VirtV2V/GuestOS/RedHat.pm b/lib/Sys/VirtV2V/GuestOS/RedHat.pm index 920eea2..d6abe9b 100644 --- a/lib/Sys/VirtV2V/GuestOS/RedHat.pm +++ b/lib/Sys/VirtV2V/GuestOS/RedHat.pm @@ -17,9 +17,13 @@ package Sys::VirtV2V::GuestOS::RedHat; +our @ISA = ('Sys::VirtV2V::GuestOS'); + use strict; use warnings; +use File::Spec; + use Sys::Guestfs::Lib qw(inspect_linux_kernel); use Sys::VirtV2V::UserMessage qw(user_message); @@ -65,7 +69,7 @@ sub can_handle return ($desc->{os} eq 'linux') && ($desc->{package_format} eq 'rpm'); } -=item Sys::VirtV2V::GuestOS::RedHat->new(g, desc, files, deps, aliases) +=item Sys::VirtV2V::GuestOS::RedHat->new(self) See BACKEND INTERFACE in L<Sys::VirtV2V::GuestOS> for details. @@ -75,27 +79,9 @@ sub new { my $class = shift; - my $self = {}; - - # Guest handle - my $g = $self->{g} = shift; - carp("new called without guest handle") unless defined($g); - - # Guest description - $self->{desc} = shift; - carp("new called without guest description") unless defined($self->{desc}); - - # Guest file map - $self->{files} = shift; - carp("new called without files description") unless defined($self->{files}); - - # Guest dependency map - $self->{deps} = shift; - carp("new called without dependencies") unless defined($self->{deps}); - - # Guest alias map - $self->{aliases} = shift; - carp("new called without aliases") unless defined($self->{aliases}); + # Self object + my $self = shift; + carp("new called without self object") unless defined($self); bless($self, $class); @@ -475,32 +461,113 @@ sub add_kernel my ($kernel_pkg, $kernel_arch) = $self->_discover_kernel(); - # Install the kernel's dependencies - $self->_install_rpms(1, $self->_resolve_deps($kernel_pkg)); + # If the guest is using a Xen PV kernel, choose an appropriate normal kernel + # replacement + if ($kernel_pkg eq "kernel-xen" || $kernel_pkg eq "kernel-xenU") { + my $desc = $self->{desc}; + + # Make an informed choice about a replacement kernel for distros we know + # about + + # RHEL 5 + if ($desc->{distro} eq 'rhel' && $desc->{major_version} eq '5') { + if ($kernel_arch eq 'i686') { + # XXX: This assumes that PAE will be available in the + # hypervisor. While this is almost certainly true, it's + # theoretically possible that it isn't. The information we need + # is available in the capabilities XML. + # If PAE isn't available, we should choose 'kernel'. + $kernel_pkg = 'kernel-PAE'; + } + + # There's only 1 kernel package on RHEL 5 x86_64 + else { + $kernel_pkg = 'kernel'; + } + } + + # RHEL 4 + elsif ($desc->{distro} eq 'rhel' && $desc->{major_version} eq '4') { + my $ncpus = $self->get_ncpus(); + + if ($kernel_arch eq 'i686') { + # If the guest has > 10G RAM, give it a hugemem kernel + if ($self->get_memory_kb() > 10 * 1024 * 1024) { + $kernel_pkg = 'kernel-hugemem'; + } + + # SMP kernel for guests with >1 CPU + elsif ($ncpus > 1) { + $kernel_pkg = 'kernel-smp'; + } + + else { + $kernel_pkg = 'kernel'; + } + } + + else { + if ($ncpus > 8) { + $kernel_pkg = 'kernel-largesmp'; + } + + elsif ($ncpus > 1) { + $kernel_pkg = 'kernel-smp'; + } + + else { + $kernel_pkg = 'kernel'; + } + } + } - my $filename; + # RHEL 3 didn't have a xen kernel + + # XXX: Could do with a history of Fedora kernels in here + + # For other distros, be conservative and just return 'kernel' + else { + $kernel_pkg = 'kernel'; + } + } + + my $app; eval { - # Get a matching rpm - $filename = $self->_match_file($kernel_pkg, $kernel_arch); + $app = $self->match_app($kernel_pkg, $kernel_arch); }; - # Return undef if we didn't find a kernel + if ($@) { + print STDERR $@; + return undef; + } + + my $path = $app->{path}; + + my @install; + # Install any kernel dependencies which aren't already installed + foreach my $dep (@{$app->{deps}}) { + push(@install, $dep) unless($self->_is_installed($dep)); + } + $self->_install_rpms(1, @install); + return undef if($@); # Inspect the rpm to work out what kernel version it contains my $version; my $g = $self->{g}; - foreach my $file ($g->command_lines(["rpm", "-qlp", $filename])) { + foreach my $file ($g->command_lines + (["rpm", "-qlp", $self->_transfer_path($path)])) + { if($file =~ m{^/boot/vmlinuz-(.*)$}) { $version = $1; last; } } - die(user_message(__x("{filename} doesn't contain a valid kernel", - filename => $filename))) if(!defined($version)); + die(user_message(__x("{path} doesn't contain a valid kernel", + path => $path))) if(!defined($version)); - $self->_install_rpms(0, ($filename)); + $self->_install_rpms(0, ($path)); # Make augeas reload so it'll find the new kernel $g->aug_load(); @@ -508,7 +575,7 @@ sub add_kernel return $version; } -# Inspect the guest description to work out what kernel should be installed. +# Inspect the guest description to work out what kernel package is in use # Returns ($kernel_pkg, $kernel_arch) sub _discover_kernel { @@ -602,63 +669,21 @@ sub add_application my $user_arch = $self->{desc}->{arch}; - # Get the rpm for this label - my $rpm = $self->_match_file($label, $user_arch); + my $app = $self->match_app($label, $user_arch); # Nothing to do if it's already installed - return if(_is_installed($rpm)); + return if($self->_is_installed($app->{path})); - my @install = ($rpm); + my @install = ($app->{path}); - # Add the dependencies to the install set - push(@install, $self->_resolve_deps($label)); + # Add any dependencies which aren't already installed to the install set + foreach my $dep (@{$app->{deps}}) { + push(@install, $dep) unless ($self->_is_installed($dep)); + } $self->_install_rpms(1, @install); } -# Return a list of dependencies which must be installed before $label can be -# installed. The list contains paths of rpm files. It does not contain the rpm -# for $label itself. This is so _resolve_deps can be used to install kernel -# dependencies with -U before the kernel itself is installed with -i. -sub _resolve_deps -{ - my $self = shift; - - my ($label, @path) = @_; - - my $user_arch = $self->{desc}->{arch}; - - # Check for an alias for $label - $label = $self->_resolve_alias($label, $user_arch); - - # Check that the dependency path doesn't include the given label. If it - # does, that's a dependency loop. - if(grep(/\Q$label\E/, @path) > 0) { - die(user_message(__x("Found dependency loop installing {label}: {path}", - label => $label, path => join(' ', @path)))); - } - push(@path, $label); - - my $g = $self->{g}; - - my @depfiles = (); - - # Find dependencies for $label - foreach my $dep ($self->_match_deps($label, $user_arch)) { - my $rpm = $self->_match_file($dep, $user_arch); - - # Don't add the dependency if it's already installed - next if($self->_is_installed($rpm)); - - # Add the dependency - push(@depfiles, $rpm); - - # Recursively add dependencies - push(@depfiles, $self->_resolve_deps($dep, @path)); - } - - return @depfiles; -} # Return 1 if the requested rpm, or a newer version, is installed # Return 0 otherwise @@ -669,6 +694,8 @@ sub _is_installed my $g = $self->{g}; + $rpm = $self->_transfer_path($rpm); + # Get NEVRA for the rpm to be installed my $nevra = $g->command(['rpm', '-qp', '--qf', '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}', @@ -828,94 +855,6 @@ sub get_application_owner die($@) if($@); } -# Lookup a guest specific match for the given label -sub _match -{ - my $self = shift; - my ($object, $label, $arch, $hash) = @_; - - my $desc = $self->{desc}; - my $distro = $desc->{distro}; - my $major = $desc->{major_version}; - my $minor = $desc->{minor_version}; - - if(values(%$hash) > 0) { - # Search for a matching entry in the file map, in descending order of - # specificity - for my $name ("$distro.$major.$minor.$arch.$label", - "$distro.$major.$minor.$label", - "$distro.$major.$arch.$label", - "$distro.$major.$label", - "$distro.$arch.$label", - "$distro.$label") { - return $name if(defined($hash->{$name})); - } - } - - die(user_message(__x("No {object} given matching {label}", - object => $object, - label => "$distro.$major.$minor.$arch.$label"))); -} - -# Return the path to an rpm for <label>.<arch> -# Dies if no match is found -sub _match_file -{ - my $self = shift; - my ($label, $arch) = @_; - - # Check for an alias for $label - $label = $self->_resolve_alias($label, $arch); - - my $files = $self->{files}; - - my $name = $self->_match(__"file", $label, $arch, $files); - - # Ensure that whatever file is returned is accessible - $self->_ensure_transfer_mounted(); - - return $self->{transfer_mount}.'/'.$files->{$name}; -} - -# Look for an alias for this label -sub _resolve_alias -{ - my $self = shift; - my ($label, $arch) = @_; - - my $aliases = $self->{aliases}; - - my $alias; - eval { - $alias = $self->_match(__"alias", $label, $arch, $aliases); - }; - - return $aliases->{$alias} if(defined($alias)); - return $label; -} - -# Return a list of labels listed as dependencies of the given label. -# Returns an empty list if no dependencies were specified. -sub _match_deps -{ - my $self = shift; - my ($label, $arch) = @_; - - my $deps = $self->{deps}; - - my $name; - eval { - $name = $self->_match(__"dependencies", $label, $arch, $deps); - }; - - # Return an empty list if there were no dependencies defined - if($@) { - return (); - } else { - return split(/\s+/, $deps->{$name}); - } -} - # Install a set of rpms sub _install_rpms { @@ -926,6 +865,9 @@ sub _install_rpms # Nothing to do if we got an empty set return if(scalar(@rpms) == 0); + # All paths are relative to the transfer mount. Need to make them absolute. + @rpms = map { $_ = $self->_transfer_path($_) } @rpms; + my $g = $self->{g}; eval { $g->command(['rpm', $upgrade == 1 ? '-U' : '-i', @rpms]); @@ -935,6 +877,18 @@ sub _install_rpms die($@) if($@); } +# Get full, local path of a file on the transfer mount +sub _transfer_path +{ + my $self = shift; + + my ($path) = @_; + + $self->_ensure_transfer_mounted(); + + return File::Spec->catfile($self->{transfer_mount}, $path); +} + # Ensure that the transfer device is mounted. If not, mount it. sub _ensure_transfer_mounted { diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl index cf78523..a0559e9 100755 --- a/v2v/virt-v2v.pl +++ b/v2v/virt-v2v.pl @@ -22,7 +22,9 @@ use strict; use Pod::Usage; use Getopt::Long; #use Data::Dumper; -use Config::Tiny; +use File::Spec; +use File::stat; + use Locale::TextDomain 'virt-v2v'; use Sys::Guestfs; @@ -31,10 +33,11 @@ use Sys::Guestfs::Lib qw(open_guest get_partitions inspect_all_partitions inspect_in_detail); use Sys::VirtV2V; -use Sys::VirtV2V::GuestOS; use Sys::VirtV2V::Converter; use Sys::VirtV2V::Connection::LibVirt; use Sys::VirtV2V::Connection::LibVirtXML; +use Sys::VirtV2V::ExecHelper; +use Sys::VirtV2V::GuestOS; use Sys::VirtV2V::UserMessage qw(user_message); =encoding utf8 @@ -296,10 +299,6 @@ if ($@) { exit(1); } -# Configure GuestOS ([files] and [deps] sections) -# Need to fix GuestOS's usage of config for installing applications -Sys::VirtV2V::GuestOS->configure({}); - ############################################################################### ## Start of processing @@ -311,6 +310,9 @@ exit(1) unless(defined($dom)); # Get a list of the guest's transfered storage devices my @storage = $conn->get_local_storage(); +# Create the transfer iso if required +my $transferiso = get_transfer_iso($config, $config_file); + # Open a libguestfs handle on the guest's storage devices my $g = get_guestfs_handle(\@storage, $transferiso); @@ -321,7 +323,7 @@ $SIG{'QUIT'} = \&close_guest_handle; my $os = inspect_guest($g); # Instantiate a GuestOS instance to manipulate the guest -my $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $os); +my $guestos = Sys::VirtV2V::GuestOS->new($g, $os, $dom, $config); # Modify the guest and its metadata for the target hypervisor Sys::VirtV2V::Converter->convert($vmm, $guestos, $config, $dom, $os); @@ -346,9 +348,85 @@ sub close_guest_handle } } +sub get_transfer_iso +{ + my ($config, $config_file) = @_; + + # Nothing to do if there's no config + return undef unless (defined($config)); + + # path-root doesn't have to be defined + my ($root) = $config->findnodes('/virt-v2v/path-root/text()'); + $root = $root->getData() if (defined($root)); + + # Construct a list of path arguments to mkisofs from paths referenced in the + # config file + # We actually use a hash here to avoid duplicates + my %path_args; + foreach my $path ($config->findnodes('/virt-v2v/app/path/text() | '. + '/virt-v2v/app/dep/text()')) { + $path = $path->getData(); + + # Get the absolute path if iso-root was defined + my $abs; + if (defined($root)) { + $abs = File::Spec->catfile($root, $path); + } else { + $abs = $path; + } + + # Check the referenced path is accessible + die(user_message(__x("Unable to access {path} referenced in ". + "the config file", + path => $path))) unless (-r $abs); + + $path_args{"$path=$abs"} = 1; + } + + # Nothing further to do if there are no paths + return if (keys(%path_args) == 0); + + # Get the path of the transfer iso + my ($iso_path) = $config->findnodes('/virt-v2v/iso-path/text()'); + + # We need this + die(user_message(__"<iso-path> must be specified in the configuration ". + "file")) unless (defined($iso_path)); + $iso_path = $iso_path->getData(); + + # Check that the transfer iso exists, and is newer than the config file + if (-e $iso_path) { + my $iso_st = stat($iso_path) + or die(user_message(__x("Unable to stat iso file {path}: {error}", + path => $iso_path, error => $!))); + + my $config_st = stat($config_file) + or die(user_message(__x("Unable to stat config file {path}: ". + "{error}", + path => $config_file, error => $!))); + + # Don't need to re-create if the iso file is newer than the config file + return $iso_path if ($iso_st->mtime > $config_st->mtime); + } + + # Re-create the transfer iso + my $eh = Sys::VirtV2V::ExecHelper->run + ('mkisofs', '-o', $iso_path, + '-r', '-J', + '-V', '__virt-v2v_transfer__', + '-graft-points', keys(%path_args)); + die(user_message(__x("Failed to create transfer iso. ". + "Command output was:\n{output}", + output => $eh->output()))) unless ($eh->status() == 0); + + return $iso_path; +} + sub get_guestfs_handle { - my $g = open_guest(\@_, rw => 1); + my ($storage, $transferiso) = @_; + + my $g = open_guest($storage, rw => 1); # Add the transfer iso if there is one $g->add_drive($transferiso) if(defined($transferiso)); -- 1.6.6
Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 6/9] Documentation: Update virt-v2v man page
Correct example command lines Add references to ESX Add preparation steps for both ESX and Xen guests Remove reference to reged Additional minor cleanups --- v2v/virt-v2v.pl | 251 ++++++++++++++++++++++++++++++++---------------------- 1 files changed, 149 insertions(+), 102 deletions(-) diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl index a0559e9..84f67f1 100755 --- a/v2v/virt-v2v.pl +++ b/v2v/virt-v2v.pl @@ -48,67 +48,16 @@ virt-v2v - Convert a guest to use KVM =head1 SYNOPSIS - virt-v2v guest-domain.xml + virt-v2v -f virt-v2v.conf -i libvirtxml guest-domain.xml - virt-v2v -f virt-v2v.conf guest-domain.xml - - virt-v2v -ic qemu:///system guest-domain + virt-v2v -f virt-v2v.conf -ic esx://esx.server/ -op transfer guest-domain =head1 DESCRIPTION -Virt-v2v converts guests from one virtualization hypervisor to -another. Currently it is limited in what it can convert. See the -table below. - -=begin html - -<table border="1" style="border-collapse: collapse"> - <tr> - <th>Source</th> - <th>Target</th> - </tr> - - <tr> - <td valign="top" style="padding: 0 0.5em 0 0.5em"> - <p>Xen domain managed by libvirt</p> - <p>Guest - <ul> - <li>PV or FV Kernel</li> - <li>with or without PV drivers</li> - <li>RHEL 3.x, 4.x, 5.x</li> - </ul> - </p> - </td> - <td valign="top" style="padding: 0 0.5em 0 0.5em"> - <p>KVM domain managed by libvirt</p> - <p>Guest - <ul> - <li>with virtio drivers if support by guest</li> - </ul> - </p> - </td> - </tr> -</table> - -=end html - -=begin :man - - -------------------------------+---------------------------- - SOURCE | TARGET - -------------------------------+---------------------------- - Xen domain managed by | KVM domain managed by - libvirt | libvirt - | - Guest: | Guest: - - PV or FV kernel | - with virtio drivers - - with or without PV drivers | if supported by guest - - RHEL 3.x, 4.x, 5.x | - | - | - -------------------------------+---------------------------- - -=end :man +virt-v2v converts guests from a foreign hypervisor to run on KVM, managed by +libvirt. It can currently convert Red Hat Enterprise Linux and Fedora guests +running on Xen and VMware ESX. It will enable VirtIO drivers in the converted +guest if possible. =head1 OPTIONS @@ -120,8 +69,8 @@ my $input_method = "libvirt"; =item B<-i input> -Specifies how the conversion source metadata can be obtained. The default is -C<libvirt>. Supported options are: +Specifies what input method to use to obtain the guest for conversion. The +default is C<libvirt>. Supported options are: =over @@ -131,7 +80,7 @@ Guest argument is the name of a libvirt domain. =item I<libvirtxml> -Guest argument is the path to an XML file describing a libvirt domain. +Guest argument is the path to an XML file containing a libvirt domain. =back @@ -151,6 +100,7 @@ my $input_transport; =item B<-it method> Species the transport method used to obtain raw storage from the source guest. +This is currently only a placeholder, and does nothing. =cut @@ -161,6 +111,10 @@ my $output_uri = "qemu:///system"; Specifies the libvirt connection to use to create the converted guest. If ommitted, this defaults to qemu:///system. +B<N.B.> virt-v2v must be able to write directly to storage described by this +libvirt connection. This makes writing to a remote connection impractical at +present. + =cut my $output_pool; @@ -174,7 +128,7 @@ guest. my $config_file; -=item B<-f file> +=item B<-f file> | B<--config file> Load the virt-v2v configuration from I<file>. There is no default. @@ -493,64 +447,159 @@ sub inspect_guest return $os; } -=head1 PREPARING TO RUN VIRT-V2V +=head1 PREPARING TO CONVERT A GUEST + +=head2 Xen guests + +The following steps are required before converting a Xen guest. Note that only +local Xen guests are currently supported. These steps are not required for +conversions from ESX, and will not be required for remote Xen guests when we +support that. -=head2 Backup the guest +=head3 Backup the guest -Virt-v2v converts guests 'in-place': it will make changes to a guest directly -without creating a backup. It is recommended that virt-v2v be run against a -copy. +If converting a local guest using the libvirtxml input method, the guest will be +converted in place: it will make changes to a guest directly without creating a +backup. It is recommended that virt-v2v be run against a copy. The L<v2v-snapshot(1)> tool can be used to convert a guest to use a snapshot for storage prior to running virt-v2v against it. This snapshot can then be committed to the original storage after the conversion is confirmed as successful. -The L<virt-clone(1)> tool can make a complete copy of a guest, including all its -storage. - -=head2 Obtain domain XML for the guest domain +=head3 Obtain domain XML for the guest domain -Virt-v2v uses a libvirt domain description to determine the current +virt-v2v uses a libvirt domain description to determine the current configuration of the guest, including the location of its storage. This should be obtained from the host running the guest pre-conversion by running: virsh dumpxml <domain> > <domain>.xml -=head1 CONVERTING A GUEST +This will require a reboot if the host running Xen is the same host that will +run KVM. This is because libvirt needs to connect to a running xen hypervisor to +obtain its metadata. + +=head2 ESX guests + +=head3 Create a local storage pool for transferred storage + +virt-v2v copies the guest storage to the local machine during import from an ESX +server. It creates new storage in a locally defined libvirt pool. This pool can +be defined using any libvirt tool, and can be of any type. + +The simplest way to create a new pool is with virt-manager(1). Pools can be +defined from the Storage tab under Host Details. + +=head2 All guests + +=head3 Create local network interfaces + +The local machine must have an appropriate network for the converted guest +to connect to. This is likely to be a bridge interface. A bridge interface can +be created using standard tools on the host. + +Since version 0.8.3, virt-manager(1) can also create and manage bridges. + +=head1 CONVERTING A LOCAL XEN GUEST + +The following requires that the domain XML is available locally, and that the +storage referred to in the domain XML is available locally at the same paths. + +To perform the conversion, run: + + virt-v2v -f virt-v2v.conf -i libvirtxml <domain>.xml + +where C<< <domain>.xml >> is the path to the exported guest domain's xml. virt-v2v.conf should specify: + +=over + +=item * + +a mapping for the guest's network configuration. + +=item * + +app definitions for any required replacement kernels. -In the simplest case, virt-v2v can be run as follows: +=back + +See L<virt-v2v.conf(5)> for details. - virt-v2v <domain>.xml +You can avoid having to specify replacement kernels by ensuring that the guest +has a fully virt kernel installed prior to conversion. Note that it doesn't have +to be the default kernel. -where C<< <domain>.xml >> is the path to the exported guest domain's xml. This -is the simplest form of conversion. It can only be used when the guest has an -installed kernel which will boot on KVM, i.e. a guest with only paravirtualised -Xen kernels installed will not work. Virtio will be configured if it is -supported, otherwise the guest will be configured to use non-virtio drivers. See -L</GUEST DRIVERS> for details of which drivers will be used. +=head2 CONVERTING A GUEST FROM VMWARE ESX + +virt-v2v can convert a guest from VMware ESX, including transferring its +storage. -Virt-v2v can also be configured to install new software into a guest. This might -be necessary if the guest will not boot on KVM without modification, or if you -want to upgrade it to support virtio during conversion. Doing this requires -specifying a configuration file describing where to find the new software. In -this case, virt-v2v is called as: +B<N.B.> virt-v2v does not transfer snapshots from ESX. Only the latest flat +storage is transferred. - virt-v2v -s <virt-v2v.conf> <domain>.xml +The guest MUST be shut down in ESX before conversion starts. virt-v2v will not +proceed if the guest is still running. To convert the guest, run: -See L<virt-v2v.conf(5)> for details of this configuration file. During the -conversion process, if virt-v2v does not detect that the guest is capable of -supporting virtio it will try to upgrade components to resolve this. On Linux -guests this will involve upgrading the kernel, and may involve upgrading -dependent parts of userspace. + virt-v2v -f virt-v2v.conf -ic esx://<esx.server>/ -op <pool> <domain> + +where: + +=over -To text boot the new guest in KVM, run: +=item * - virsh start <domain> - virt-viewer <domain> +E<lt>esx.serverE<gt> is the hostname of the ESX server hosting the guest to be +converted. -If you have created a guest snapshot using L<v2v-snapshot(1)>, it can be -committed or rolled back at this stage. +B<N.B.> This hostname must match the hostname reported in the ESX server's SSL +certificate, or verification will fail. + +=item * + +E<lt>poolE<gt> is the name of the local storage pool where copies of the guest's +storage will be created. + +=item * + +E<lt>domainE<gt> is the name of the guest on the ESX server which is to be +converted. + +=back + +virt-v2v.conf should specify a mapping for the guest's network configuration. +See L<virt-v2v.conf(5)> for details. + +=head3 Authenticating to the ESX server + +Connecting to the ESX server will require authentication. virt-v2v supports +password authentication when connecting to ESX. It reads passwords from +$HOME/.netrc. The format of this file is described in L<netrc(5)>. An example +entry is: + + machine esx01.example.com login root password s3cr3t + +=head3 Connecting to an ESX server with an invalid certificate + +In non-production environments, the ESX server may have a non-valid certificate, +for example a self-signed certificate. In this case, certificate checking can be +explicitly disabled by adding '?no_verify=1' to the connection URI as shown +below: + + ... -ic esx://<esx.server>/?no_verify=1 ... + +=head1 RUNNING THE CONVERTED GUEST + +On successful completion, virt-v2v will create a new libvirt domain for the +converted guest with the same name as the original guest. It can be started as +usual using libvirt tools, for example virt-manager(1). + +=head1 POST-CONVERSION TASKS + +=head2 Guest network configuration + +virt-v2v cannot currently reconfigure a guest's network configuration. If the +converted guest is not connected to the same subnet as the source, its network +configuration may have to be updated. =head1 GUEST CONFIGURATION CHANGES @@ -597,7 +646,7 @@ root device, whether it is using virtio or not. =head1 GUEST DRIVERS -Virt-v2v will install the following drivers in a Linux guest: +Virt-v2v will configure the following drivers in a Linux guest: =head2 VirtIO @@ -615,12 +664,10 @@ Additionally, initrd will preload the virtio_pci driver. =head1 SEE ALSO -L<v2v-snapshot(1)> +L<virt-manager(1)>, +L<v2v-snapshot(1)>, L<http://libguestfs.org/>. -For Windows registry parsing we require the C<reged> program -from L<http://home.eunet.no/~pnordahl/ntpasswd/>. - =head1 AUTHOR Richard W.M. Jones L<http://et.redhat.com/~rjones/> @@ -629,7 +676,7 @@ Matthew Booth <mbooth at redhat.com> =head1 COPYRIGHT -Copyright (C) 2009 Red Hat Inc. +Copyright (C) 2009,2010 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 -- 1.6.6
Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 7/9] Documentation: Minor cleanups to module POD
--- lib/Sys/VirtV2V/Connection/LibVirt.pm | 7 +++---- lib/Sys/VirtV2V/Connection/LibVirtXML.pm | 2 +- lib/Sys/VirtV2V/Converter.pm | 4 ++-- lib/Sys/VirtV2V/Converter/Linux.pm | 30 +++++++++++++++++++++++++----- lib/Sys/VirtV2V/ExecHelper.pm | 1 - lib/Sys/VirtV2V/GuestOS.pm | 6 +++--- lib/Sys/VirtV2V/GuestOS/RedHat.pm | 4 ++-- lib/Sys/VirtV2V/Transfer/ESX.pm | 4 ++-- 8 files changed, 38 insertions(+), 20 deletions(-) diff --git a/lib/Sys/VirtV2V/Connection/LibVirt.pm b/lib/Sys/VirtV2V/Connection/LibVirt.pm index 59e4913..2c289b9 100644 --- a/lib/Sys/VirtV2V/Connection/LibVirt.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirt.pm @@ -62,8 +62,8 @@ libvirt connection. =item new(uri, name, pool) Create a new Sys::VirtV2V::Connection::LibVirt. Domain I<name> will be -downloaded from I<uri>. Remote storage will be copied to a new volume, which -will be create in <pool>. +obtained from I<uri>. Remote storage will be copied to a new volume, which +will be created in I<pool>. =cut @@ -243,7 +243,7 @@ sub _get_dom =head1 COPYRIGHT -Copyright (C) 2009 Red Hat Inc. +Copyright (C) 2009,2010 Red Hat Inc. =head1 LICENSE @@ -253,7 +253,6 @@ Please see the file COPYING.LIB for the full license. L<Sys::VirtV2V::Connection(3)>, L<virt-v2v(1)>, -L<v2v-snapshot(1)>, L<http://libguestfs.org/>. =cut diff --git a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm index 874946a..03b85b1 100644 --- a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm @@ -107,8 +107,8 @@ Please see the file COPYING.LIB for the full license. =head1 SEE ALSO +L<Sys::VirtV2V::Connection(3pm>, L<virt-v2v(1)>, -L<v2v-snapshot(1)>, L<http://libguestfs.org/>. =cut diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm index edc6589..cba6db8 100644 --- a/lib/Sys/VirtV2V/Converter.pm +++ b/lib/Sys/VirtV2V/Converter.pm @@ -39,8 +39,8 @@ Sys::VirtV2V::Converter - Convert a guest to run on KVM use Sys::VirtV2V::GuestOS; use Sys::VirtV2V::Converter; - my $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $os); - Sys::VirtV2V::Converter->convert($vmm, $guestos, $dom, $os); + my $guestos = Sys::VirtV2V::GuestOS->new($g, $os, $dom, $config); + Sys::VirtV2V::Converter->convert($vmm, $guestos, $config, $dom, $os); =head1 DESCRIPTION diff --git a/lib/Sys/VirtV2V/Converter/Linux.pm b/lib/Sys/VirtV2V/Converter/Linux.pm index 4458fc3..375da48 100644 --- a/lib/Sys/VirtV2V/Converter/Linux.pm +++ b/lib/Sys/VirtV2V/Converter/Linux.pm @@ -46,8 +46,7 @@ Sys::VirtV2V::Converter::Linux - Convert a Linux guest to run on KVM =head1 DESCRIPTION -Sys::VirtV2V::Converter::Linux convert a Linux guest to use KVM. It is an -implementation of the Sys::VirtV2V::Converter interface. +Sys::VirtV2V::Converter::Linux converts a Linux guest to use KVM. =head1 METHODS @@ -55,7 +54,8 @@ implementation of the Sys::VirtV2V::Converter interface. =item Sys::VirtV2V::Converter::Linux->can_handle(desc) -See BACKEND INTERFACE in L<Sys::VirtV2V::Converter> for details. +Return 1 if Sys::VirtV2V::Converter::Linux can convert the guest described by +I<desc>, 0 otherwise. =cut @@ -71,7 +71,27 @@ sub can_handle =item Sys::VirtV2V::Converter::Linux->convert(vmm, guestos, dom, desc) -See BACKEND INTERFACE in L<Sys::VirtV2V::Converter> for details. +Convert a Linux guest. Assume that can_handle has previously returned 1. + +=over + +=item vmm + +A Sys::Virt handle to the target libvirt. + +=item guestos + +An initialised Sys::VirtV2V::GuestOS for manipulating the guest OS>. + +=item dom + +A parsed XML::DOM of the guest's libvirt domain XML prior to conversion. + +=item desc + +A description of the guest OS as returned by Sys::Guestfs::Lib. + +=back =cut @@ -526,7 +546,7 @@ sub _supports_acpi =head1 COPYRIGHT -Copyright (C) 2009 Red Hat Inc. +Copyright (C) 2009,2010 Red Hat Inc. =head1 LICENSE diff --git a/lib/Sys/VirtV2V/ExecHelper.pm b/lib/Sys/VirtV2V/ExecHelper.pm index 29f3049..87f6d06 100644 --- a/lib/Sys/VirtV2V/ExecHelper.pm +++ b/lib/Sys/VirtV2V/ExecHelper.pm @@ -141,7 +141,6 @@ Please see the file COPYING.LIB for the full license. =head1 SEE ALSO L<virt-v2v(1)>, -L<v2v-snapshot(1)>, L<http://libguestfs.org/>. =cut diff --git a/lib/Sys/VirtV2V/GuestOS.pm b/lib/Sys/VirtV2V/GuestOS.pm index 539659e..41dac02 100644 --- a/lib/Sys/VirtV2V/GuestOS.pm +++ b/lib/Sys/VirtV2V/GuestOS.pm @@ -50,9 +50,9 @@ Sys::VirtV2V::GuestOS - Manipulate and query a Guest OS Sys::VirtV2V::GuestOS provides a mechanism for querying and manipulating a specific guest operating system. -Sys::VirtV2V::GuestOS is an interface to various backends, each of -which implement a consistent API. Sys::VirtV2V::GuestOS itself only -implements methods to access backends. +Sys::VirtV2V::GuestOS is a virtual superclass to various backends, each of which +implement a consistent API. The new method will actually instantiate an +appropriate subclass. Sys::VirtV2V::GuestOS uses L<Module::Pluggable> to automatically discover backends under Sys::VirtV2V::GuestOS. diff --git a/lib/Sys/VirtV2V/GuestOS/RedHat.pm b/lib/Sys/VirtV2V/GuestOS/RedHat.pm index d6abe9b..9561338 100644 --- a/lib/Sys/VirtV2V/GuestOS/RedHat.pm +++ b/lib/Sys/VirtV2V/GuestOS/RedHat.pm @@ -33,7 +33,7 @@ use Locale::TextDomain 'virt-v2v'; =head1 NAME -Sys::VirtV2V::GuestOS::RedHat - Manipulate and query a Red Hat guest +Sys::VirtV2V::GuestOS::RedHat - Manipulate and query a Red Hat based Linux guest =head1 SYNOPSIS @@ -44,7 +44,7 @@ Sys::VirtV2V::GuestOS::RedHat - Manipulate and query a Red Hat guest =head1 DESCRIPTION Sys::VirtV2V::GuestOS::RedHat provides an interface for manipulating and -querying a Red Hat based guest. Specifically it handles any Guest OS which +querying a Red Hat based Linux guest. Specifically it handles any Guest OS which Sys::Guestfs::Lib has identified as 'linux', which uses rpm as a package format. =head1 METHODS diff --git a/lib/Sys/VirtV2V/Transfer/ESX.pm b/lib/Sys/VirtV2V/Transfer/ESX.pm index 353c10d..75bb3f5 100644 --- a/lib/Sys/VirtV2V/Transfer/ESX.pm +++ b/lib/Sys/VirtV2V/Transfer/ESX.pm @@ -327,7 +327,7 @@ sub transfer =head1 COPYRIGHT -Copyright (C) 2009, 2010 Red Hat Inc. +Copyright (C) 2009,2010 Red Hat Inc. =head1 LICENSE @@ -335,8 +335,8 @@ Please see the file COPYING.LIB for the full license. =head1 SEE ALSO +L<Sys::VirtV2V::Converter>, L<virt-v2v(1)>, -L<v2v-snapshot(1)>, L<http://libguestfs.org/>. =cut -- 1.6.6
Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 8/9] Build: Fix removal of .pl suffix from scripts during installation
process_<foo>_files isn't defined to return anything. Checking its return returned a bogus value which meant processing halted before renaming. Also removed all bogus return values from subclassed process_<foo>_files. --- Build.PL | 9 ++------- 1 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Build.PL b/Build.PL index 5e085a1..d661b62 100644 --- a/Build.PL +++ b/Build.PL @@ -44,19 +44,16 @@ sub process_script_files my $self = shift; # Run the regular process_script_files action - $self->SUPER::process_script_files() - or return 1; + $self->SUPER::process_script_files(); foreach my $script (<blib/script/*>) { if($script =~ /^(.*)\.pl$/) { unless(rename($script, $1)) { $self->log_info("rename $script to $1 failed: $1\n"); - return 1; + die(); # Return isn't checked } } } - - return 0; } # Also process confdoc files @@ -85,8 +82,6 @@ sub process_confdoc_files $self->log_info("Manifying $pod -> $outfile\n"); $parser->parse_from_file( $pod, $outfile ); } - - return 0; } # Add syntaxcheck target -- 1.6.6
Matthew Booth
2010-Feb-12 09:39 UTC
[Libguestfs] [PATCH 9/9] Build: Update location of git repo in module info
--- Build.PL | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Build.PL b/Build.PL index d661b62..efce5dd 100644 --- a/Build.PL +++ b/Build.PL @@ -236,7 +236,7 @@ my $build = $class->new ( resources => { license => "http://www.gnu.org/licenses/gpl.html", homepage => "http://people.redhat.com/mbooth/virt-v2v/", - repository => "http://gitorious.org/virt-v2v/virt-v2v", + repository => "git://git.fedorahosted.org/virt-v2v.git", MailingList => "http://www.redhat.com/mailman/listinfo/libguestfs", }, }, -- 1.6.6
Richard W.M. Jones
2010-Feb-12 12:56 UTC
[Libguestfs] [PATCH 1/9] Convert config file to XML, and translate networks/bridge for all connections
On Fri, Feb 12, 2010 at 09:39:14AM +0000, Matthew Booth wrote:> Previously, only the LibVirtXML connection translated network and bridge names > in imported metadata. This change moves this functionality in Converter, making > it available to LibVirt connections as well. > > At the same time, the format of the config file is switched to XML. The primary > driver for this is that the allowable syntax of a foreign network/bridge name is > not known. Rather than create a new format which deals with this, I have > switched to an existing one. > > Note that this change doesn't update GuestOS's use of the config file. Until > this is restored it is not possible to install software in a guest, and > therefore not possible to convert a PV xen guest.This patch looks reasonable, ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/
Matthew Booth
2010-Feb-12 17:20 UTC
[Libguestfs] [PATCH 4/9] Converter: Remove disk driver elements other than 'qemu'
On 12/02/10 14:04, Richard W.M. Jones wrote:> On Fri, Feb 12, 2010 at 02:03:46PM +0000, Matthew Booth wrote: >> On 12/02/10 13:03, Richard W.M. Jones wrote: >>> On Fri, Feb 12, 2010 at 09:39:17AM +0000, Matthew Booth wrote: >>>> QEMU only currently supports the qemu storage driver in libvirt. Remove any >>>> other driver element. >>>> --- >>>> lib/Sys/VirtV2V/Converter.pm | 7 +++++++ >>>> 1 files changed, 7 insertions(+), 0 deletions(-) >>>> >>>> diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm >>>> index 4b11efd..edc6589 100644 >>>> --- a/lib/Sys/VirtV2V/Converter.pm >>>> +++ b/lib/Sys/VirtV2V/Converter.pm >>>> @@ -436,6 +436,13 @@ sub _unconfigure_hvs >>>> $emulator->getParent()->removeChild($emulator); >>>> } >>>> >>>> + # Remove any disk driver element other than 'qemu' >>>> + foreach my $driver >>>> + ($dom->findnodes('/domain/devices/disk/driver[@name != \'qemu\']')) >>>> + { >>>> + $driver->getParentNode()->removeChild($driver); >>>> + } >>>> + >>>> _unconfigure_xen_metadata($dom, $default_dom); >>>> } >>>> >>>> -- >>>> 1.6.6 >>> >>> Not sure I understand this. Looking at: >>> >>> http://libvirt.org/formatdomain.html#elementsDisks >>> >>> won't this change end up deleting important disks from the guest? >> >> No. It's only removing <driver>, not the disk element. > > OK. Is it safe to remove the <driver> element and > leave the rest?Pretty sure it is. I'll dig out a reason why when I get back on Tuesday. This is now my only outstanding patch :) Matt -- Matthew Booth, RHCA, RHCSS Red Hat Engineering, Virtualisation Team M: +44 (0)7977 267231 GPG ID: D33C3490 GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
Matthew Booth
2010-Feb-16 10:03 UTC
[Libguestfs] [PATCH 4/9] Converter: Remove disk driver elements other than 'qemu'
On 12/02/10 14:04, Richard W.M. Jones wrote:>> No. It's only removing <driver>, not the disk element. > > OK. Is it safe to remove the <driver> element and > leave the rest?Thanks for the pre-emptive ACK ;) I double-checked this anyway. <driver> is documented as being optional: http://libvirt.org/formatdomain.html#elementsDisks Matt -- Matthew Booth, RHCA, RHCSS Red Hat Engineering, Virtualisation Team M: +44 (0)7977 267231 GPG ID: D33C3490 GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
Maybe Matching Threads
- [PATCH 1/6] Convert config file to XML, and translate networks/bridge for all connections
- [PATCH] Config: Change config to lookup dependencies by name
- RHN support and capabilities
- [ESX support] Working ESX conversion for RHEL 5
- [FOR REVIEW ONLY] ESX work in progress