[Libguestfs] [PATCH 1/9] Convert config file to XML, and translate networks/bridge for all connections

Matthew Booth mbooth at redhat.com
Fri Feb 12 09:39:14 UTC 2010


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




More information about the Libguestfs mailing list