Skip to content

Commit

Permalink
qemu: Automatically create swtpm device
Browse files Browse the repository at this point in the history
- Create device if QEMUTPM is set
- Recommend swtpm packages
- Add swtpm test deps

See: https://progress.opensuse.org/issues/101015
  • Loading branch information
kalikiana committed Nov 9, 2021
1 parent a611f35 commit dc3864b
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 30 deletions.
55 changes: 27 additions & 28 deletions backend/qemu.pm
Expand Up @@ -530,19 +530,33 @@ sub create_virtio_console_fifo { console_fifo($_) for virtio_console_fifo_names

sub delete_virtio_console_fifo { unlink $_ or bmwqemu::fctwarn("Could not unlink $_ $!") for grep { -e } virtio_console_fifo_names }

sub qemu_params_ofw {
my $self = shift;
sub setup_tpm {
my ($self, $arch) = @_;
my $vars = \%bmwqemu::vars;
$vars->{QEMUVGA} ||= "std";
$vars->{QEMUMACHINE} //= "usb=off";
sp('g', '1024x768');
# newer qemu needs safe cache capability level quirk settings
# https://progress.opensuse.org/issues/75259
my $caps = ',cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken';
$vars->{QEMUMACHINE} .= $caps if $vars->{QEMUMACHINE} !~ /$caps/;
$caps = ',cap-ccf-assist=off';
$vars->{QEMUMACHINE} .= $caps if $self->{qemu_version} >= version->declare(5) && $vars->{QEMUMACHINE} !~ /$caps/;
return 1;
return unless ($vars->{QEMUTPM});
local *sp = sub { $self->{proc}->static_param(@_); };
my $tpmn = $vars->{QEMUTPM} eq 'instance' ? $vars->{WORKER_INSTANCE} : $vars->{QEMUTPM};
my $vmpath = "/tmp/mytpm$tpmn";
mkdir $vmpath unless -d $vmpath;
my $vmsock = "$vmpath/swtpm-sock";
unless (-e $vmsock) {
my @args = ('swtpm', 'socket', '--tpmstate', "dir=$vmpath", '--ctrl', "type=unixio,path=$vmsock", '--log', 'level=20', '-d');
push @args, '--tpm2' if (($vars->{QEMUTPM_VER} // '2.0') == '2.0');
runcmd(@args);
}
sp('chardev', "socket,id=chrtpm,path=$vmsock");
sp('tpmdev', 'emulator,id=tpm0,chardev=chrtpm');
if ($arch eq 'aarch64') {
sp('device', 'tpm-tis-device,tpmdev=tpm0');
}
elsif ($arch eq 'ppc64le') {
sp('device', 'tpm-spapr,tpmdev=tpm0');
sp('device', 'spapr-vscsi,id=scsi9,reg=0x00002000');
}
else {
# x86_64
sp('device', 'tpm-tis,tpmdev=tpm0');
}
}

sub start_qemu {
Expand Down Expand Up @@ -837,22 +851,7 @@ sub start_qemu {
sp('append', "dhcp && sanhook iscsi:$vars->{WORKER_HOSTNAME}::3260:1:$vars->{NBF}", no_quotes => 1);
}

if ($vars->{QEMUTPM}) {
my $tpmn = $vars->{QEMUTPM} eq 'instance' ? $vars->{WORKER_INSTANCE} : $vars->{QEMUTPM};
sp('chardev', "socket,id=chrtpm,path=/tmp/mytpm$tpmn/swtpm-sock");
sp('tpmdev', 'emulator,id=tpm0,chardev=chrtpm');
if ($arch eq 'aarch64') {
sp('device', 'tpm-tis-device,tpmdev=tpm0');
}
elsif ($arch eq 'ppc64le') {
sp('device', 'tpm-spapr,tpmdev=tpm0');
sp('device', 'spapr-vscsi,id=scsi9,reg=0x00002000');
}
else {
# x86_64
sp('device', 'tpm-tis,tpmdev=tpm0');
}
}
$self->setup_tpm($arch);

my @boot_args;
# Enable boot menu for aarch64 workaround, see bsc#1022064 for details
Expand Down
1 change: 1 addition & 0 deletions container/os-autoinst_dev/Dockerfile
Expand Up @@ -37,6 +37,7 @@ RUN zypper in -y -C \
qemu-tools \
qemu-x86 \
sudo \
swtpm \
which \
'perl(B::Deparse)' \
'perl(Benchmark)' \
Expand Down
1 change: 1 addition & 0 deletions dependencies.yaml
Expand Up @@ -89,6 +89,7 @@ test_base_requires:
qemu-x86:
procps:
python3-setuptools:
swtpm:

test_version_only_requires:
perl(Mojo::IOLoop::ReadWriteProcess): '>= 0.28'
Expand Down
11 changes: 10 additions & 1 deletion dist/rpm/os-autoinst.spec
Expand Up @@ -74,7 +74,7 @@ Source0: %{name}-%{version}.tar.xz
%define python_style_requires %{nil}
%endif
# The following line is generated from dependencies.yaml
%define test_base_requires %main_requires cpio perl(Benchmark) perl(Devel::Cover) perl(FindBin) perl(Pod::Coverage) perl(Test::Fatal) perl(Test::Mock::Time) perl(Test::MockModule) perl(Test::MockObject) perl(Test::MockRandom) perl(Test::Mojo) perl(Test::Most) perl(Test::Output) perl(Test::Pod) perl(Test::Strict) perl(Test::Warnings) >= 0.029 procps python3-setuptools qemu >= 4.0 qemu-tools qemu-x86
%define test_base_requires %main_requires cpio perl(Benchmark) perl(Devel::Cover) perl(FindBin) perl(Pod::Coverage) perl(Test::Fatal) perl(Test::Mock::Time) perl(Test::MockModule) perl(Test::MockObject) perl(Test::MockRandom) perl(Test::Mojo) perl(Test::Most) perl(Test::Output) perl(Test::Pod) perl(Test::Strict) perl(Test::Warnings) >= 0.029 procps python3-setuptools qemu >= 4.0 qemu-tools qemu-x86 swtpm
# The following line is generated from dependencies.yaml
%define test_version_only_requires perl(Mojo::IOLoop::ReadWriteProcess) >= 0.28
# The following line is generated from dependencies.yaml
Expand Down Expand Up @@ -142,6 +142,15 @@ Requires: qemu-tools
Convenience package providing os-autoinst and qemu-x86 dependencies.
%endif

%package swtpm
Summary: Convenience package providing os-autoinst+swtpm
Group: Development/Tools/Other
Requires: os-autoinst
Requires: swtpm

%description swtpm
Convenience package providing os-autoinst and swtpm dependencies.

%package s390-deps
Summary: Convenience package providing os-autoinst + s390 worker jumphost deps
Group: Development/Tools/Other
Expand Down
3 changes: 2 additions & 1 deletion doc/backend_vars.asciidoc
Expand Up @@ -122,7 +122,8 @@ QEMUMACHINE;see qemu -machine ?;undef;Machine and chipset to emulate
QEMUPORT;integer;20002 + worker instance * 10;Port on which QEMU monitor should listen
QEMURAM;integer;1024;Size of RAM of VM in MiB
QEMUTHREADS;integer;0;Number of cpu threads used by VM
QEMUTPM;'instance' or appropriate value for local swtpm config;undef;Configure VM to use a TPM emulator device, with appropriate args for the arch. sysadmin is responsible for running swtpm with a socket at /tmp/mytpmX, where X is the value of QEMUTPM or the worker instance number if QEMUTPM is set to 'instance'
QEMUTPM;'instance' or appropriate value for local swtpm config;undef;Configure VM to use a TPM emulator device, with appropriate args for the arch. If a TPM device is available at /tmp/mytpmX, where X is the value of QEMUTPM or the worker instance number if QEMUTPM is set to 'instance', it will be used. Otherwise it will be created at test startup. See QEMUTPM_VER in the latter case.
QEMUTPM_VER;'1.2' or '2.0' depending on which TPM chip should be emulated;'2.0';If no TPM device has been setup otherwise, swtpm will be used internally to create one with a socket at /tmp/mytpmX
QEMUVGA;see qemu -device ?;cirrus;VGA device to use with VM
QEMU_COMPRESS_QCOW2;boolean;1;compress qcow2 images intended for upload
QEMU_IMG_CREATE_TRIES;integer;3;Define number of tries for qemu-img commands
Expand Down
16 changes: 16 additions & 0 deletions t/18-qemu-options.t
Expand Up @@ -112,12 +112,16 @@ subtest qemu_huge_pages_option => sub {
# of QEMU here.
subtest qemu_tpm_option => sub {
# call isotovideo with QEMUTPM=instance
mkdir('/tmp/mytpm3');
path('/tmp/mytpm3/swtpm-sock')->touch;
run_isotovideo(QEMU_ONLY_EXEC => 1, QEMUTPM => 'instance');
like($log, qr|-chardev socket,id=chrtpm,path=/tmp/mytpm3/swtpm-sock|, '-chardev socket option added (instance)');
like($log, qr|-tpmdev emulator,id=tpm0,chardev=chrtpm|, '-tpmdev emulator option added');
like($log, qr|-device tpm-tis,tpmdev=tpm0|, '-device tpm-tis option added');

# call isotovideo with QEMUTPM=2
mkdir('/tmp/mytpm2');
path('/tmp/mytpm2/swtpm-sock')->touch;
run_isotovideo(QEMU_ONLY_EXEC => 1, QEMUTPM => '2');
like($log, qr|-chardev socket,id=chrtpm,path=/tmp/mytpm2/swtpm-sock|, '-chardev socket option added (2)');

Expand All @@ -133,6 +137,18 @@ subtest qemu_tpm_option => sub {
like($log, qr|-chardev socket,id=chrtpm,path=/tmp/mytpm3/swtpm-sock|, '-chardev socket option added (instance)');
like($log, qr/-tpmdev emulator,id=tpm0,chardev=chrtpm/, '-tpmdev emulator option added');
like($log, qr/-device tpm-tis-device,tpmdev=tpm0/, '-device tpm-tis option added');

# call isotovideo with QEMUTPM=4 w/o creating a device beforehand
run_isotovideo(QEMU_ONLY_EXEC => 1, QEMUTPM => '4');
like($log, qr|swtpm socket --tpmstate dir=/tmp/mytpm4 --ctrl type=unixio,path=/tmp/mytpm4/swtpm-sock --log level=20 -d --tpm2|, 'swtpm default device created');

# call isotovideo with QEMUTPM=5, QEMUTPM_VER=2.0 w/o creating a device beforehand
run_isotovideo(QEMU_ONLY_EXEC => 1, QEMUTPM => '5', QEMUTPM_VER => '2.0');
like($log, qr|swtpm socket --tpmstate dir=/tmp/mytpm5 --ctrl type=unixio,path=/tmp/mytpm5/swtpm-sock --log level=20 -d --tpm2|, 'swtpm 2.0 device created');

# call isotovideo with QEMUTPM=6, QEMU_TPM_VER=1.2 w/o creating a device beforehand
run_isotovideo(QEMU_ONLY_EXEC => 1, QEMUTPM => '6', QEMUTPM_VER => '1.2');
like($log, qr|swtpm socket --tpmstate dir=/tmp/mytpm6 --ctrl type=unixio,path=/tmp/mytpm6/swtpm-sock --log level=20 -d|, 'swtpm 1.2 device created');
};

done_testing();

0 comments on commit dc3864b

Please sign in to comment.