#130 Enable Anaconda Text install via serial console.
Closed 5 years ago by adamwill. Opened 5 years ago by lruzicka.

file modified
+8
@@ -120,6 +120,14 @@ 

      if (get_var("LIVE") && get_var("DESKTOP") eq "gnome") {

          send_key "ctrl-alt-f3";

      }

+     # If we want to log in using serial console, we need to select

+     # it first, otherwise no action will be possible.

+     elsif (get_var("SERIAL_CONSOLE")) {

+         select_console("root-virtio-terminal");

+         # as we don't have any live image cases here, we know we

+         # don't need to login

+         return;

+     }

      else {

          send_key "ctrl-alt-f2";

      }

file modified
+9 -1
@@ -1,5 +1,6 @@ 

  package fedoradistribution;

  use base 'distribution';

+ use Cwd;

  

  # Fedora distribution class

  
@@ -15,12 +16,19 @@ 

  

  # importing whole testapi creates circular dependency, so import only

  # necessary functions from testapi

- use testapi qw(send_key type_string wait_idle assert_screen);

+ use testapi qw(check_var get_var send_key type_string wait_idle assert_screen);

  

  sub init() {

      my ($self) = @_;

  

      $self->SUPER::init();

+     # This initiates the serial console as "root-virtio-terminal".

+     if (check_var('BACKEND', 'qemu')) {

+         $self->add_console('root-virtio-terminal', 'virtio-terminal', {});

+         for (my $num = 1; $num < get_var('VIRTIO_CONSOLE_NUM', 1); $num++) {

+             $self->add_console('root-virtio-terminal' . $num, 'virtio-terminal', {socked_path => cwd() . '/virtio_console' . $num});

+         }

+     }

  }

  

  sub x11_start_program {

file modified
+10 -3
@@ -15,9 +15,16 @@ 

      my %args = (

          tty => 1, # what TTY to login to

          @_);

- 

-     send_key "ctrl-alt-f$args{tty}";

-     console_login;

+     # If we want to work with serial console, we have to select it first,

+     # otherwise no interaction will be possible. We ignore tty here and

+     # always use hvc1...that may present a problem in some circumstances

+     if (get_var("SERIAL_CONSOLE")) {

+         select_console("root-virtio-terminal");

+     }

+     else { # For normal terminal emulation, use key combo to reach any of the ttys.

+         send_key "ctrl-alt-f$args{tty}";

+     }

+     console_login; # Do the login.

  }

  

  sub post_fail_hook {

file modified
+128 -71
@@ -15,9 +15,21 @@ 

  

  sub run_with_error_check {

      my ($func, $error_screen) = @_;

-     die "Error screen appeared" if (check_screen $error_screen, 5);

-     $func->();

-     die "Error screen appeared" if (check_screen $error_screen, 5);

+     # Check screen does not work for serial console, so we need to use

+     # different checking mechanism for it.

+     if (testapi::is_serial_terminal) {

+         # by using 'unless' and 'expect_not_found=>1' here we avoid

+         # the web UI showing each failure to see the error message as

+         # a 'failed match'

+         die "Error screen appeared" unless (wait_serial($error_screen, timeout=>5, expect_not_found=>1));

+         $func->();

+         die "Error screen appeared" unless (wait_serial($error_screen, timeout=>5, expect_not_found=>1));

+     }

+     else {

+         die "Error screen appeared" if (check_screen $error_screen, 5);

+         $func->();

+         die "Error screen appeared" if (check_screen $error_screen, 5);

+     }

  }

  

  # high-level 'type this string quite safely but reasonably fast'
@@ -78,18 +90,27 @@ 

  sub boot_to_login_screen {

      my %args = @_;

      $args{timeout} //= 300;

-     # we may start at a screen that matches one of the needles; if so,

-     # wait till we don't (e.g. when rebooting at end of live install,

-     # we match text_console_login until the console disappears)

-     my $count = 5;

-     while (check_screen("login_screen", 3) && $count > 0) {

-         sleep 5;

-         $count -= 1;

+     # For serial console, just wait for the login prompt

+     if (testapi::is_serial_terminal) {

+         unless (wait_serial "login:", timeout=>$args{timeout}) { # Check for the login prompt.

+             die "No login prompt shown on serial console.";

+         }

      }

-     assert_screen "login_screen", $args{timeout};

-     if (match_has_tag "graphical_login") {

-         wait_still_screen 10, 30;

-         assert_screen "login_screen";

+     else {

+         # we may start at a screen that matches one of the needles; if so,

+         # wait till we don't (e.g. when rebooting at end of live install,

+         # we match text_console_login until the console disappears).

+         # The following is true for non-serial console.

+         my $count = 5;

+         while (check_screen("login_screen", 3) && $count > 0) {

+            sleep 5;

+            $count -= 1;

+         }

+        assert_screen "login_screen", $args{timeout};

+        if (match_has_tag "graphical_login") {

+            wait_still_screen 10, 30;

+            assert_screen "login_screen";

+        }

      }

  }

  
@@ -128,8 +149,16 @@ 

  # failed (the prompt looks different in this case). We treat this as

  # a soft failure.

  sub _console_login_finish {

-     if (match_has_tag "bash_noprofile") {

-         record_soft_failure "It looks like profile sourcing failed";

+     # The check differs according to the console used.

+     if (testapi::is_serial_terminal) {

+         unless (wait_serial("-bash-.*[#\$]", timeout=>5, expect_not_found=>1)) {

+             record_soft_failure "It looks like profile sourcing failed";

+         }

+     }

+     else {

+         if (match_has_tag "bash_noprofile") {

+             record_soft_failure "It looks like profile sourcing failed";

+         }

      }

  }

  
@@ -145,66 +174,94 @@ 

          @_);

      $args{timeout} ||= 10;

  

-     # There's a timing problem when we switch from a logged-in console

-     # to a non-logged in console and immediately call this function;

-     # if the switch lags a bit, this function will match one of the

-     # logged-in needles for the console we switched from, and get out

-     # of sync (e.g. https://openqa.stg.fedoraproject.org/tests/1664 )

-     # To avoid this, we'll sleep a few seconds before starting

-     sleep 4;

- 

-     my $good = "";

-     my $bad = "";

-     if ($args{user} eq "root") {

-         $good = "root_console";

-         $bad = "user_console";

+     # Since we do not test many serial console tests, and we probably

+     # only want to test serial console on a minimal installation only,

+     # let us not do all the magic to handle different console logins

+     # and let us simplify the process.

+     # We will check if we are logged in, and if so, we will log out to

+     # enable a new proper login based on the user variable.

+     if (get_var("SERIAL_CONSOLE")) {

+         # Check for the usual prompt.

+         if (wait_serial("~\][#\$]", timeout=>5, quiet=>1)) {

+             type_string "logout\n";

+             # Wait a bit to let the logout properly finish.

+             sleep 10;

+         }

+         # Do the new login.

+         type_string $args{user};

+         type_string "\n";

+         sleep 2;

+         type_string $args{password};

+         type_string "\n";

+         # Let's perform a simple login test. This is the same as

+         # whoami, but has the advantage of existing in installer env

+         assert_script_run "id -un";

+         unless (wait_serial $args{user}, timeout=>5) {

+             die "Logging onto the serial console has failed.";

+         }

      }

      else {

-         $good = "user_console";

-         $bad = "root_console";

-     }

+         # There's a timing problem when we switch from a logged-in console

+         # to a non-logged in console and immediately call this function;

+         # if the switch lags a bit, this function will match one of the

+         # logged-in needles for the console we switched from, and get out

+         # of sync (e.g. https://openqa.stg.fedoraproject.org/tests/1664 )

+         # To avoid this, we'll sleep a few seconds before starting

+         sleep 4;

+ 

+         my $good = "";

+         my $bad = "";

+         if ($args{user} eq "root") {

+             $good = "root_console";

+             $bad = "user_console";

+         }

+         else {

+             $good = "user_console";

+             $bad = "root_console";

+         }

  

-     if (check_screen $bad, 0) {

-         # we don't want to 'wait' for this as it won't return

-         script_run "exit", 0;

-         sleep 2;

-     }

+         if (check_screen $bad, 0) {

+             # we don't want to 'wait' for this as it won't return

+             script_run "exit", 0;

+             sleep 2;

+         }

  

-     assert_screen [$good, 'text_console_login'], $args{timeout};

-     # if we're already logged in, all is good

-     if (match_has_tag $good) {

-         _console_login_finish();

-         return;

-     }

-     # otherwise, we saw the login prompt, type the username

-     type_string("$args{user}\n");

-     assert_screen [$good, 'console_password_required'], 30;

-     # on a live image, just the user name will be enough

-     if (match_has_tag $good) {

-         _console_login_finish();

-         return;

-     }

-     # otherwise, type the password

-     type_string "$args{password}";

-     if (get_var("SWITCHED_LAYOUT") and $args{user} ne "root") {

-         # see _do_install_and_reboot; when layout is switched

-         # user password is doubled to contain both US and native

-         # chars

-         console_switch_layout;

+         assert_screen [$good, 'text_console_login'], $args{timeout};

+         # if we're already logged in, all is good

+         if (match_has_tag $good) {

+             _console_login_finish();

+             return;

+         }

+         # otherwise, we saw the login prompt, type the username

+         type_string("$args{user}\n");

+         assert_screen [$good, 'console_password_required'], 30;

+         # on a live image, just the user name will be enough

+         if (match_has_tag $good) {

+             _console_login_finish();

+             return;

+         }

+         # otherwise, type the password

          type_string "$args{password}";

-         console_switch_layout;

-     }

-     send_key "ret";

-     # make sure we reached the console

-     unless (check_screen($good, 30)) {

-         # as of 2018-10 we have a bug in sssd which makes this take

-         # unusually long in the FreeIPA tests, let's allow longer,

-         # with a soft fail - RHBZ #1644919

-         record_soft_failure "Console login is taking a long time - #1644919?";

-         my $timeout = 30;

-         # even an extra 30 secs isn't long enough on aarch64...

-         $timeout = 90 if (get_var("ARCH") eq "aarch64");

-         assert_screen($good, $timeout);

+         if (get_var("SWITCHED_LAYOUT") and $args{user} ne "root") {

+             # see _do_install_and_reboot; when layout is switched

+             # user password is doubled to contain both US and native

+             # chars

+             console_switch_layout;

+             type_string "$args{password}";

+             console_switch_layout;

+         }

+         send_key "ret";

+         # make sure we reached the console

+         unless (check_screen($good, 30)) {

+             # as of 2018-10 we have a bug in sssd which makes this take

+             # unusually long in the FreeIPA tests, let's allow longer,

+             # with a soft fail - RHBZ #1644919

+             record_soft_failure "Console login is taking a long time - #1644919?";

+             my $timeout = 30;

+             # even an extra 30 secs isn't long enough on aarch64...

+             $timeout = 90 if (get_var("ARCH") eq "aarch64");

+             assert_screen($good, $timeout);

+         }

      }

      _console_login_finish();

  }

file modified
+48
@@ -702,6 +702,17 @@ 

                      },

                      {

                        machine    => { name => "64bit" },

+                       prio       => 30,

+                       product    => {

+                                       arch    => "x86_64",

+                                       distri  => "fedora",

+                                       flavor  => "universal",

+                                       version => "*",

+                                     },

+                       test_suite => { name => "install_anaconda_serial_console" },

+                     },

+                     {

+                       machine    => { name => "64bit" },

                        prio       => 31,

                        product    => {

                                        arch    => "x86_64",
@@ -2389,6 +2400,18 @@ 

                      {

                        group_name => "Fedora PowerPC",

                        machine    => { name => "ppc64le" },

+                       prio       => 30,

+                       product    => {

+                                       arch    => "ppc64le",

+                                       distri  => "fedora",

+                                       flavor  => "universal",

+                                       version => "*",

+                                     },

+                       test_suite => { name => "install_anaconda_serial_console" },

+                     },

+                     {

+                       group_name => "Fedora PowerPC",

+                       machine    => { name => "ppc64le" },

                        prio       => 31,

                        product    => {

                                        arch    => "ppc64le",
@@ -3477,6 +3500,18 @@ 

                      {

                        group_name => "Fedora AArch64",

                        machine    => { name => "aarch64" },

+                       prio       => 30,

+                       product    => {

+                                       arch    => "aarch64",

+                                       distri  => "fedora",

+                                       flavor  => "universal",

+                                       version => "*",

+                                     },

+                       test_suite => { name => "install_anaconda_serial_console" },

+                     },

+                     {

+                       group_name => "Fedora AArch64",

+                       machine    => { name => "aarch64" },

                        prio       => 31,

                        product    => {

                                        arch    => "aarch64",
@@ -4686,6 +4721,19 @@ 

                        ],

                      },

                      {

+                       name => "install_anaconda_serial_console",

+                       settings => [

+                         { key => "ANACONDA_TEXT", value => "1" },

+                         { key => "SERIAL_CONSOLE", value => "1" },

+                         # we want one console for anaconda and one for a root

+                         # terminal

+                         { key => "VIRTIO_CONSOLE_NUM", value => "2" },

+                         # we don't need to check this here and it doesn't work

+                         # with serial console

+                         { key => "NO_UEFI_POST", value => "1" },

+                       ],

+                     },

+                     {

                        name => "install_rescue_encrypted",

                        settings => [

                          { key => "BOOTFROM", value => "d" },

file modified
+37 -5
@@ -37,8 +37,30 @@ 

      }

      if (get_var("ANACONDA_TEXT")) {

          $params .= "inst.text ";

-         # we need this on aarch64 till #1594402 is resolved

+         # we need this on aarch64 till #1594402 is resolved,

+         # and we also can utilize this if we want to run this

+         # over the serial console.

          $params .= "console=tty0 " if (get_var("ARCH") eq "aarch64");

+         # when the text installation should run over the serial console,

+         # we have to add some more parametres to grub. Although, the written

+         # test case recommends using ttyS0, OpenQA only uses that console for

+         # displaying information but does not accept key strokes. Therefore,

+         # let us use a real virtio console here.

+         if (get_var("SERIAL_CONSOLE")) {

+             # this is icky. on ppc64 (OFW), virtio-terminal is hvc1 and

+             # virtio-terminal1 is hvc2, because the 'standard' serial

+             # terminal is hvc0 (the firmware does this or something).

+             # On other arches, the 'standard' serial terminal is ttyS0,

+             # so virtio-terminal becomes hvc0 and virtio-terminal1 is

+             # hvc1. We want anaconda to wind up on the console that is

+             # virtio-terminal1 in both cases

+             if (get_var("OFW")) {

+                 $params .= "console=hvc2 ";

+             }

+             else {

+                 $params .= "console=hvc1 ";

+             }

+         }

      }

      # inst.debug enables memory use tracking

      $params .= "debug" if get_var("MEMCHECK");
@@ -73,10 +95,20 @@ 

      else {

          if (get_var("ANACONDA_TEXT")) {

              # select that we don't want to start VNC; we want to run in text mode

-             assert_screen "anaconda_use_text_mode", 300;

-             type_string "2\n";

-             # wait for text version of Anaconda main hub

-             assert_screen "anaconda_main_hub_text", 300;

+             if (get_var("SERIAL_CONSOLE")) {

+                 # we direct the installer to virtio-terminal1, and use

+                 # virtio-terminal as a root console

+                 select_console('root-virtio-terminal1');

+                 unless (wait_serial "Use text mode", timeout=>120) { die "Anaconda has not started."; }

+                 type_string "2\n";

+                 unless (wait_serial "Installation") { die "Text version of Anaconda has not started."; }

+             }

+             else {

+                 assert_screen "anaconda_use_text_mode", 300;

+                 type_string "2\n";

+                 # wait for text version of Anaconda main hub

+                 assert_screen "anaconda_main_hub_text", 300;

+             }

          }

          else {

              # on lives, we have to explicitly launch anaconda

@@ -20,7 +20,11 @@ 

  

      # do user login unless USER_LOGIN is set to string 'false'

      unless (get_var("USER_LOGIN") eq "false") {

+         # this avoids us waiting 90 seconds for a # to show up

+         my $origprompt = $self->{serial_term_prompt};

+         $testapi::distri->{serial_term_prompt} = '$ ';

          console_login(user=>get_var("USER_LOGIN", "test"), password=>get_var("USER_PASSWORD", "weakpassword"));

+         $testapi::distri->{serial_term_prompt} = $origprompt;

      }

      if (get_var("ROOT_PASSWORD")) {

          console_login(user=>"root", password=>get_var("ROOT_PASSWORD"));

file modified
+100 -59
@@ -3,11 +3,38 @@ 

  use testapi;

  use utils;

  

+ 

+ # this enables you to send a command and some post-command wait time

+ # in one step and also distinguishes between serial console and normal

+ # VNC based console and handles the wait times differently.

+ sub console_type_wait {

+     my ($string, $wait) = @_;

+     $wait ||= 5;

+     type_string $string;

+     if (testapi::is_serial_terminal) {

+         sleep $wait;

+     }

+     else {

+         wait_still_screen $wait;

+     }

+ }

+ 

  sub run {

      my $self = shift;

-     assert_screen "anaconda_main_hub_text";

-     # IMHO it's better to use sleeps than to have needle for every text screen

-     wait_still_screen 5;

+ 

+     # First, preset the environment according to the chosen console. This test

+     # can run both on a VNC based console, or a serial console.

+     if (get_var("SERIAL_CONSOLE")) {

+         select_console('root-virtio-terminal1');

+         unless (testapi::is_serial_terminal) {

+             die "The test does not run on a serial console when it should.";

+         }

+     }

+     else {

+         assert_screen "anaconda_main_hub_text";

+         # IMHO it's better to use sleeps than to have needle for every text screen

+         wait_still_screen 5;

+     }

  

      # prepare for different number of spokes (e. g. as in Atomic DVD)

      my %spoke_number = (
@@ -21,77 +48,76 @@ 

          "user" => 8

      );

  

+     # The error message that we are going to check for in the text installation

+     # must be different for serial console and a VNC terminal emulator.

+     my $error = "";

+     if (testapi::is_serial_terminal) {

+         $error = "unknown error has occured";

+     }

+     else {

+         $error = "anaconda_text_error";

+     }

+ 

      # Set timezone

-     run_with_error_check(sub {type_string $spoke_number{"timezone"} . "\n"}, "anaconda_text_error");

-     wait_still_screen 5;

-     type_string "1\n"; # Set timezone

-     wait_still_screen 5;

-     type_string "1\n"; # Europe

-     wait_still_screen 5;

-     type_string "37\n"; # Prague

-     wait_still_screen 7;

+     run_with_error_check(sub {console_type_wait($spoke_number{"timezone"} . "\n")}, $error);

+     console_type_wait("1\n"); # Set timezone

+     console_type_wait("1\n"); # Europe

+     console_type_wait("37\n", 7); # Prague

  

      # Select disk

-     run_with_error_check(sub {type_string $spoke_number{"destination"} . "\n"}, "anaconda_text_error");

-     wait_still_screen 5;

-     type_string "c\n"; # first disk selected, continue

-     wait_still_screen 5;

-     type_string "c\n"; # use all space selected, continue

-     wait_still_screen 5;

-     type_string "c\n"; # LVM selected, continue

-     wait_still_screen 7;

+     run_with_error_check(sub {console_type_wait($spoke_number{"destination"} . "\n")}, $error);

+     console_type_wait("c\n"); # first disk selected, continue

+     console_type_wait("c\n"); # use all space selected, continue

+     console_type_wait("c\n", 7); # LVM selected, continue

  

      # Set root password

-     run_with_error_check(sub {type_string $spoke_number{"rootpwd"} . "\n"}, "anaconda_text_error");

-     wait_still_screen 5;

-     type_string get_var("ROOT_PASSWORD", "weakpassword");

-     send_key "ret";

-     wait_still_screen 5;

-     type_string get_var("ROOT_PASSWORD", "weakpassword");

-     send_key "ret";

-     wait_still_screen 7;

+     my $rootpwd = get_var("ROOT_PASSWORD", "weakpassword");

+     run_with_error_check(sub {console_type_wait($spoke_number{"rootpwd"} . "\n")}, $error);

+     console_type_wait("$rootpwd\n");

+     console_type_wait("$rootpwd\n");

  

      # Create user

-     run_with_error_check(sub {type_string $spoke_number{"user"} . "\n"}, "anaconda_text_error");

-     wait_still_screen 5;

-     type_string "1\n"; # create new

-     wait_still_screen 5;

-     type_string "3\n"; # set username

-     wait_still_screen 5;

-     type_string get_var("USER_LOGIN", "test");

-     send_key "ret";

-     wait_still_screen 5;

+     my $userpwd = get_var("USER_PASSWORD", "weakpassword");

+     my $username = get_var("USER_LOGIN", "test");

+     run_with_error_check(sub {console_type_wait($spoke_number{"user"} . "\n")}, $error);

+     console_type_wait("1\n"); # create new

+     console_type_wait("3\n"); # set username

+     console_type_wait("$username\n");

      # from Rawhide-20190503.n.0 (F31) onwards, 'use password' is default

      if (get_release_number() < 31) {

          # typing "4\n" on abrt screen causes system to reboot, so be careful

-         run_with_error_check(sub {type_string "4\n"}, "anaconda_text_error"); # use password

+         run_with_error_check(sub {console_type_wait("4\n")}, $error); # use password

      }

-     wait_still_screen 5;

-     type_string "5\n"; # set password

-     wait_still_screen 5;

-     type_string get_var("USER_PASSWORD", "weakpassword");

-     send_key "ret";

-     wait_still_screen 5;

-     type_string get_var("USER_PASSWORD", "weakpassword");

-     send_key "ret";

-     wait_still_screen 5;

-     type_string "6\n"; # make him an administrator

-     wait_still_screen 5;

-     type_string "c\n";

-     wait_still_screen 7;

+     console_type_wait("5\n"); # set password

+     console_type_wait("$userpwd\n");

+     console_type_wait("$userpwd\n");

+     console_type_wait("6\n"); # make him an administrator

+     console_type_wait("c\n", 7);

  

      my $counter = 0;

-     while (check_screen "anaconda_main_hub_text_unfinished", 2) {

-         if ($counter > 10) {

-             die "There are unfinished spokes in Anaconda";

+     if (testapi::is_serial_terminal) {

+         while (wait_serial("[!]", timeout=>5, quiet=>1)) {

+             if ($counter > 10) {

+                 die "There are unfinished spokes in Anaconda";

+             }

+             sleep 10;

+             $counter++;

+             console_type_wait("r\n"); # refresh

+         }

+     }

+     else {

+         while (check_screen "anaconda_main_hub_text_unfinished", 2) {

+             if ($counter > 10) {

+                 die "There are unfinished spokes in Anaconda";

+             }

+             sleep 10;

+             $counter++;

+             console_type_wait("r\n"); # refresh

          }

-         sleep 10;

-         $counter++;

-         type_string "r\n"; # refresh

      }

  

      # begin installation

-     type_string "b\n";

+     console_type_wait("b\n");

  

      # Wait for install to end. Give Rawhide a bit longer, in case

      # we're on a debug kernel, debug kernel installs are really slow.
@@ -99,8 +125,23 @@ 

      if (lc(get_var('VERSION')) eq "rawhide") {

          $timeout = 2400;

      }

-     assert_screen "anaconda_install_text_done", $timeout;

-     type_string "\n";

+ 

+     if (testapi::is_serial_terminal) {

+         wait_serial("Installation complete", timeout=>$timeout);

+         if (get_var("SERIAL_CONSOLE") && get_var("OFW")) {

+             $self->root_console();

+             # we need to force the system to load a console on both hvc1

+             # and hvc2 for ppc64 serial console post-install tests

+             assert_script_run 'chroot /mnt/sysimage systemctl enable serial-getty@hvc1';

+             assert_script_run 'chroot /mnt/sysimage systemctl enable serial-getty@hvc2';

+             # back to anaconda ui

+             select_console("root-virtio-terminal1");

+         }

+     }

+     else {

+         assert_screen "anaconda_install_text_done", $timeout;

+     }

+     console_type_wait("\n");

  }

  

  

This adds the Anaconda text installation test over
serial console and FIXES #115.

rebased onto 80502249987f57d2228f2b5cfdfa3882e9ed6d61

5 years ago

Metadata Update from @lruzicka:
- Request assigned

5 years ago

1 new commit added

  • Fix white spaces.
5 years ago

2 new commits added

  • Fix white spaces.
  • Enable Anaconda Text install via serial console.
5 years ago

this seems like a pretty useless wrapper. Why not just use testapi::is_serial_terminal directly anyplace we want to check this?

why bother checking equality to 1 (and using the unnecessary wrapper)? why not just write if (testapi::is_serial_terminal) { ?

I kinda feel like I'd prefer if we just convert any place where we do send_key "ret" to type_string "\n" inline, rather than having this. And include sleeps if necessary on a case-by-case basis.

so, uh, I really think we could skip all this at least for now. A large chunk of it is setting up a sort of abstraction around named consoles so those can be used instead of just doing a bunch of send_key 'ctrl-alt-fX'; and trying to keep track of the flow like we do now - which would probably be a good change for us, but would make more sense as a separate PR. Another large chunk of it is dealing with stuff we just don't use - we don't use any backends beside qemu, we don't have s390x workers, we don't use hyperv. I think the only bit of this that the current PR actually needs is the if (check_var('BACKEND', 'qemu')) { block near the top, which we could just do up in sub init() if SERIAL_CONSOLE var is set.

uh...is this intentional and useful somehow, or a typo?

I think this would flow nicer if the logic were reversed. As a general rule, whenever I have a situation like "if (X), do this really simple thing; otherwise, do this much more complicated thing", I like to put the simple thing first, I just find it clearer that way. Also, you should use the timeout arg in the wait_serial command, not just hard code it as 300.

Also you mean "except" not "accept". Darn nearly-homophones. :)

Um. That reads oddly. Doesn't it mean we're always going to record a soft failure here?

Please make this:

}
else {

so the else matches indentation with the if, it's more readable that way.

have you tested what happens here if we run the serial console test on aarch64? :) It'll add both console= args. Probably the second one will 'win' and the test will work, but...might be worth thinking about.

could we reverse the logic here too? I just find unless ... else to be a bit awkward, and it's easy to avoid here by putting the serial console path first, with if (get_var("SERIAL_CONSOLE)) {. if ... else is pretty much universal, unless ... else just reads weirdly, to me.

Maybe console_type should have a bit more of a descriptive name to make it clear that it also has a baked-in wait? console_type_wait or something like that?

this seems like a pretty useless wrapper. Why not just use testapi::is_serial_terminal directly anyplace we want to check this?

Yeah, my first version had exactly this, but then I thought you would not like using the testapi::is_serial_terminal syntax, because we almost never use it in tests, or I have not noticed.

so, uh, I really think we could skip all this at least for now. A large chunk of it is setting up a sort of abstraction around named consoles so those can be used instead of just doing a bunch of send_key 'ctrl-alt-fX'; and trying to keep track of the flow like we do now - which would probably be a good change for us, but would make more sense as a separate PR. Another large chunk of it is dealing with stuff we just don't use - we don't use any backends beside qemu, we don't have s390x workers, we don't use hyperv. I think the only bit of this that the current PR actually needs is the if (check_var('BACKEND', 'qemu')) { block near the top, which we could just do up in sub init() if SERIAL_CONSOLE var is set.

And I knew, you would not like this one, either. You are right that we only need that tiny little piece by now, however I thought this might come handy in the future, when they will buy a lot of s390x to test for IBM and stuff.

Also, using ctrl-alt-f(x) does not work for serial console, so we need at least that tiny bit. I spent like a day finding it out.

uh...is this intentional and useful somehow, or a typo?

That would be a typo, but when I open the file, I do not see that.

3 new commits added

  • Totally deplete the SuSE function and leave whats needed.
  • Make changes according to the review.
  • Enable Anaconda Text install via serial console.
5 years ago

1 new commit added

  • Delete wrong package usage.
5 years ago

1 new commit added

  • Add sleeps to prevent typos.
5 years ago

rebased onto 12ec2fadd9805e0f585f82759199819c3bffa62d

5 years ago

I have updated the pull request according to the review:

  • discarded the check_serial() method and started using testapi::is_serial_terminal
  • discarded the send_safe_enter and used type_string instead, but had to add several sleeps for the test to work on serial console
  • deleted the whole chunk in fedoradistribution.pm and only left the small part to register the serial console. I also moved that bit to the init() sub.
  • checked the typo
  • reversed the conditions where requested
  • corrected the darn nearly-homophone :)
  • added condition to only record soft failure in case of such failure
  • fixed the } else { syntax, although this syntax was recommended in one of the perl books I have read.
  • changed the name of console_type to console_type_wait
  • since console_type_wait was the last one standing in lib/console.pm, I deleted the file and move the sub to lib/utils.pm

Luckily, the tests still do pass. :D

this seems like a pretty useless wrapper. Why not just use testapi::is_serial_terminal directly anyplace we want to check this?

Yeah, my first version had exactly this, but then I thought you would not like using the testapi::is_serial_terminal syntax, because we almost never use it in tests, or I have not noticed.

Well, that's just because most everything we need is exported by default so there's no need, but is_serial_terminal is marked EXPORT_OK not EXPORT so you have to import it explicitly or call it with the module name. To keep it consistent we could explicitly import is_serial_terminal in files where we want to use it:

use testapi;
use testapi qw(is_serial_terminal);

but that's not necessarily any better than just calling it as testapi::is_serial_terminal really.

so, uh, I really think we could skip all this at least for now. A large chunk of it is setting up a sort of abstraction around named consoles so those can be used instead of just doing a bunch of send_key 'ctrl-alt-fX'; and trying to keep track of the flow like we do now - which would probably be a good change for us, but would make more sense as a separate PR. Another large chunk of it is dealing with stuff we just don't use - we don't use any backends beside qemu, we don't have s390x workers, we don't use hyperv. I think the only bit of this that the current PR actually needs is the if (check_var('BACKEND', 'qemu')) { block near the top, which we could just do up in sub init() if SERIAL_CONSOLE var is set.

And I knew, you would not like this one, either. You are right that we only need that tiny little piece by now, however I thought this might come handy in the future, when they will buy a lot of s390x to test for IBM and stuff.
Also, using ctrl-alt-f(x) does not work for serial console, so we need at least that tiny bit. I spent like a day finding it out.

I'd rather just cross those bridges as we come to them, I think. After all, even if we do start needing some of those bits, they may change upstream in the mean time...

The } else { syntax isn't wrong, indeed, this is one of those 'preference' things. But it's good to stay consistent, and we use the two-line syntax everywhere else in the tests.

I assume this was swiped from SUSE? The conditional probably isn't necessary for us, as the backend is always qemu :) It doesn't really hurt anything, though, I suppose.

as the waiting part here is really specific to the text install process, it might make more sense for this function to just live in that file rather than here.

I think this should be fixable. can't you just do:

my $rootpw = get_var("ROOT_PASSWORD", "weakpassword");
console_type_wait("$rootpw\n");

to avoid the need to have an extra command and sleep, here and in the other places where you did this?

Aside from the few extra notes this is looking good, thanks!

Thanks for the comments, I'll go through it the first thing in the morning.

1 new commit added

  • Add changes per review.
5 years ago

1 new commit added

  • Delete export from utils.pm
5 years ago

rebased onto 578ea06628430703bf9db3f722895cdb1d6a6099

5 years ago

rebased onto 459677ad835b2151565f0ade39cf25be96b0e5f0

5 years ago

rebased onto 708985f551ac2a529918470ef1b2c4b6396446a9

5 years ago

I think this time it might be finished.

rebased onto 292775bc40179e6b53d126bbea853c76d4225353

5 years ago

rebased onto c59563ac455430e8fa6884a0c5564be61508afaf

5 years ago

rebased onto bb6b9c3611c1d54ddeae2d6de590069c5d6cfc67

5 years ago

OK, so I just went over it again and fixed several things. You still had several whitespace errors - trailing whitespace, lines with nothing but space characters, a tab instead of a space in one place. At the end of console_login indentation was incorrect, and the _console_login_finish() call was inside the else block, meaning we never actually ran it on the serial console path (so now we get to see if it actually works there). Also I moved console_type_wait into install_text.pm as I suggested since that's the only place it's used and we don't really need to introduce a whole new module just for that function, and I had run_with_error_check pass expect_not_found arg to wait_serial, because otherwise every time it checks for the error message and doesn't find it (which is what we want), this is recorded as a 'failure' frame by openQA and shown with a red border in the web UI, which is confusing. Finally I added the test to aarch64 and ppc64le as well as x86_64.

I'm testing my changes now and will merge once they seem to be working, thanks.

rebased onto 04210b11183e8070945fe5de3b223a5c42d73bdd

5 years ago

rebased onto 57a6e9f7ca713f874340f65bb090cb27bab589d7

5 years ago

rebased onto aa65d3964fc752eb06e2c91364df887ebd2718bf

5 years ago

rebased onto 089a21c2f0e5ed59303fa42dab8c268924a997d7

5 years ago

rebased onto a277550b469fa44093edc694908bdbd3d47522d2

5 years ago

rebased onto 1744aa1cc172bae9f055bd210d4151252b3e008a

5 years ago

rebased onto cfa7a442f91a2e2b6f894ec8a056e95f7768c22b

5 years ago

rebased onto 04a7a329db46d4361e6b7893a1dbc4ab40c2cb0b

5 years ago

rebased onto a92f6fcf7241a55524a82ad933b8ee2b0816f6e1

5 years ago

rebased onto 59a4649e7b173b51e2c06d2c8d7d64318103566c

5 years ago

rebased onto e3c7559f035578dd2d3ff7492db53ef3153835c7

5 years ago

rebased onto 209860bd0315ff0f8d771788420aea7cebf03db7

5 years ago

rebased onto 46bb5dfe5cf3cf10026cbe2570921da671742b44

5 years ago

rebased onto 04a2cc95d92bc993172d876f8875cc2ec7d4c129

5 years ago

rebased onto 2e3de96007be96b878a951d73bed642bb0c35526

5 years ago

OK, so I had a ton of fun with this today, which I'll note down here for posterity. There's a reason why power introduces a ton of wrinkles here.

os-autoinst by default does these qemu params:

-chardev ringbuf,id=serial0,logfile=serial0,logappend=on -serial chardev:serial0 ... -device virtio-serial -chardev socket,path=virtio_console,server,nowait,id=virtio_console,logfile=virtio_console.log,logappend=on -device virtconsole,chardev=virtio_console,name=org.openqa.console.virtio_console

if you pass VIRTIO_CONSOLE_NUM as a number greater than 1, it will create more virtio consoles, named virtio_console1, virtio_console2 etc. So - basically we have a 'standard' serial port, sorta-named 'serial0', plus some additional virtio serial consoles, by default just one.

On most arches, serial0 shows up as the tty ttyS0, and the first virtio serial console shows up as the tty hvc0, the second as hvc1 and so on. But...on power, for some goddamn reason to do with the firmware or something, serial0 shows up as the tty hvc0, not ttyS0. So the first virtio serial console shows up as tty hvc1, the second as tty hvc2 and so on.

So on x86_64 and aarch64 when we do select_console('root-virtio-terminal'); we are activating the console that maps to the tty hvc0, but on power, it's hvc1.

openQA has some annoying logging quirks which don't help here either. The log file for the device 'serial0' - so usually ttyS0, but on power, hvc0 - is serial0.txt. The log file for the first virtio console is serial-terminal.txt. The log files for subsequent virtio consoles are virtio_console1.log, virtio_console2.log and so on. Messages from serial0 and the first virtio console are shown in the live serial log while the test is running, but messages from the later virtio consoles are not. The log files for the later virtio consoles are uploaded as assets when the test ends, but in stock openQA they are not shown in the web UI - you have to just know that you can browse to a URL like https://openqa.stg.fedoraproject.org/tests/673451/file/virtio_console1.log to see them. (I have hacked up staging openQA to show them in the web UI for now).

It also turned out to be useful to know anaconda's behaviour for where it puts the anaconda text interface itself and where it loads a shell. This can be found in data/systemd/anaconda-generator in the anaconda source tree. Basically anaconda will load the tmux where its text interface runs on whatever is considered the "console tty", as determined by following the contents of /sys/class/tty/console/active (exactly which console this will be is a whole other can of worms, but if you pass console=(something) as a boot arg it will usually be that console). It will then check hvc0 and hvc1 in that order (and a few others we don't care about here) and launch a root shell on the first one that exists and is not the "console tty". So if the anaconda UI launched on hvc0 and hvc1 exists too, hvc1 will get a root shell.

There's also some fun around which consoles get ttys run on them in the installed system; you will get a tty on hvc0 if it exists, and on the 'console tty' (so if you have console=hvc1 on cmdline you'll likely get a tty on hvc1), but you won't necessarily get a tty on hvc1 or hvc2 if they are not the 'console tty', you need to manually activate the systemd services.

rebased onto deda506b1f21430689438cfafdd6c3596c023f84

5 years ago

rebased onto b6e5581c68012aec41efdf6e47b72b9a926dc599

5 years ago

rebased onto 1217bc3

5 years ago

OK, so I finally got this working in all cases (I hope, will kick off a final check tonight). Bearing in mind all of the above, I tweaked things so during the install phase, a root console is always available on the first virtio console (whether that's hvc0 or hvc1) and the installer runs on the second; with your original approach the test was broken on power and on x86_64/aarch64 the installer ran on the first virtio console and there was no root shell console available, so e.g. the post fail hook could never work. I also tweaked things to make sure that we get a tty on both virtio consoles after install on ppc64; I had to dig about a bit in systemd internals and stuff but it turns out there's basically no way (at least that I can find) to make this happen 'automatically', we just have to enable the appropriate services in post-install like this. On x86_64/aarch64 we get a tty on hvc0 because that's kinda hardwired into systemd and we get one on hvc1 because we have console=hvc1 on the cmdline and that makes systemd run a tty on hvc1, but on power we have console=hvc2 on the cmdline so we get a console on hvc2, but there's no mechanism to auto-spawn a tty on hvc1.

er, and I merged this manually so I can't hit the merge button, d'oh.

Pull-Request has been closed by adamwill

5 years ago

Wow, it looks I only approached the problems and never actually had met them in person. I bow for you. Thanks a lot.