[libvirt] [PATCH tck 1/6] Add ability to provision full OS using virt-builder

Daniel P. Berrange berrange at redhat.com
Fri Mar 28 12:26:27 UTC 2014


Some of the tests require a full operating system, not
merely a living dead zombie. Add the ability to bootstrap
a full OS image using the 'virt-builder' tool, defaulting
to 'fedora-20' OS image for x86_64.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 conf/default.cfg                  |  19 +++
 lib/Sys/Virt/TCK.pm               | 245 ++++++++++++++++++++++++++++++++------
 lib/Sys/Virt/TCK/DomainBuilder.pm |   7 +-
 3 files changed, 233 insertions(+), 38 deletions(-)

diff --git a/conf/default.cfg b/conf/default.cfg
index 143fba9..0da118c 100644
--- a/conf/default.cfg
+++ b/conf/default.cfg
@@ -40,6 +40,25 @@
 # over the interwebs
 ks = /etc/libvirt-tck/ks.cfg
 
+# Some of the scripts need to be able to login to the
+# guest OS images. The TCK will pick a random root
+# password, but if you want to login to the guest OS
+# images to debug things, then set a fixed password
+# here
+#rootpassword = 123456
+
+# List the virt-builder images to use for each arch
+images = (
+  {
+    arch = x86_64
+    ostype = (
+      hvm
+      xen
+    )
+    osname = fedora-20
+  }
+)
+
 #
 # Where the kernel/initrd files needed by tests are to be
 # found. These can be URLS or local file paths.
diff --git a/lib/Sys/Virt/TCK.pm b/lib/Sys/Virt/TCK.pm
index 57eb08c..9981c0f 100644
--- a/lib/Sys/Virt/TCK.pm
+++ b/lib/Sys/Virt/TCK.pm
@@ -67,6 +67,12 @@ sub new {
     return $self;
 }
 
