1
0
mirror of https://pagure.io/fedora-qa/os-autoinst-distri-fedora.git synced 2024-12-01 17:53:08 +00:00
os-autoinst-distri-fedora/lib/fedoradistribution.pm
Lukáš Růžička fe8306d2cd Implement distribution methods to replace the testapi defaults.
This PR adds implementations of distribution methods to make them
usable on Fedora. It adds the following methods

* ensure_installed (to install packages)
* become_root (to switch to root account)
* script_sudo (run script with sudo)
* assert_script_sudo (run and assert a sudo script)

It also adds a helper script to the utils.pm

* make_serial_writable

that makes the serial console writable for normal users
and so enables to run commands that check their progress
by sending messages to the serial console. Normally, they
fail, because the messages will not be written their, so
the checking mechanism will never see them.
2022-01-27 21:44:35 +00:00

168 lines
6.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);
use utils qw(console_login desktop_vt menu_launch_type);
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', {});
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: