1
0
mirror of https://pagure.io/fedora-qa/os-autoinst-distri-fedora.git synced 2024-12-28 13:13:09 +00:00
os-autoinst-distri-fedora/lib/fedoradistribution.pm
Adam Williamson e89ec3017a Update serial console handling for upstream changes
Upstream https://github.com/os-autoinst/openQA/pull/4973 requires
us to poke things here a bit. This only works with the newer
os-autoinst and openQA (there may be a way to conditionalize it
to work with both, but I can't be bothered figuring it out, let's
just update).

Signed-off-by: Adam Williamson <awilliam@redhat.com>
2023-05-02 12:24:26 -07:00

181 lines
7.1 KiB
Perl

package fedoradistribution;
use strict;
use base 'distribution';
use Cwd;
# Fedora distribution class
# Distro-specific functions, that are actually part of the API
# (and it's completely up to us to implement them) should be here
# functions that can be reimplemented:
# ensure_installed (reimplemented here)
# x11_start_program (reimplemented here)
# become_root (reimplemented here)
# script_sudo (reimplemented here)
# assert_script_sudo (reimplemented here
# type_password (works as is)
# importing whole testapi creates circular dependency, so import only
# necessary functions from testapi
use testapi qw(check_var get_var send_key type_string assert_screen check_screen assert_script_run validate_script_output enter_cmd type_password);
use utils qw(console_login desktop_vt menu_launch_type);
# Class constructor
sub new {
my ($class) = @_;
my $self = $class->SUPER::new(@_);
# script_run requires this to be set distri-wide or specified on
# each invocation, it tells os-autoinst what to do if a script_run
# times out (rather than succeeding or failing)
$self->{script_run_die_on_timeout} = 1;
return $self;
}
sub init() {
my ($self) = @_;
$self->SUPER::init();
# Initialize the first virtio serial console as "virtio-console"
if (check_var('BACKEND', 'qemu')) {
$self->add_console('virtio-console', 'virtio_terminal', {});
$self->add_console('user-virtio-console', 'virtio_terminal', {socked_path => cwd() . '/virtio_console_user'});
for (my $num = 1; $num < get_var('VIRTIO_CONSOLE_NUM', 1); $num++) {
# initialize second virtio serial console as
# "virtio-console1", third as "virtio-console2" etc.
$self->add_console('virtio-console' . $num, 'virtio_terminal', {socked_path => cwd() . '/virtio_console' . $num});
}
}
}
# This routine should be able to start a graphical application in various DEs
# across Fedora, as it uses the Alt-F2 combination that is known to work
# similarly everywhere, maybe not in i3 or sway, but we do not test them so often anyway.
# If this should change in the future, we would need to enhance this routine.
sub x11_start_program {
my ($self, $program, $timeout, $options) = @_;
send_key "alt-f2";
assert_screen "desktop_runner";
type_string $program, 20;
sleep 5; # because of KDE dialog - SUSE guys are doing the same!
send_key "ret", 1;
}
# ensure_installed checks if a package is already installed and if not install it.
# To make it happen, it will switch to a virtual terminal (if not already there)
# and try to install the package. DNF will skip the installation,
# if it is already installed.
sub ensure_installed {
my ($self, @packages) = @_;
# First, let's assume that we are in the virtual console and that we want to stay there
# when the routine finishes.
my $stay_on_console = 1;
# We will check if GUI elements are present, that would suggest that we are not in the
# console but in GUI.
if (check_screen("apps_menu_button")) {
# In that case, we want to return to GUI after the routine finishes.
$stay_on_console = 0;
# From GUI we need to switch to the console.
send_key("ctrl-alt-f3");
# Let's wait to allow for screen changes.
sleep 5;
# And do the login.
console_login();
}
# Try to install the packages via dnf. If it is already installed, DNF will not do anything
# so there is no need to do any complicated magic.
assert_script_run("dnf install -y @packages", timeout => 240);
# If we need to leave the console.
if ($stay_on_console == 0) {
desktop_vt();
}
}
# This subroutine switches to the root account.
# On Fedora, the system can be installed with a valid root account (root password assigned)
# or without it (with root password empty). If no root password is provided through environment
# variables, we assume that the system is a "rootless" system. In that case we will use
# `sudo -i` to acquire the administrator access.
sub become_root {
# If ROOT_PASSWORD exists, it means that the root account exists, too.
# To become root, we will use the real root account and we'll switch to it.
if (check_var("ROOT_PASSWORD")) {
my $password = get_var("ROOT_PASSWORD");
enter_cmd("su -", max_interval => 15, wait_screen_changes => 3);
type_password($password, max_interval => 15);
send_key("ret");
}
# If no root password is set, it means, that we are only using an administrator
# who is in the wheel group and therefore we will use the sudo command to obtain
# the admin rights.
else {
my $password = get_var("USER_PASSWORD") || "weakpassword";
enter_cmd("sudo -i", max_interval => 15, wait_screen_changes => 3);
# The SUDO warning might be displayed so let's wait it out a bit.
sleep 2;
type_password($password, max_interval => 15);
send_key("ret");
}
sleep 2;
# Now we should be root. Let's check for root prompt.
assert_screen("root_logged_in");
}
# This routine is adapted from the SuSE distribution file.
# There are two differences however. To save a needle,
# we actually call the `sudo -k` command instead plain sudo to always
# require a password. Then, we do not need to check for
# password prompt and and we can provide the password any time.
# Also, the routine uses the serial console to check for messages
# passed to it after the command has finished to save some time.
# The serial console is only accessible for the root user, so that
# mechanism does not work when not root (why would anyone use sudo
# if they were root already anyway).
# To override this, call `make_serial_writable` from `utils.pm` in the
# beginning of the test script to enable serial console for normal users.
sub script_sudo {
my ($self, $prog, $wait) = @_;
# If $wait is not assigned, let's make it 10 seconds to give some
# time to the commands to finish.
$wait //= 10;
my $str;
if ($wait > 0) {
# Create a uniqe hash from the command and the wait time.
$str = testapi::hashed_string("SS$prog$wait");
# Chain the commands to pass the message to the serial console.
$prog = "$prog; echo $str > /dev/$testapi::serialdev";
}
# Run the command with `sudo -k`
type_string "sudo -k $prog\n";
# Put a user password (we might not know the root password anyway)
my $password = get_var("USER_PASSWORD") || "weakpassword";
type_password($password);
send_key "ret";
# Wait for the message hash to appear on the serial console which indicates
# that the command has finished. No matter what time has passed, finish
# or die if no message appears on time.
if ($str) {
return testapi::wait_serial($str, $wait);
}
send_key("ret");
return;
}
# Run the script with sudo and check the exit code after it has run.
# See the script_sudo subroutine for details.
sub assert_script_sudo {
my ($self, $prog, $wait) = @_;
script_sudo($prog, $wait);
# Validate that the command exited with a correct exit code.
validate_script_output('echo $?', sub { $_ == 0 });
return;
}
1;
# vim: set sw=4 et: