[fedora-virt] virt-manager/libvirtd beginner question: how to "convert" qemu-kvm image for use by virt-manager

Daniel P. Berrange berrange at redhat.com
Mon Apr 27 20:27:59 UTC 2009


On Mon, Apr 27, 2009 at 10:26:20AM -0700, Tom London wrote:
> I have a pre-existing qemu-kvm VM that I run with the following command:
> 
> qemu-kvm -localtime -vga std -m 512 -usbdevice tablet -name "Windows
> XP" -hda ~/VirtualMachines/raw.img -k en-us
> 
> I've been trying to "convert/adapt" this to be run with virt-manager,
> without success.  Is there a "recipe" I can follow?

We are actally working on a command for virsh to perform 'import' of
existing QEMU args, spitting back out a libvirt domain XML file. 

I've got a crude perl script proof of concept people can use in the
meanwhile - it is far from complete & doesn't cover all QEMU args,
but it may be of use in short term. It is attached to this mail. Run
it with perl, giving the full list of QEMU args you have, eg

 # perl virt-xml-import-qemu-args  qemu-kvm -localtime -vga std \
        -m 512 -usbdevice tablet -name "Windows XP" -hda \
        ~/VirtualMachines/raw.img -k en-us
<domain type='kvm'>
  <name>Windows XP</name>
  <memory>524288</memory>
  <vcpu>1</vcpu>
  <os>
    <type arch='i686'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
  </features>
  <clock offset='localtime'/>
  <on_reboot>restart</on_reboot>
  <devices>
    <emulator>qemu-kvm</emulator>
    <disk type='/home/berrange/VirtualMachines/raw.img' device='disk'>
      <source file='/home/berrange/VirtualMachines/raw.img'/>
      <target dev='hda' bus='ide'/>
    </disk>
    <graphics type='sdl' display=':0.0/>
  </devices>
</domain>

You'll likely still need to edit some things - particularly network
config, but this will get you started in the right direction...

Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
-------------- next part --------------
#!/usr/bin/perl


use strict;
use warnings;

use Getopt::Long;
use POSIX;

my $arch;
my $machine;
my $emulator;
my @disks;
my @nets;
my $graphics = { type => "sdl" };
my $clock = "utc";
my @usb;
my $uuid;
my $name = "guest1";
my @audio;
my $memory = 64 * 1024;
my $vcpus = 1;
my $on_reboot = "restart";
my @boot;
my $kernel;
my $initrd;
my $append;
my @serials;
my @parallels;
my $type = "qemu";
my $acpi = 1;

$emulator = shift @ARGV;

if ($emulator =~ /kvm/) {
    $type = "kvm";
}


if ($emulator eq "qemu") {
    $arch = "i386";
} elsif ($emulator eq "qemu-system-(.*)") {
    $arch = $1;
} else {
    $arch = (POSIX::uname)[4];
}

my $arg;
while (defined ($_ = shift @ARGV)) {
    if (/^-M$/) {
	$machine = shift @ARGV;
    } elsif (/^-(hd[abcd])$/) {
	my $file = shift @ARGV;
	my $target = $1;

	my $type = $file =~ m,/dev, ? "block" :"file";

	push @disks, { target => $target, type => $file,
		       bus => "ide", source => $file,
		       device => "disk" };
    } elsif (/^-(fd[ab])$/) {
	my $file = shift @ARGV;
	my $target = $1;

	my $type = $file =~ m,/dev, ? "block" :"file";

	push @disks, { target => $target, type => $file,
		       bus => "fd", source => $file,
		       device => "floppy" };
    } elsif (/^-cdrom$/) {
	my $file = shift @ARGV;

	my $type = $file =~ m,/dev, ? "block" :"file";

	push @disks, { target => "hdc", type => $file,
		       bus => "fd", source => $file,
		       device => "floppy" };
    } elsif (/^-drive$/) {
	my $opt = shift @ARGV;

	push @disks, &parse_drive($opt);
    } elsif (/^-net$/) {
	my $opt1 = shift @ARGV;
	my $opt2;
	if (@ARGV && $ARGV[0] eq "-net")  {
	    shift @ARGV;
	    $opt2 = shift @ARGV;
	}

	my $net = &parse_net($opt1, $opt2);
	if ($net) {
	    push @nets, $net;
	}
    } elsif (/^-vnc$/) {
	my $opt = shift @ARGV;

	my ($listen, $port) = split /:/, $opt;

        $graphics = { type => "vnc", listen => $listen, port => $port + 5900 };
    } elsif (/^-localtime$/) {
	$clock = "localtime";
    } elsif (/^-usbdevice$/) {
	my $opt = shift @ARGV;
    } elsif (/^-uuid$/) {
	$uuid = shift @ARGV;
    } elsif (/^-name$/) {
	$name = shift @ARGV;
    } elsif (/^-usbdevice$/) {
	my $opt = shift @ARGV;
    } elsif (/^-m$/) {
	$memory = (shift @ARGV) * 1024;
    } elsif (/^-smp$/) {
	$vcpus = shift @ARGV;
    } elsif (/^-no-reboot$/) {
	$on_reboot = "destroy";
    } elsif (/^-no-acpi$/) {
	$acpi = 0;
    } elsif (/^-boot$/) {
	my $opt = shift @ARGV;
	my @let = split //, $opt;

	my %boot = (
	    a => "fd",
	    c => "hd",
	    d => "cdrom",
	    n => "network",
	    );
	foreach (@let) {
	    if (exists $boot{$_}) {
		push @boot, $boot{$_};
	    }
	}
    } elsif (/^-kernel$/) {
	$kernel = shift @ARGV;
    } elsif (/^-initrd$/) {
	$initrd = shift @ARGV;
    } elsif (/^-append$/) {
	$append = shift @ARGV;
    } elsif (/^-serial$/) {
	my $opt = shift @ARGV;
	my $chr = &parse_chr($opt);
	if ($chr) {
	    push @serials, $chr;
	}
    } elsif (/^-parallel$/) {
	my $opt = shift @ARGV;
	my $chr = &parse_chr($opt);
	if ($chr) {
	    push @parallels, $chr;
	}
    } elsif (/^-no-kvm$/) {
	$type = "qemu";
    } elsif (/^-no-graphic$/) {
	$graphics = undef;
    }
}


print "<domain type='$type'>\n";
print "  <name>$name</name>\n";
print "  <uuid>$uuid</uuid>\n" if defined $uuid;
print "  <memory>$memory</memory>\n";
print "  <vcpu>$vcpus</vcpu>\n";

print "  <os>\n";
print "    <type";
if ($machine) {
    print " machine='$machine'";
}
if ($arch) {
    print " arch='$arch'";
}
print ">hvm</type>\n";
print "    <kernel>$kernel</kernel>\n" if $kernel;
print "    <initrd>$initrd</initrd>\n" if $initrd;
print "    <cmdline>$append</cmdline>\n" if $append;
if (@boot) {
    foreach my $boot (@boot) {
	print "    <boot dev='$boot'/>\n";
    }
} else {
	print "    <boot dev='hd'/>\n";
}
print "  </os>\n";

print "  <features>\n";
if ($acpi) {
    print "    <acpi/>\n";
}
print "  </features>\n";
print "  <clock offset='$clock'/>\n";
print "  <on_reboot>$on_reboot</on_reboot>\n";

print "  <devices>\n";
print "    <emulator>$emulator</emulator>\n";
foreach my $disk (@disks) {
    print "    <disk type='" . $disk->{type} . "' device='" . $disk->{device} . "'>\n";
    if ($disk->{type} eq "block") {
	print "      <source dev='" . $disk->{source} . "'/>\n";
    } else {
	print "      <source file='" . $disk->{source} . "'/>\n";
    }
    print "      <target dev='" . $disk->{target} . "' bus='" . $disk->{bus} . "'/>\n";
    print "    </disk>\n";
}
foreach my $net (@nets) {
    print "    <interface type='" . $net->{type} . "'>\n";
    if ($net->{type} eq "bridge") {
	print "      <source bridge='" . $net->{source} . "'/>\n";
    }
    print "      <mac adddress='" . $net->{mac} . "'/>\n";
    print "    </interface>\n";
}
foreach my $chr (@serials) {
    print "    <serial type='" . $chr->{type} . "'>\n";
    print "    </serial>\n";
}
foreach my $chr (@parallels) {
    print "    <parallel type='" . $chr->{type} . "'>\n";
    print "    </parallel>\n";
}
if ($graphics) {
    if ($graphics->{type} eq "sdl") {
	print "    <graphics type='sdl'";
	if (exists $ENV{DISPLAY}) {
	    print " display='$ENV{DISPLAY}";
	}
	print "/>\n";
    } else {
	print "    <graphics type='vnc' port='" . $graphics->{port} . "'";
	if ($graphics->{listen}) {
	    print " listen='" . $graphics->{listen} . "'";
	}
	print "/>\n";
    }
}
print "  </devices>\n";
print "</domain>\n";


sub parse_drive {
    my $opt = shift;

    my $type = "file";
    my $device = "disk";
    my $source = "foo";
    my $target = "hda";
    my $bus = "ide";

    my $index;

    my @opts = split m/,/, $opt;

    foreach my $oneopt (@opts) {
	my ($key, $val) = split m/=/, $oneopt;

        if ($key eq "file") {
	    $source = $val;
	    if ($source =~ m,/dev/,) {
		$type = "block";
	    }
        } elsif ($key eq "media") {
	    if ($val eq "disk" ||
		$val eq "cdrom") {
		$device = $val
	    }
        } elsif ($key eq "index") {
	    $index = $val;
        } elsif ($key eq "if") {
	    if ($val eq "ide" ||
		$val eq "scsi" ||
		$val eq "virtio") {
		$bus = $val;
	    }
	    if ($val eq "floppy") {
		$bus = "fdc";
		$device = "floppy";
	    }
	}
    }

    if (defined $index) {
	if ($bus eq "ide") {
	    $target = "hd" . chr(ord('a') + $index);
	} elsif ($bus eq "scsi") {
	    $target = "sd" . chr(ord('a') + $index);
	} elsif ($bus eq "fdc") {
	    $target = "fd" . chr(ord('a') + $index);
	}
    }

    return {
	type => $type, device => $device,
	source => $source, target => $target,
	bus => $bus
    };
}


sub parse_net {
    my $opt1 = shift;
    my $opt2 = shift;

    if ($opt1 =~ /nic/) {
	my $tmp = $opt1;
	$opt1 = $opt2;
	$opt2 = $tmp;
    }

    my $mac;
    my $model;
    my $type = "bridge";
    my $src = "br0";

    my @opt = split m/,/, $opt1;
    if ($opt2) {
	push @opt, split m/,/, $opt2;
    }
    foreach my $oneopt (@opt) {
	my ($key, $val) = split m/=/, $oneopt;

	if ($key eq "macaddr") {
	    $mac = $val;
	} elsif ($key eq "tap") {
	    $type = "bridge";
	    $src = "br0";
	} elsif ($key eq "user") {
	    $type = "user";
	} elsif ($key eq "model") {
	    $model = $val;
	}
    }

    return { type => $type, model => $model, mac => $mac, source => $src };
}

sub parse_chr {
    my $opt = shift;

    if ($opt =~ /pty/) {
	return { type => "pty" },
    }
    return undef;
}


More information about the Fedora-virt mailing list