+sub root_password {
+    my $self = shift;
+
+    return $self->{config}->get("rootpassword", "123456");
+}
+
 sub setup_conn {
     my $self = shift;
     my $uri = shift;
@@ -299,6 +305,7 @@ sub download_scratch {
     my $target = shift;
     my $uncompress = shift;
 
+    print "# downloading $source\n";
     my $ua = LWP::UserAgent->new;
     $ua->timeout(10);
     $ua->env_proxy;
@@ -332,6 +339,7 @@ sub copy_scratch {
     my $target = shift;
     my $uncompress = shift;
 
+    print "# copying $source\n";
     if (defined $uncompress) {
 	if ($uncompress eq "gzip") {
 	    gunzip $source => $target;
@@ -366,6 +374,28 @@ sub create_sparse_disk {
 }
 
 
+sub create_virt_builder_disk {
+    my $self = shift;
+    my $bucket = shift;
+    my $name = shift;
+    my $osname = shift;
+
+    my $dir = $self->bucket_dir($bucket);
+
+    my $target = catfile($dir, $name);
+
+    my $password = $self->root_password;
+
+    if (-f $target) {
+	return $target;
+    }
+
+    print "# running virt-builder $osname\n";
+    `virt-builder --root-password 'password:$password' --output $target $osname`;
+
+    return $target;
+}
+
 sub create_empty_dir {
     my $self = shift;
     my $bucket = shift;
@@ -489,7 +519,31 @@ EOF
     return ($target, catfile(rootdir, "sbin", "init"));
 }
 
-sub match_kernel {
+sub best_domain {
+    my $self = shift;
+    my $caps = shift;
+    my $ostype = shift;
+
+    for (my $i = 0 ; $i < $caps->num_guests ; $i++) {
+	if ($caps->guest_os_type($i) eq $ostype &&
+	    $caps->guest_arch_name($i) eq $caps->host_cpu_arch()) {
+
+	    my @domains = $caps->guest_domain_types($i);
+	    next unless int(@domains);
+
+	    # Prefer kvm if multiple domain types are returned
+	    my $domain = (grep /^kvm$/, @domains) ? "kvm" : $domains[0];
+
+	    return ($domain,
+		    $caps->host_cpu_arch());
+	}
+    }
+
+    return ();
+}
+
+
+sub match_guest_domain {
     my $self = shift;
     my $caps = shift;
     my $arch = shift;
@@ -521,12 +575,15 @@ sub best_kernel {
     my $wantostype = shift;
 
     my $kernels = $self->config("kernels", []);
+    my $hostarch = $caps->host_cpu_arch();
 
     for (my $i = 0 ; $i <= $#{$kernels} ; $i++) {
 	my $arch = $kernels->[$i]->{arch};
 	my $ostype = $kernels->[$i]->{ostype};
 	my @ostype = ref($ostype) ? @{$ostype} : ($ostype);
 
+	next unless $arch eq $hostarch;
+
 	foreach $ostype (@ostype) {
 	    if ((defined $wantostype) &&
 		($wantostype ne $ostype)) {
@@ -534,7 +591,7 @@ sub best_kernel {
 	    }
 
 	    my ($domain, $emulator, $loader) =
-		$self->match_kernel($caps, $arch, $ostype);
+		$self->match_guest_domain($caps, $arch, $ostype);
 
 	    if (defined $domain) {
 		return ($i, $domain, $arch, $ostype, $emulator, $loader)
@@ -545,6 +602,64 @@ sub best_kernel {
     return ();
 }
 
+
+# Find an image matching the host arch and requested ostype
+sub best_image {
+    my $self = shift;
+    my $caps = shift;
+    my $wantostype = shift;
+
+    my $images = $self->config("images", []);
+    my $hostarch = $caps->host_cpu_arch();
+
+    for (my $i = 0 ; $i <= $#{$images} ; $i++) {
+	my $arch = $images->[$i]->{arch};
+	my $ostype = $images->[$i]->{ostype};
+	my @ostype = ref($ostype) ? @{$ostype} : ($ostype);
+
+	next unless $arch eq $hostarch;
+
+	foreach $ostype (@ostype) {
+	    if ((defined $wantostype) &&
+		($wantostype ne $ostype)) {
+		next;
+	    }
+
+	    my ($domain, $emulator, $loader) =
+		$self->match_guest_domain($caps, $arch, $ostype);
+
+	    if (defined $domain) {
+		return ($i, $domain, $arch, $ostype, $emulator, $loader)
+	    }
+	}
+    }
+
+    return ();
+}
+
+sub get_disk_dev {
+    my $self = shift;
+    my $ostype = shift;
+    my $domain = shift;
+
+    my $dev;
+    if ($ostype eq "xen") {
+	$dev = "xvda";
+    } elsif ($ostype eq "uml") {
+	$dev = "ubda";
+    } elsif ($ostype eq "hvm") {
+	if ($domain eq "kvm" ||
+	    $domain eq "qemu" ||
+	    $domain eq "kqemu") {
+	    $dev = "vda";
+	} else {
+	    $dev = "hda";
+	}
+    }
+    return $dev;
+}
+
+
 sub get_kernel {
     my $self = shift;
     my $caps = shift;
@@ -575,20 +690,7 @@ sub get_kernel {
 
     chmod 0755, $kfile;
 
-    my $dev;
-    if ($ostype eq "xen") {
-	$dev = "xvda";
-    } elsif ($ostype eq "uml") {
-	$dev = "ubda";
-    } elsif ($ostype eq "hvm") {
-	if ($domain eq "kvm" ||
-	    $domain eq "qemu" ||
-	    $domain eq "kqemu") {
-	    $dev = "vda";
-	} else {
-	    $dev = "hda";
-	}
-    }
+    my $dev = $self->get_disk_dev($ostype, $domain);
 
     return (
 	domain => $domain,
@@ -604,32 +706,97 @@ sub get_kernel {
 }
 
 
-
-sub generic_machine_domain {
+sub get_image {
     my $self = shift;
-    my %params = @_;
-    my $name = exists $params{name} ? $params{name} : "tck";
-    my $ostype = exists $params{ostype} ? $params{ostype} : "hvm";
-    my $caps = exists $params{caps} ? $params{caps} : die "caps parameter is required";
+    my $caps = shift;
+    my $wantostype = shift;
 
-    my %config = $self->get_kernel($caps, $ostype);
+    my ($cfgindex, $domain, $arch, $ostype, $emulator, $loader) =
+	$self->best_image($caps, $wantostype);
 
-    my $b = Sys::Virt::TCK::DomainBuilder->new(conn => $self->conn,
-					       name => $name,
-					       domain => $config{domain},
-					       ostype => $config{ostype});
-    $b->memory(64 * 1024);
-    $b->with_acpi();
-    $b->with_apic();
+    if (!defined $cfgindex) {
+	die "cannot find any supported image configuration";
+    }
 
-    # XXX boot CDROM or vroot for other HVs
-    $b->boot_kernel($config{kernel}, $config{initrd});
+    my $kernels = $self->config("images", []);
 
-    $b->disk(src => $config{root},
-	     dst => $config{dev},
-	     type => "file");
+    my $osname = $kernels->[$cfgindex]->{osname};
 
-    return $b;
+    my $bucket = "os-$arch-$ostype";
+
+    my $dfile = $self->create_virt_builder_disk($bucket, "disk-$osname.img", $osname);
+
+    my $dev = $self->get_disk_dev($ostype, $domain);
+
+    return (
+	domain => $domain,
+	arch => $arch,
+	ostype => $ostype,
+	emulator => $emulator,
+	loader => $loader,
+	root => $dfile,
+	dev => $dev,
+    );
+}
+
+
+
+sub generic_machine_domain {
+    my $self = shift;
+    my %params = @_;
+    my $name = exists $params{name} ? $params{name} : "tck";
+    my $caps = exists $params{caps} ? $params{caps} : die "caps parameter is required";
+    my $ostype = exists $params{ostype} ? $params{ostype} : "hvm";
+    my $fullos = exists $params{fullos} ? $params{fullos} : 0;
+
+    if ($fullos) {
+	my %config = $self->get_image($caps, $ostype);
+
+        my $b = Sys::Virt::TCK::DomainBuilder->new(conn => $self->conn,
+						   name => $name,
+						   arch => $config{arch},
+						   domain => $config{domain},
+						   ostype => $config{ostype});
+	$b->memory(1024 * 1024);
+	$b->with_acpi();
+	$b->with_apic();
+
+	$b->boot_disk();
+
+	$b->graphics(type => "vnc",
+		     port => "-1",
+		     autoport => "yes",
+		     listen => "127.0.0.1");
+
+	$b->disk(src => $config{root},
+		 dst => $config{dev},
+		 type => "file");
+	return $b;
+    } else {
+	my %config = $self->get_kernel($caps, $ostype);
+
+	my $b = Sys::Virt::TCK::DomainBuilder->new(conn => $self->conn,
+						   name => $name,
+						   arch => $config{arch},
+						   domain => $config{domain},
+						   ostype => $config{ostype});
+	$b->memory(1024 * 1024);
+	$b->with_acpi();
+	$b->with_apic();
+
+	# XXX boot CDROM or vroot for other HVs
+	$b->boot_kernel($config{kernel}, $config{initrd});
+
+	$b->graphics(type => "vnc",
+		     port => "-1",
+		     autoport => "yes",
+		     listen => "127.0.0.1");
+
+	$b->disk(src => $config{root},
+		 dst => $config{dev},
+		 type => "file");
+	return $b;
+    }
 }
 
 
@@ -683,6 +850,7 @@ sub generic_domain {
 
     my $name = exists $params{name} ? $params{name} : "tck";
     my $ostype = exists $params{ostype} ? $params{ostype} : "hvm";
+    my $fullos = exists $params{fullos} ? $params{fullos} : 0;
 
     my $caps = Sys::Virt::TCK::Capabilities->new(xml => $self->conn->get_capabilities);
 
@@ -692,13 +860,16 @@ sub generic_domain {
 	unless $ostype && $ostype ne "exe";
 
     if ($container) {
+	die "Full provisioned OS not supported with containers yet" if $fullos;
+
 	return $self->generic_container_domain(name => $name,
 					       caps => $caps,
 					       domain => $container);
     } else {
 	return $self->generic_machine_domain(name => $name,
 					     caps => $caps,
-					     ostype => $ostype);
+					     ostype => $ostype,
+					     fullos => $fullos);
     }
 }
 
diff --git a/lib/Sys/Virt/TCK/DomainBuilder.pm b/lib/Sys/Virt/TCK/DomainBuilder.pm
index dbfb65f..5308dc9 100644
--- a/lib/Sys/Virt/TCK/DomainBuilder.pm
+++ b/lib/Sys/Virt/TCK/DomainBuilder.pm
@@ -35,6 +35,7 @@ sub new {
 	type => $domain,
 	ostype => $ostype,
 	boot => { type => "disk" },
+	arch => $params{arch} ? $params{arch} : undef,
 	emulator => undef,
 	lifecycle => {},
 	features => {},
@@ -336,7 +337,11 @@ sub as_xml {
     }
 
     $w->startTag("os");
-    $w->dataElement("type", $self->{ostype});
+    if ($self->{arch}) {
+	$w->dataElement("type", $self->{ostype}, arch => $self->{arch});
+    } else {
+	$w->dataElement("type", $self->{ostype});
+    }
 
     if ($self->{boot}->{type} eq "disk") {
 	$w->emptyTag("boot", dev => "hd");
-- 
1.8.5.3




More information about the libvir-list mailing list