1
0
mirror of https://pagure.io/fedora-qa/os-autoinst-distri-fedora.git synced 2024-12-27 20:53:09 +00:00
os-autoinst-distri-fedora/lib/fedoradistribution.pm
Adam Williamson 5f702b0be8 Run update repo setup steps from a serial console
This is a surprisingly large change as we want to go back to
the console we were previously on after doing it. To do that we
need to know what console we were on, and to know *that*, we need
to port everything that currently uses (ctrl-)alt-fX to switch
consoles to use select_console instead.

This is primarily intended to make running setup_repos.py faster
when it has to download a lot of packages (as typing in hundreds
of package names is quite slow). But it actually makes the whole
thing faster, even when only downloading one or two packages.

Signed-off-by: Adam Williamson <awilliam@redhat.com>
2024-01-11 12:09:59 -08:00

187 lines
7.6 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 select_console);
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});
}
$self->add_console('tty1-console', 'tty-console', {tty => 1});
$self->add_console('tty2-console', 'tty-console', {tty => 2});
$self->add_console('tty3-console', 'tty-console', {tty => 3});
$self->add_console('tty4-console', 'tty-console', {tty => 4});
$self->add_console('tty5-console', 'tty-console', {tty => 5});
$self->add_console('tty6-console', 'tty-console', {tty => 6});
}
}
# 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.
select_console "tty3-console";
# 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: