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(a)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