#311 Go back to having update tests download their own packages, but use a downloader script and run from a serial console (#108)
Merged 4 months ago by adamwill. Opened 4 months ago by adamwill.

file modified
+3 -4
@@ -313,14 +313,13 @@ 

      # It is used in the `install_text.pm` test and can be switched on by using the CRASH_REPORT

      # variable set to 1.

      #

-     # First let us navigate to reach the shell window in Anaconda using the alt-f3 combo,

-     # this should take us to another terminal, where we can simulate the crash.

-     send_key "alt-f3";

+     # tty3 has a shell on all f31+ installer and live images

+     select_console "tty3-console";

      assert_screen("anaconda_text_install_shell");

      # We use the trigger command to do the simulated crash.

      type_string "kill -USR1 `cat /var/run/anaconda.pid`\n";

      # And navigate back to the main panel of Anaconda. This should require

-     send_key "alt-f1";

+     select_console "tty1-console";

      assert_screen("anaconda_text_install_main");

      # We wait until the crash menu appears. This usually takes some time,

      # so let's try for 300 seconds, this should be long enough.

file modified
+1 -1
@@ -141,7 +141,7 @@ 

      }

      else {

          # tty3 has a shell on all f31+ installer and live images

-         send_key "ctrl-alt-f3";

+         select_console "tty3-console";

      }

      console_login(user => "root", timeout => $args{timeout});

  }

file modified
+8 -2
@@ -20,7 +20,7 @@ 

  

  # 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 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
@@ -48,6 +48,12 @@ 

              # "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});

      }

  }

  
@@ -79,7 +85,7 @@ 

          # 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");

+         select_console "tty3-console";

          # Let's wait to allow for screen changes.

          sleep 5;

          # And do the login.

file modified
+2 -2
@@ -9,7 +9,7 @@ 

  # should be used when with tests, where system is already installed, e. g all parts

  # of upgrade tests, postinstall phases...

  

- use testapi qw(is_serial_terminal :DEFAULT);

+ use testapi qw(is_serial_terminal :DEFAULT select_console);

  use utils;

  

  sub root_console {
@@ -27,7 +27,7 @@ 

      }

      else {

          # For normal terminal emulation, use key combo to reach a tty

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

+         select_console "tty$args{tty}-console";

      }

      console_login(timeout => $args{timeout});    # Do the login.

  }

file modified
+176 -105
@@ -6,8 +6,8 @@ 

  use Exporter;

  

  use lockapi;

- use testapi;

- our @EXPORT = qw/run_with_error_check type_safely type_very_safely desktop_vt boot_to_login_screen console_login console_switch_layout desktop_switch_layout console_loadkeys_us do_bootloader boot_decrypt check_release menu_launch_type repo_setup setup_workaround_repo disable_updates_repos mount_update_image umount_update_image cleanup_workaround_repo console_initial_setup handle_welcome_screen gnome_initial_setup anaconda_create_user check_desktop download_modularity_tests quit_firefox advisory_get_installed_packages advisory_check_nonmatching_packages start_with_launcher quit_with_shortcut disable_firefox_studies select_rescue_mode copy_devcdrom_as_isofile get_release_number check_left_bar check_top_bar check_prerelease check_version spell_version_number _assert_and_click is_branched rec_log repos_mirrorlist register_application get_registered_applications solidify_wallpaper check_and_install_git download_testdata make_serial_writable set_update_notification_timestamp/;

+ use testapi qw(is_serial_terminal :DEFAULT);

+ our @EXPORT = qw/run_with_error_check type_safely type_very_safely desktop_vt boot_to_login_screen console_login console_switch_layout desktop_switch_layout console_loadkeys_us do_bootloader boot_decrypt check_release menu_launch_type setup_repos repo_setup get_workarounds disable_updates_repos cleanup_workaround_repo console_initial_setup handle_welcome_screen gnome_initial_setup anaconda_create_user check_desktop download_modularity_tests quit_firefox advisory_get_installed_packages advisory_check_nonmatching_packages start_with_launcher quit_with_shortcut disable_firefox_studies select_rescue_mode copy_devcdrom_as_isofile get_release_number check_left_bar check_top_bar check_prerelease check_version spell_version_number _assert_and_click is_branched rec_log repos_mirrorlist register_application get_registered_applications solidify_wallpaper check_and_install_git download_testdata make_serial_writable set_update_notification_timestamp/;

  

  

  # We introduce this global variable to hold the list of applications that have
@@ -163,7 +163,7 @@ 

      # 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")) {

+     if (get_var("SERIAL_CONSOLE") || is_serial_terminal()) {

          # Check for the usual prompt.

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

              type_string "logout\n";
@@ -173,7 +173,7 @@ 

          # Do the new login.

          type_string $args{user};

          type_string "\n";

-         sleep 2;

+         wait_serial("Password:", timeout => 2, quiet => 1);

          type_string $args{password};

          type_string "\n";

          # Let's perform a simple login test. This is the same as
@@ -285,7 +285,7 @@ 

      while ($xout =~ /tty(\d)/g) {

          $tty = $1;    # most recent match is probably best

      }

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

+     select_console "tty${tty}-console";

      # work around https://gitlab.gnome.org/GNOME/gnome-software/issues/582

      # if it happens. As of 2019-05, seeing something similar on KDE too

      my $desktop = get_var('DESKTOP');
@@ -302,10 +302,10 @@ 

          click_lastmatch if ($desktop eq 'kde');

          if (match_has_tag "auth_required_fprint") {

              my $user = get_var("USER_LOGIN", "test");

-             send_key "ctrl-alt-f6";

+             select_console "tty6-console";

              console_login;

              assert_script_run "echo SCAN ${user}-finger-1 | socat STDIN UNIX-CONNECT:/run/fprintd-virt";

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

+             select_console "tty${tty}-console";

          }

          elsif (match_has_tag "auth_required_locked") {

              # When console operation takes a long time, the screen locks
@@ -463,58 +463,31 @@ 

      assert_script_run "sed -i -e 's,metalink,mirrorlist,g' ${files}";

  }

  

- sub mount_update_image {

-     # mount the update and workarounds images (whichever are attached)

-     if (get_var("ISO_2") && script_run "grep updateiso /proc/mounts") {

-         script_run "mkdir -p /mnt/updateiso";

-         my $devnode = "/dev/sr0";

-         $devnode = "/dev/sr1" if (get_var("ISO") || get_var("ISO_1"));

-         assert_script_run 'echo "' . $devnode . ' /mnt/updateiso iso9660 loop 0 0" >> /etc/fstab';

-         assert_script_run "mount /mnt/updateiso";

-     }

-     if (get_var("ISO_3") && script_run "grep workaroundsiso /proc/mounts") {

-         script_run "mkdir -p /mnt/workaroundsiso";

-         my $devnum = 0;

-         $devnum++ if (get_var("ISO") || get_var("ISO_1"));

-         $devnum++ if (get_var("ISO_2"));

-         my $devnode = "/dev/sr${devnum}";

-         assert_script_run 'echo "' . $devnode . ' /mnt/workaroundsiso iso9660 loop 0 0" >> /etc/fstab';

-         assert_script_run "mount /mnt/workaroundsiso";

+ sub get_setup_repos_script {

+     # ensure the 'setup_repos.py' downloader script is present

+     if (script_run "ls /usr/local/bin/setup_repos.py") {

+         assert_script_run 'curl --retry-delay 10 --max-time 30 --retry 5 -o /usr/local/bin/setup_repos.py https://pagure.io/fedora-qa/os-autoinst-distri-fedora/raw/concdl/f/setup_repos.py', timeout => 180;

+         assert_script_run 'chmod ugo+x /usr/local/bin/setup_repos.py';

      }

  }

  

- sub umount_update_image {

-     # inverse of mount_update_image

-     assert_script_run "sed -i '/updateiso/d' /etc/fstab" if (get_var("ISO_2"));

-     assert_script_run "sed -i '/workaroundsiso/d' /etc/fstab" if (get_var("ISO_3"));

-     assert_script_run "umount /mnt/updateiso" unless (!get_var("ISO_2") || script_run "grep updateiso /proc/mounts");

-     assert_script_run "umount /mnt/workaroundsiso" unless (!get_var("ISO_3") || script_run "grep workaroundsiso /proc/mounts");

+ sub get_workarounds {

+     my $version = shift || get_var("VERSION");

+     my %workarounds = (

+         "38" => [],

+         "39" => [],

+         "40" => [],

+     );

+     my $advortasks = $workarounds{$version};

+     return @$advortasks;

  }

  

  sub cleanup_workaround_repo {

      # clean up the workaround repo (see next).

+     script_run "rm -rf /mnt/workarounds_repo";

      script_run "rm -f /etc/yum.repos.d/workarounds.repo";

  }

  

- sub setup_workaround_repo {

-     # we periodically need to pull an update from updates-testing in

-     # to fix some bug or other. so, here's an organized way to do it.

-     # the code that builds the image, and the workaround lists, are

-     # in fedora_openqa schedule.py. If there are no workarounds, we

-     # don't get an ISO

-     return unless (get_var("ISO_3"));

-     my $version = shift || get_var("VERSION");

-     cleanup_workaround_repo;

-     mount_update_image;

-     # write a repo config file, unless this is the support_server test

-     # and it is running on a different release than the update is for

-     # (in this case we need the repo to exist but do not want to use

-     # it on the actual support_server system)

-     unless (get_var("TEST") eq "support_server" && $version ne get_var("CURRREL")) {

-         assert_script_run 'printf "[workarounds]\nname=Workarounds repo\nbaseurl=file:///mnt/workaroundsiso/workarounds_repo\nenabled=1\nmetadata_expire=1\ngpgcheck=0" > /etc/yum.repos.d/workarounds.repo';

-     }

- }

- 

  sub disable_updates_repos {

      # disable updates-testing, or both updates-testing and updates.

      # factors out similar code in a few different places.
@@ -556,13 +529,105 @@ 

      # }

  }

  

+ sub _prepare_update_mount {

+     # create and mount the filesystem where we will store update/task packages

+     # this is separate from setup_repos as it has to happen before we

+     # enter the toolbox container on the CANNED workflow

+     assert_script_run "mkdir -p /mnt/update_repo";

+     # if NUMDISKS is above 1, assume we want to put the update repo on

+     # the second disk (to avoid huge updates exhausting space on the main

+     # disk)

+     if (get_var("NUMDISKS") > 1) {

+         # I think the disk will always be vdb. This creates a single large

+         # partition.

+         assert_script_run "echo 'type=83' | sfdisk /dev/vdb";

+         assert_script_run "mkfs.ext4 /dev/vdb1";

+         assert_script_run "echo '/dev/vdb1 /mnt/update_repo ext4 defaults 1 2' >> /etc/fstab";

+         assert_script_run "mount /mnt/update_repo";

+     }

+     assert_script_run "cd /mnt/update_repo";

+ }

+ 

+ sub setup_repos {

+     # setup workarounds (if necessary) and updates or tag repositories,

+     # using the setup_repos.py script. It's necessary to set up repos

+     # (rather than just downloading the RPMs and doing a one-time update)

+     # for various reasons: to ensure later package operations use the

+     # update packages, and for use when creating deliverables in the

+     # tests that do that. Has a 'workarounds only' mode for

+     # upgrade_preinstall to use (in case we need workarounds for the

+     # pre-upgrade environment)

+     my %args = (

+         # workarounds only

+         waonly => 0,

+         # release to get workarounds for

+         version => get_var("VERSION"),

+         # whether to write repo configs

+         configs => 1,

+         @_

+     );

+     my $arch = get_var("ARCH");

+     my $tag = get_var("TAG");

+     # write the tag repo config if appropriate

+     assert_script_run 'printf "[openqa-testtag]\nname=openqa-testtag\nbaseurl=https://kojipkgs.fedoraproject.org/repos/' . "$tag/latest/$arch" . '/\ncost=2000\nenabled=1\ngpgcheck=0\n" > /etc/yum.repos.d/openqa-testtag.repo' if ($tag && !$args{waonly});

+     my @was = get_workarounds($args{version});

+     # bail if there are no workarounds:

+     # * if we're in workarounds-only mode

+     # * if we're testing a side tag (so no packages to dl)

+     if ($args{waonly} || $tag) {

+         return unless (@was);

+     }

+     # if we got this far, we're definitely downloading *something*

+     script_run "dnf -y install createrepo_c bodhi-client koji", 300;

+     get_setup_repos_script;

+     my $wastring = join(',', @was);

+     my $udstring;

+     # work out the list of update/task NVRs to test

+     if (get_var("ADVISORY_NVRS") || get_var("ADVISORY_NVRS_1")) {

+         # regular update case

+         # old style single ADVISORY_NVRS var

+         my @nvrs = split(/ /, get_var("ADVISORY_NVRS"));

+         unless (@nvrs) {

+             # new style chunked ADVISORY_NVRS_N vars

+             my $count = 1;

+             while ($count) {

+                 if (get_var("ADVISORY_NVRS_$count")) {

+                     push @nvrs, split(/ /, get_var("ADVISORY_NVRS_$count"));

+                     $count++;

+                 }

+                 else {

+                     $count = 0;

+                 }

+             }

+         }

+         $udstring = join(',', @nvrs);

+     }

+     elsif (get_var("KOJITASK")) {

+         # Koji task case (KOJITASK will be set). If multiple tasks,

+         # they're concatenated with underscores, switch to commas

+         $udstring =~ s/_/,/;

+     }

+     else {

+         die "Neither ADVISORY_NVRS nor KOJITASK set! Don't know what to do";

+     }

+     my $cmd = "/usr/local/bin/setup_repos.py";

+     # don't download updates if we're in workarounds-only mode or testing a tag

+     $cmd .= " -u $udstring" unless ($args{waonly} || $tag);

+     $cmd .= " -w $wastring" if (@was);

+     # write repo config files if asked

+     $cmd .= " -c" if ($args{configs});

+     $cmd .= " $arch";

+     assert_script_run $cmd, 600;

+     unless ($args{waonly} || $tag) {

+         upload_logs "/mnt/updatepkgnames.txt";

+         upload_logs "/mnt/updatepkgs.txt";

+     }

+ }

+ 

  sub _repo_setup_updates {

      # Appropriate repo setup steps for testing a Bodhi update

-     # sanity check

-     die "_repo_setup_updates called, but ISO_2 is not attached!" unless (get_var("ISO_2") || get_var("TAG"));

-     mount_update_image if (get_var("ISO_2"));

      # Check if we already ran, bail if so

-     return unless script_run "test -f /root/.oqarsurun";

+     return unless script_run "test -f /mnt/updatepkgs.txt";

      my $version = get_var("VERSION");

      my $currrel = get_var("CURRREL", "0");

      my $arch = get_var("ARCH");
@@ -571,65 +636,77 @@ 

      # unless (script_run 'pushd /etc/yum.repos.d && tar czvf yumreposd.tar.gz * && popd') {

      #     upload_logs "/etc/yum.repos.d/yumreposd.tar.gz";

      # }

+     # if no current console is registered, assume we're on tty1

+     my $currcon = current_console || "tty1-console";

+     # do all this setup from a serial console for speed (especially when

+     # downloading large updates)

+     # the console we register as 'virtio-console' is the first virtio

+     # serial console, 'virtio_console' on the qemu command line.

+     # on most platforms, this console is /dev/hvc0 (and the default

+     # qemu serial console, which for openQA is backed by a ringbuf

+     # device and logged as serial0.txt, is /dev/ttyS0). however, on

+     # Power, the default serial console is /dev/hvc0 and the first

+     # virtio serial console is /dev/hvc1.

+     # it seems we get a getty on ttyS0 and hvc0 by default, but we

+     # don't get one on hvc1. so on Power, start a tty on hvc1

+     assert_script_run 'systemctl start serial-getty@hvc1.service' if (get_var("OFW"));

+     script_run "echo 'Package download and repo creation happening on serial console...'";

+     select_console("virtio-console");

+     console_login();

+     # prepare the directory the packages will be downloaded to, unless we're

+     # testing a side tag

+     _prepare_update_mount() unless ($tag);

  

-     # Set up an additional repo containing the update or task packages. We do

-     # this rather than simply running a one-time update because it may be the

-     # case that a package from the update isn't installed *now* but will be

-     # installed by one of the tests; by setting up a repo containing the

-     # update and enabling it here, we ensure all later 'dnf install' calls

-     # will get the packages from the update.

      # on CANNED, we need to enter the toolbox at this point

      if (get_var("CANNED")) {

          type_string "toolbox -y enter\n";

-         # look for the little purple dot

-         assert_screen "console_in_toolbox", 180;

+         # this is simply to wait till we're in the toolbox

+         assert_script_run "true", 180;

      }

+ 

      # use mirrorlist not metalink in repo configs

      repos_mirrorlist();

      # Disable updates-testing so other bad updates don't break us

      disable_updates_repos(both => 0) if ($version > $currrel);

      # use the buildroot repo on Rawhide: see e.g.

      # https://pagure.io/fedora-ci/general/issue/376 for why

-     if ($version eq get_var("RAWREL") && get_var("TEST") ne "support_server") {

-         assert_script_run 'printf "[koji-rawhide]\nname=koji-rawhide\nbaseurl=https://kojipkgs.fedoraproject.org/repos/f' . $version . '-build/latest/' . $arch . '/\ncost=2000\nenabled=1\nmetadata_expire=30\ngpgcheck=0\nskip_if_unavailable=1\n" > /etc/yum.repos.d/koji-rawhide.repo';

-     }

-     # set up the workaround repo

-     setup_workaround_repo;

-     upload_logs "/mnt/updateiso/updatepkgnames.txt" unless ($tag);

-     upload_logs "/mnt/updateiso/updatepkgs.txt" unless ($tag);

-     # write a repo config file, unless this is the support_server test

-     # and it is running on a different release than the update is for

-     # (in this case we need the repo to exist but do not want to use

-     # it on the actual support_server system)

-     unless (get_var("TEST") eq "support_server" && $version ne get_var("CURRREL")) {

-         if ($tag) {

-             assert_script_run 'printf "[openqa-testtag]\nname=openqa-testtag\nbaseurl=https://kojipkgs.fedoraproject.org/repos/' . "$tag/latest/$arch" . '/\ncost=2000\nenabled=1\ngpgcheck=0\n" > /etc/yum.repos.d/openqa-testtag.repo';

-         }

-         else {

-             assert_script_run 'printf "[advisory]\nname=Advisory repo\nbaseurl=file:///mnt/updateiso/update_repo\nenabled=1\nmetadata_expire=3600\ngpgcheck=0" > /etc/yum.repos.d/advisory.repo';

-         }

+     if (get_var("VERSION") eq get_var("RAWREL") && get_var("TEST") ne "support_server") {

+         assert_script_run 'printf "[koji-rawhide]\nname=koji-rawhide\nbaseurl=https://kojipkgs.fedoraproject.org/repos/rawhide/latest/' . $arch . '/\ncost=2000\nenabled=1\ngpgcheck=0\n" > /etc/yum.repos.d/koji-rawhide.repo';

+     }

+     if (get_var("CANNED")) {

+         # install and use en_US.UTF-8 locale for consistent sort

+         # ordering

+         assert_script_run "dnf -y install glibc-langpack-en", 300;

+         assert_script_run "export LC_ALL=en_US.UTF-8";

+     }

+     # set up workarounds and updates repos (if needed)

+     if (get_var("TEST") eq "support_server" && $version ne get_var("CURRREL")) {

+         # don't write repo configs if this is the support_server test

+         # and it is running on a different release than the update is for

+         # (in this case we need the repo to exist but do not want to use

+         # it on the actual support_server system)

+         setup_repos(configs => 0);

+     }

+     else {

+         setup_repos(configs => 1);

          # run an update now, except for upgrade or install tests,

          # where the updated packages should have been installed

          # already and we want to fail if they weren't, or CANNED

          # tests, there's no point updating the toolbox

          script_run "dnf -y update", 1200 unless (get_var("UPGRADE") || get_var("INSTALL") || get_var("CANNED"));

-         # work around update removing 'dnf' command for the dnf5

-         # revert: https://bodhi.fedoraproject.org/updates/FEDORA-2023-5fd964c1bf#comment-3149533

-         if (get_var("ADVISORY_OR_TASK") eq "FEDORA-2023-5fd964c1bf") {

-             script_run "dnf5 -y --best install 'dnf < 5'", 300 unless (get_var("UPGRADE") || get_var("INSTALL") || get_var("CANNED"));

-         }

          # on liveinst tests, we'll remove the packages we installed

          # above (and their deps, which dnf will include automatically),

          # just in case they're in the update under test; otherwise we

          # get a bogus failure for the package not being updated

-         script_run "dnf -y remove bodhi-client createrepo koji", 600 if (get_var("INSTALL") && !get_var("CANNED"));

+         script_run "dnf -y remove bodhi-client createrepo_c koji", 600 if (get_var("INSTALL") && !get_var("CANNED"));

      }

      # exit the toolbox on CANNED

      if (get_var("CANNED")) {

          type_string "exit\n";

-         wait_still_screen 5;

+         wait_serial "# ";

      }

-     assert_script_run "touch /root/.oqarsurun";

+     # flip back to whatever console we were on before

+     select_console $currcon;

  }

  

  sub repo_setup {
@@ -1009,9 +1086,9 @@ 

      my ($whitelist) = @_;

      # we need python3-yaml for the script to run

      assert_script_run 'dnf -y install python3-yaml', 180;

-     assert_script_run 'curl --verbose --retry-delay 10 --max-time 30 --retry 5 -o /root/test.py https://pagure.io/fedora-qa/modularity_testing_scripts/raw/master/f/modular_functions.py', timeout => 180;

+     assert_script_run 'curl --retry-delay 10 --max-time 30 --retry 5 -o /root/test.py https://pagure.io/fedora-qa/modularity_testing_scripts/raw/master/f/modular_functions.py', timeout => 180;

      if ($whitelist eq 'whitelist') {

-         assert_script_run 'curl --verbose --retry-delay 10 --max-time 30 --retry 5 -o /root/whitelist https://pagure.io/fedora-qa/modularity_testing_scripts/raw/master/f/whitelist', timeout => 180;

+         assert_script_run 'curl --retry-delay 10 --max-time 30 --retry 5 -o /root/whitelist https://pagure.io/fedora-qa/modularity_testing_scripts/raw/master/f/whitelist', timeout => 180;

      }

      assert_script_run 'chmod 755 /root/test.py';

  }
@@ -1111,21 +1188,18 @@ 

  sub advisory_get_installed_packages {

      # can't do anything useful when testing a side tag

      return if (get_var("TAG"));

-     # sanity check

-     die "advisory_get_installed_packages, but ISO_2 is not attached!" unless (get_var("ISO_2"));

-     mount_update_image;

      # bail out if the file doesn't exist: this is in case we get

      # here in the post-fail hook but we failed before creating it

-     return if script_run "test -f /mnt/updateiso/updatepkgs.txt";

+     return if script_run "test -f /mnt/updatepkgs.txt";

      assert_script_run 'rpm -qa --qf "%{SOURCERPM} %{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE}\n" | sort -u > /tmp/allpkgs.txt', timeout => 90;

      # this finds lines which appear in both files

      # http://www.unix.com/unix-for-dummies-questions-and-answers/34549-find-matching-lines-between-2-files.html

-     if (script_run 'comm -12 /tmp/allpkgs.txt /mnt/updateiso/updatepkgs.txt > /mnt/testedpkgs.txt') {

+     if (script_run 'comm -12 /tmp/allpkgs.txt /mnt/updatepkgs.txt > /mnt/testedpkgs.txt') {

          # occasionally, for some reason, it's unhappy about sorting;

          # we shouldn't fail the test in this case, just upload the

          # files so we can see why...

          upload_logs "/tmp/allpkgs.txt", failok => 1;

-         upload_logs "/mnt/updateiso/updatepkgs.txt", failok => 1;

+         upload_logs "/mnt/updatepkgs.txt", failok => 1;

      }

      # we'll try and upload the output even if comm 'failed', as it

      # does in fact still write it in some cases
@@ -1144,19 +1218,16 @@ 

      );

      # can't do anything useful when testing a side tag

      return if (get_var("TAG"));

-     # sanity check

-     die "advisory_check_nonmatching_packages called, but ISO_2 is not attached!" unless (get_var("ISO_2"));

-     mount_update_image;

      # bail out if the file doesn't exist: this is in case we get

      # here in the post-fail hook but we failed before creating it

-     return if script_run "test -f /mnt/updateiso/updatepkgnames.txt";

+     return if script_run "test -f /mnt/updatepkgnames.txt";

      # if this fails in advisory_post, we don't want to do it *again*

      # unnecessarily in post_fail_hook

      return if (get_var("_ACNMP_DONE"));

      script_run 'touch /tmp/installedupdatepkgs.txt';

      # this creates /tmp/installedupdatepkgs.txt as a sorted list of installed

      # packages with the same name as packages from the update, in the same form

-     # as /mnt/updateiso/updatepkgs.txt. The '--last | head -1' tries to handle the

+     # as /mnt/updatepkgs.txt. The '--last | head -1' tries to handle the

      # problem of installonly packages like the kernel, where we wind up with

      # *multiple* versions installed after the update; the first line of output

      # for any given package with --last is the most recent version, i.e. the
@@ -1167,15 +1238,15 @@ 

      # (we need four to reach bash, and half of them get eaten by perl or

      # something along the way). Yes, it only works with *single* quotes. Yes,

      # I hate escaping

-     script_run 'for pkg in $(cat /mnt/updateiso/updatepkgnames.txt); do rpm -q $pkg && rpm -q $pkg --last | head -1 | cut -d" " -f1 | sed -e \'s,\^,\\\\\\\\^,g\' | xargs rpm -q --qf "%{SOURCERPM} %{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE}\n" >> /tmp/installedupdatepkgs.txt; done', timeout => 180;

+     script_run 'for pkg in $(cat /mnt/updatepkgnames.txt); do rpm -q $pkg && rpm -q $pkg --last | head -1 | cut -d" " -f1 | sed -e \'s,\^,\\\\\\\\^,g\' | xargs rpm -q --qf "%{SOURCERPM} %{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE}\n" >> /tmp/installedupdatepkgs.txt; done', timeout => 180;

      script_run 'sort -u -o /tmp/installedupdatepkgs.txt /tmp/installedupdatepkgs.txt';

      # for debugging, may as well always upload these, can't hurt anything

      upload_logs "/tmp/installedupdatepkgs.txt", failok => 1;

-     upload_logs "/mnt/updateiso/updatepkgs.txt", failok => 1;

+     upload_logs "/mnt/updatepkgs.txt", failok => 1;

      # download the check script and run it

-     assert_script_run 'curl --verbose --retry-delay 10 --max-time 30 --retry 5 -o updvercheck.py https://pagure.io/fedora-qa/os-autoinst-distri-fedora/raw/main/f/updvercheck.py', timeout => 180;

+     assert_script_run 'curl --retry-delay 10 --max-time 30 --retry 5 -o updvercheck.py https://pagure.io/fedora-qa/os-autoinst-distri-fedora/raw/main/f/updvercheck.py', timeout => 180;

      my $advisory = get_var("ADVISORY");

-     my $cmd = 'python3 ./updvercheck.py /mnt/updateiso/updatepkgs.txt /tmp/installedupdatepkgs.txt';

+     my $cmd = 'python3 ./updvercheck.py /mnt/updatepkgs.txt /tmp/installedupdatepkgs.txt';

      $cmd .= " $advisory" if ($advisory);

      my $ret = script_run $cmd;

      # 2 is warnings only, 3 is problems, 1 means the script died in
@@ -1560,7 +1631,7 @@ 

      assert_script_run("mkdir temp");

      assert_script_run("cd temp");

      # Download the compressed file with the repository content.

-     assert_script_run("curl --verbose --retry-delay 10 --max-time 120 --retry 5 -o repository.tar.gz https://pagure.io/fedora-qa/openqa_testdata/blob/thetree/f/repository.tar.gz", timeout => 600);

+     assert_script_run("curl --retry-delay 10 --max-time 120 --retry 5 -o repository.tar.gz https://pagure.io/fedora-qa/openqa_testdata/blob/thetree/f/repository.tar.gz", timeout => 600);

      # Untar it.

      assert_script_run("tar -zxvf repository.tar.gz");

      # Copy out the files into the VMs directory structure.

file added
+217
@@ -0,0 +1,217 @@ 

+ #!/usr/bin/python3

+ 

+ # Copyright Red Hat

+ #

+ # This file is part of os-autoinst-distri-fedora.

+ #

+ # This file is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation, either version 3 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License

+ # along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ #

+ # Author: Adam Williamson <awilliam@redhat.com>

+ 

+ """

+ Package download and repository setup script for openQA update tests.

+ This script uses asyncio to download the packages to be tested, and

+ any 'workaround' packages, concurrently, and create repositories and

+ repository configuration files for them. This is work that used to be

+ done in-line in the test scripts, but doing it that way is slow for

+ large multi-package updates.

+ """

+ 

+ import argparse

+ import asyncio

+ import glob

+ import os

+ import pathlib

+ import shutil

+ import subprocess

+ import sys

+ 

+ # these are variables to make testing this script easier...change them

+ # to /tmp for testing

+ WORKAROUNDS_DIR = "/mnt/workarounds_repo"

+ UPDATES_DIR = "/mnt/update_repo"

+ UPDATES_FILE_PATH = "/mnt"

+ 

+ 

+ class DownloadError(Exception):

+     """Exception raised when package download fails."""

+     pass

+ 

+ 

+ # thanks, https://stackoverflow.com/questions/63782892

+ async def run_command(*args, **kwargs):

+     """

+     Run a command with subprocess such that we can run multiple

+     concurrently.

+     """

+     # Create subprocess

+     process = await asyncio.create_subprocess_exec(

+         *args,

+         # stdout must a pipe to be accessible as process.stdout

+         stderr=asyncio.subprocess.PIPE,

+         stdout=asyncio.subprocess.PIPE,

+         **kwargs,

+     )

+     # Wait for the subprocess to finish

+     stdout, stderr = await process.communicate()

+     # Return retcode, stdout and stderr

+     return (process.returncode, stdout.decode().strip(), stderr.decode().strip())

+ 

+ 

+ async def download_item(item, arch, targetdir):

+     """

+     Download something - a build or task (with koji) or an update

+     (with bodhi).

+     """

+     print(f"Downloading item {item}")

+     if item.isdigit():

+         # this will be a task ID

+         cmd = ("koji", "download-task", f"--arch={arch}", "--arch=noarch", item)

+     elif item.startswith("FEDORA-"):

+         # this is a Bodhi update ID

+         cmd = ("bodhi", "updates", "download", "--arch", arch, "--updateid", item)

+     else:

+         # assume it's an NVR

+         cmd = ("koji", "download-build", f"--arch={arch}", "--arch=noarch", item)

+     # do the download and check for failure

+     (retcode, _, stderr) = await run_command(*cmd, cwd=targetdir)

+     if retcode:

+         # "No .*available for {nvr}" indicates there are no

+         # packages for this arch in the build

+         if not f"available for {item}" in stderr:

+             return item

+     return False

+ 

+ 

+ async def create_workarounds_repo(workarounds, arch, config):

+     """Set up the workarounds repository."""

+     shutil.rmtree(WORKAROUNDS_DIR, ignore_errors=True)

+     os.makedirs(WORKAROUNDS_DIR)

+     rets = []

+     if workarounds:

+         for i in range(0, len(workarounds), 20):

+             tasks = [

+                 asyncio.create_task(download_item(item, arch, WORKAROUNDS_DIR))

+                 for item in workarounds[i : i + 20]

+             ]

+             rets.extend(await asyncio.gather(*tasks))

+     subprocess.run(["createrepo", "."], cwd=WORKAROUNDS_DIR, check=True)

+     if config:

+         with open("/etc/yum.repos.d/workarounds.repo", "w", encoding="utf-8") as repofh:

+             repofh.write(

+                 "[workarounds]\nname=Workarounds repo\n"

+                 "baseurl=file:///mnt/workarounds_repo\n"

+                 "enabled=1\nmetadata_expire=1\ngpgcheck=0"

+             )

+     return [ret for ret in rets if ret]

+ 

+ 

+ async def create_updates_repo(items, arch, config):

+     """Set up the updates/task repository."""

+     # we do not recreate the directory as the test code has to do that

+     # since it has to mount it, before we run

+     rets = []

+     for i in range(0, len(items), 20):

+         tasks = [

+             asyncio.create_task(download_item(item, arch, UPDATES_DIR))

+             for item in items[i : i + 20]

+         ]

+         rets.extend(await asyncio.gather(*tasks))

+     subprocess.run(["createrepo", "."], cwd=UPDATES_DIR, check=True)

+     if not glob.glob(f"{UPDATES_DIR}/*.rpm"):

+         pathlib.Path(f"{UPDATES_FILE_PATH}/updatepkgnames.txt").touch()

+         pathlib.Path(f"{UPDATES_FILE_PATH}/updatepkgs.txt").touch()

+     else:

+         cmd = "rpm -qp *.rpm --qf '%{SOURCERPM} %{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE}\n' | "

+         cmd += f"sort -u > {UPDATES_FILE_PATH}/updatepkgs.txt"

+         subprocess.run(cmd, shell=True, check=True, cwd=UPDATES_DIR)

+         # also log just the binary package names: this is so we can check

+         # later whether any package from the update *should* have been

+         # installed, but was not

+         subprocess.run(

+             "rpm -qp *.rpm --qf '%{NAME} ' > "

+             + f"{UPDATES_FILE_PATH}/updatepkgnames.txt",

+             shell=True,

+             check=True,

+             cwd=UPDATES_DIR,

+         )

+     if config:

+         with open("/etc/yum.repos.d/advisory.repo", "w", encoding="utf-8") as repofh:

+             repofh.write(

+                 "[advisory]\nname=Advisory repo\nbaseurl=file:///mnt/update_repo\n"

+                 "enabled=1\nmetadata_expire=3600\ngpgcheck=0"

+             )

+     return [ret for ret in rets if ret]

+ 

+ 

+ def commalist(string):

+     """Separate a string on commas."""

+     return string.split(",")

+ 

+ 

+ def parse_args():

+     """Parse CLI args with argparse."""

+     parser = argparse.ArgumentParser(

+         description="Packager downloader script for openQA tests"

+     )

+     parser.add_argument("arch", help="Architecture")

+     parser.add_argument(

+         "--workarounds",

+         "-w",

+         type=commalist,

+         help="Comma-separated list of workaround packages",

+     )

+     parser.add_argument(

+         "--updates",

+         "-u",

+         type=commalist,

+         help="Comma-separated list of update/task packages",

+     )

+     parser.add_argument(

+         "--configs", "-c", action="store_true", help="Write repo config files"

+     )

+     args = parser.parse_args()

+     if not (args.workarounds or args.updates):

+         parser.error("At least one of workarounds or updates package lists is required")

+     return args

+ 

+ 

+ async def main():

+     """Do the thing!"""

+     args = parse_args()

+ 

+     tasks = []

+     if args.workarounds:

+         tasks.append(

+             asyncio.create_task(

+                 create_workarounds_repo(args.workarounds, args.arch, args.configs)

+             )

+         )

+     if args.updates:

+         tasks.append(

+             asyncio.create_task(

+                 create_updates_repo(args.updates, args.arch, args.configs)

+             )

+         )

+     failed = []

+     rets = await asyncio.gather(*tasks, return_exceptions=True)

+     for ret in rets:

+         if isinstance(ret, Exception):

+             raise ret

+         failed.extend(ret)

+     if failed:

+         sys.exit(f"Download of item(s) {', '.join(failed)} failed!")

+ 

+ 

+ asyncio.run(main())

@@ -79,7 +79,7 @@ 

      # just for convenience - sometimes it's useful to see this log

      # for a success case

      upload_logs "/tmp/packaging.log", failok => 1;

-     send_key "ctrl-alt-f6";

+     select_console "tty6-console";

  

      # Anaconda hub

      assert_screen "anaconda_main_hub", 30;

file modified
+1 -1
@@ -5,7 +5,7 @@ 

  

  sub run {

      my $self = shift;

-     send_key "ctrl-alt-f3";

+     select_console "tty3-console";

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

      # Since there is no console support for arabic, so we cannot let the user log in

      # with a password that requires Arabic support.

@@ -1,7 +1,6 @@ 

  use base "installedtest";

  use strict;

  use testapi;

- use utils;

  

  sub run {

      my $self = shift;
@@ -16,9 +15,6 @@ 

      # tests that need to edit boot params will see it. Don't use

      # assert_script_run as this will fail when it's not set

      script_run("grub2-editenv - unset menu_auto_hide", 0);

-     # similarly, drop the updateiso/workaroundsiso edits to /etc/fstab

-     # in case the drive is enumerated differently on a follow-up test

-     umount_update_image if (get_var("ISO_2") || get_var("ISO_3"));

      script_run("poweroff", 0);

      assert_shutdown 180;

  }

@@ -90,7 +90,7 @@ 

      if (get_var("IMAGE_DEPLOY")) {

          # if this was an image deployment, we also need to create

          # root user now, for subsequent tests to work

-         send_key "ctrl-alt-f3";

+         select_console "tty3-console";

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

          type_string "sudo su\n";

          type_string "$password\n";

file modified
+2 -4
@@ -11,8 +11,6 @@ 

      my $repo = $version eq $rawrel ? "fedora-rawhide.repo" : "fedora.repo";

      my $advortask = get_var("ADVISORY_OR_TASK");

      my $arch = get_var("ARCH");

-     # we need the update repo mounted to use it in image creation

-     mount_update_image;

      my $packages = "lorax";

      $packages .= " hfsplus-tools" if ($arch eq "ppc64le");

      assert_script_run "dnf -y install $packages", 120;
@@ -27,9 +25,9 @@ 

      unless ($version > $currrel) {

          $cmd .= " --isfinal --repo=/etc/yum.repos.d/fedora-updates.repo";

      }

-     $cmd .= " --repo=/etc/yum.repos.d/advisory.repo" if (get_var("ISO_2"));

-     $cmd .= " --repo=/etc/yum.repos.d/workarounds.repo" if (get_var("ISO_3"));

+     $cmd .= " --repo=/etc/yum.repos.d/workarounds.repo" if (get_workarounds);

      $cmd .= " --repo=/etc/yum.repos.d/koji-rawhide.repo" if ($version eq $rawrel);

+     $cmd .= " --repo=/etc/yum.repos.d/advisory.repo" unless (get_var("TAG"));

      $cmd .= " --repo=/etc/yum.repos.d/openqa-testtag.repo" if (get_var("TAG"));

      $cmd .= " ./results";

      assert_script_run $cmd, 2400;

file modified
+12 -14
@@ -27,13 +27,12 @@ 

      my $arch = get_var("ARCH");

      my $subv = get_var("SUBVARIANT");

      my $lcsubv = lc($subv);

-     # we need the update repo mounted to use it in image creation

-     mount_update_image;

+     my $tag = get_var("TAG");

+     my $workarounds = get_workarounds;

      if (get_var("NUMDISKS") > 2) {

-         # put /var/lib/mock on the third disk. FIXME: this used to

-         # be because we used the second disk for the updates repo,

-         # but now we use an updates image, we can probably change

-         # this

+         # put /var/lib/mock on the third disk, so we don't run out of

+         # space on the main disk. The second disk will have already

+         # been claimed for the update repo.

          assert_script_run "echo 'type=83' | sfdisk /dev/vdc";

          assert_script_run "mkfs.ext4 /dev/vdc1";

          assert_script_run "echo '/dev/vdc1 /var/lib/mock ext4 defaults 1 2' >> /etc/fstab";
@@ -46,16 +45,15 @@ 

      assert_script_run "echo \"include('/etc/mock/fedora-${mockver}-${arch}.cfg')\" > /etc/mock/openqa.cfg";

      # make the side and workarounds repos and the serial device available inside the mock root

      assert_script_run 'echo "config_opts[\'plugin_conf\'][\'bind_mount_enable\'] = True" >> /etc/mock/openqa.cfg';

-     assert_script_run 'echo "config_opts[\'plugin_conf\'][\'bind_mount_opts\'][\'dirs\'].append((\'/mnt/updateiso/update_repo\', \'/mnt/updateiso/update_repo\'))" >> /etc/mock/openqa.cfg' if (get_var("ISO_2"));

-     assert_script_run 'echo "config_opts[\'plugin_conf\'][\'bind_mount_opts\'][\'dirs\'].append((\'/mnt/workaroundsiso/workarounds_repo\', \'/mnt/workaroundsiso/workarounds_repo\'))" >> /etc/mock/openqa.cfg' if (get_var("ISO_3"));

+     assert_script_run 'echo "config_opts[\'plugin_conf\'][\'bind_mount_opts\'][\'dirs\'].append((\'/mnt/update_repo\', \'/mnt/update_repo\'))" >> /etc/mock/openqa.cfg' unless ($tag);

+     assert_script_run 'echo "config_opts[\'plugin_conf\'][\'bind_mount_opts\'][\'dirs\'].append((\'/mnt/workarounds_repo\', \'/mnt/workarounds_repo\'))" >> /etc/mock/openqa.cfg' if ($workarounds);

      assert_script_run 'echo "config_opts[\'plugin_conf\'][\'bind_mount_opts\'][\'dirs\'].append((\'/dev/' . $serialdev . '\', \'/dev/' . $serialdev . '\'))" >> /etc/mock/openqa.cfg';

-     my $tag = get_var("TAG");

      my $repos = 'config_opts[\'dnf.conf\'] += \"\"\"\n';

      # add the update repo or tag repo to the config

-     $repos .= '[advisory]\nname=Advisory repo\nbaseurl=file:///mnt/updateiso/update_repo\nenabled=1\nmetadata_expire=3600\ngpgcheck=0\n' if (get_var("ISO_2"));

+     $repos .= '[advisory]\nname=Advisory repo\nbaseurl=file:///mnt/update_repo\nenabled=1\nmetadata_expire=3600\ngpgcheck=0\n' unless ($tag);

      $repos .= '[openqa-testtag]\nname=Tag test repo\nbaseurl=https://kojipkgs.fedoraproject.org/repos/' . "${tag}/latest/${arch}" . '\nenabled=1\nmetadata_expire=3600\ngpgcheck=0\n' if ($tag);

-     # and the workaround repo if present

-     $repos .= '\n[workarounds]\nname=Workarounds repo\nbaseurl=file:///mnt/workaroundsiso/workarounds_repo\nenabled=1\nmetadata_expire=3600\ngpgcheck=0\n' if (get_var("ISO_3"));

+     # and the workaround repo

+     $repos .= '\n[workarounds]\nname=Workarounds repo\nbaseurl=file:///mnt/workarounds_repo\nenabled=1\nmetadata_expire=3600\ngpgcheck=0\n' if ($workarounds);

      # also the buildroot repo, for Rawhide

      if ($version eq $rawrel) {

          $repos .= '\n[koji-rawhide]\nname=Buildroot repo\nbaseurl=https://kojipkgs.fedoraproject.org/repos/f' . $version . '-build/latest/\$basearch/\nenabled=1\nmetadata_expire=3600\ngpgcheck=0\nskip_if_unavailable=1\n';
@@ -71,10 +69,10 @@ 

      assert_script_run 'cd fedora-kickstarts';

      assert_script_run "git checkout ${branch}";

      # now add the side repo or tag repo to the appropriate repo ks

-     assert_script_run 'echo "repo --name=advisory --baseurl=file:///mnt/updateiso/update_repo" >> ' . $repoks if (get_var("ISO_2"));

+     assert_script_run 'echo "repo --name=advisory --baseurl=file:///mnt/update_repo" >> ' . $repoks unless ($tag);

      assert_script_run 'echo "repo --name=openqa-testtag --baseurl=https://kojipkgs.fedoraproject.org/repos/' . "${tag}/latest/${arch}" . '" >> ' . $repoks if ($tag);

      # and the workarounds repo

-     assert_script_run 'echo "repo --name=workarounds --baseurl=file:///mnt/workaroundsiso/workarounds_repo" >> ' . $repoks if (get_var("ISO_3"));

+     assert_script_run 'echo "repo --name=workarounds --baseurl=file:///mnt/workarounds_repo" >> ' . $repoks if ($workarounds);

      # and the buildroot repo, for Rawhide

      if ($version eq $rawrel) {

          assert_script_run 'echo "repo --name=koji-rawhide --baseurl=https://kojipkgs.fedoraproject.org/repos/f' . $version . '-build/latest/\$basearch/" >> ' . $repoks;

file modified
+11 -11
@@ -23,8 +23,8 @@ 

      my $arch = get_var("ARCH");

      my $subv = get_var("SUBVARIANT");

      my $lcsubv = lc($subv);

-     # we need the update repo mounted to use it in image creation

-     mount_update_image;

+     my $tag = get_var("TAG");

+     my $workarounds = get_workarounds;

      # mount our nice big empty scratch disk as /var/tmp

      assert_script_run "rm -rf /var/tmp/*";

      assert_script_run "echo 'type=83' | sfdisk /dev/vdc";
@@ -41,16 +41,16 @@ 

      assert_script_run 'pushd workstation-ostree-config';

      assert_script_run "git checkout ${branch}";

      # now copy the advisory, workaround repo and koji-rawhide config files

-     assert_script_run 'cp /etc/yum.repos.d/advisory.repo .' if (get_var("ISO_2"));

-     assert_script_run 'cp /etc/yum.repos.d/workarounds.repo .' if (get_var("ISO_3"));

+     assert_script_run 'cp /etc/yum.repos.d/workarounds.repo .' if ($workarounds);

      assert_script_run 'cp /etc/yum.repos.d/koji-rawhide.repo .' if ($version eq $rawrel);

-     assert_script_run 'cp /etc/yum.repos.d/openqa-testtag.repo .' if (get_var("TAG"));

+     assert_script_run 'cp /etc/yum.repos.d/advisory.repo .' unless ($tag);

+     assert_script_run 'cp /etc/yum.repos.d/openqa-testtag.repo .' if ($tag);

      # and add them to the config file

      my $repl = 'repos:';

-     $repl .= '\n  - advisory' if (get_var("ISO_2"));

-     $repl .= '\n  - workarounds' if (get_var("ISO_3"));

+     $repl .= '\n  - workarounds' if ($workarounds);

      $repl .= '\n  - koji-rawhide' if ($version eq $rawrel);

-     $repl .= '\n  - openqa-testtag' if (get_var("TAG"));

+     $repl .= '\n  - advisory' unless ($tag);

+     $repl .= '\n  - openqa-testtag' if ($tag);

      assert_script_run 'sed -i -e "s,repos:,' . $repl . ',g" fedora-' . $lcsubv . '.yaml';

      # change the ref name to a custom one (so we can test rebasing to

      # the 'normal' ref later)
@@ -99,10 +99,10 @@ 

      unless ($version > $currrel) {

          $cmd .= " --isfinal --repo=/etc/yum.repos.d/fedora-updates.repo";

      }

-     $cmd .= " --repo=/etc/yum.repos.d/advisory.repo" if (get_var("ISO_2"));

-     $cmd .= " --repo=/etc/yum.repos.d/workarounds.repo" if (get_var("ISO_3"));

+     $cmd .= " --repo=/etc/yum.repos.d/workarounds.repo" if ($workarounds);

      $cmd .= " --repo=/etc/yum.repos.d/koji-rawhide.repo" if ($version eq $rawrel);

-     $cmd .= " --repo=/etc/yum.repos.d/openqa-testtag.repo" if (get_var("TAG"));

+     $cmd .= " --repo=/etc/yum.repos.d/advisory.repo" unless ($tag);

+     $cmd .= " --repo=/etc/yum.repos.d/openqa-testtag.repo" if ($tag);

      $cmd .= " ./results";

      assert_script_run $cmd, 7000;

      # good to have the log around for checks

file modified
+1 -1
@@ -22,7 +22,7 @@ 

          # line looks like:

          # 07:40:26,614 DBG ui.lib.software: Selecting the 'custom-environment' environment.

          assert_script_run "grep 'Selecting the.*environment' /tmp/anaconda.log /tmp/packaging.log | tail -1 | grep $env";

-         send_key "ctrl-alt-f6";

+         select_console "tty6-console";

          assert_screen "anaconda_main_hub", 30;

          return;

      }

file modified
+2 -2
@@ -134,8 +134,8 @@ 

      # get the kickstart

      assert_script_run "curl -o /export/root-user-crypted-net.ks https://fedorapeople.org/groups/qa/kickstarts/root-user-crypted-net.ks";

      # for update tests, set up the update repository and export it

-     if (get_var("ADVISORY_OR_TASK")) {

-         assert_script_run "echo '/mnt/updateiso/update_repo 172.16.2.0/24(ro)' >> /etc/exports";

+     if (get_var("ADVISORY_OR_TASK") && !get_var("TAG")) {

+         assert_script_run "echo '/mnt/update_repo 172.16.2.0/24(ro)' >> /etc/exports";

      }

      # for compose tests, we do all this stuff

      else {

@@ -31,7 +31,7 @@ 

      # desktop_vt subroutine, but since we do not have networking

      # it does not work reliably. Ergo, we will use the old known

      # ctrl-alt-f2

-     send_key("ctrl-alt-f2");

+     select_console "tty2-console";

      sleep(3);

  

      # Toggle network

file modified
+3 -3
@@ -22,7 +22,7 @@ 

      # we need to use script_run as regular user

      assert_script_run "chmod ugo+w /dev/" . $serialdev;

      # let's go to another tty and login as regular user

-     send_key "alt-f2";

+     select_console "tty2-console";

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

      assert_script_run "curl -O https://fedorapeople.org/groups/qa/tunirtests.tar.gz";

      assert_script_run "tar xvf tunirtests.tar.gz";
@@ -51,7 +51,7 @@ 

      # we need to use script_run as regular user again

      assert_script_run "sudo chmod ugo+w /dev/" . $serialdev;

      # let's go to another tty and login as regular user again

-     send_key "alt-f2";

+     select_console "tty2-console";

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

      _soft_fail_run "tunirtests.testreboot.TestReboot";

      assert_script_run "sudo python3 -m unittest tunirtests.cloudservice.TestServiceManipulation -v";
@@ -63,7 +63,7 @@ 

      # we need to use script_run as regular user again

      assert_script_run "sudo chmod ugo+w /dev/" . $serialdev;

      # let's go to another tty and login as regular user again

-     send_key "alt-f2";

+     select_console "tty2-console";

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

      assert_script_run "sudo python3 -m unittest tunirtests.cloudservice.TestServiceAfter -v";

      if (get_var("CANNED")) {

file modified
+2 -2
@@ -43,7 +43,7 @@ 

      # the GDM tty needs to be active when the scan happens, so we will

      # schedule the scan to happen in 20 seconds then go deal with gdm

      type_string "sleep 20; echo SCAN $user-finger-1 | socat STDIN UNIX-CONNECT:/run/fprintd-virt\n";

-     send_key "ctrl-alt-f1";

+     select_console "tty1-console";

      mouse_hide;

      send_key_until_needlematch("graphical_login_input", "ret", 3, 5);

      # now we check that we see the "or scan fingerprint" message, then
@@ -59,7 +59,7 @@ 

      # we're doing the same as before, but scanning the 'wrong thing'

      # (note finger-2 not finger-1)

      type_string "sleep 20; echo SCAN $user-finger-2 | socat STDIN UNIX-CONNECT:/run/fprintd-virt\n";

-     send_key "ctrl-alt-f1";

+     select_console "tty1-console";

      mouse_hide;

      send_key_until_needlematch("graphical_login_input", "ret", 3, 5);

      assert_screen "graphical_login_fprint";

file modified
+2 -2
@@ -15,7 +15,7 @@ 

      # switch to tty1 (we're usually there already, but just in case

      # we're carrying on from a failed freeipa_webui that didn't fail

      # at tty1)

-     send_key "ctrl-alt-f1";

+     select_console "tty1-console";

      wait_still_screen 1;

      if (get_var("KICKSTART")) {

          # we don't have sssd debugging enabled yet
@@ -52,7 +52,7 @@ 

      # Set a longer timeout for login(1) to workaround RHBZ #1661273

      assert_script_run 'echo "LOGIN_TIMEOUT 180" >> /etc/login.defs';

      # switch to tty2 for login tests

-     send_key "ctrl-alt-f2";

+     select_console "tty2-console";

      # try and login as test1, should work

      console_login(user => "test1\@$domain", password => 'batterystaple');

      type_string "exit\n";

file modified
+2 -2
@@ -49,7 +49,7 @@ 

      assert_script_run 'printf "correcthorse\nbatterystaple\nbatterystaple" | kinit test3@TEST.OPENQA.FEDORAPROJECT.ORG';

      assert_script_run 'printf "correcthorse\nbatterystaple\nbatterystaple" | kinit test4@TEST.OPENQA.FEDORAPROJECT.ORG';

      # switch to tty4 (boy, the tty jugglin')

-     send_key "ctrl-alt-f4";

+     select_console "tty4-console";

      # try and login as test3, should work

      console_login(user => 'test3@TEST.OPENQA.FEDORAPROJECT.ORG', password => 'batterystaple');

      type_string "exit\n";
@@ -63,7 +63,7 @@ 

      type_string "batterystaple\n";

      assert_screen "login_permission_denied";

      # back to tty1

-     send_key "ctrl-alt-f1";

+     select_console "tty1-console";

  }

  

  sub test_flags {

file modified
+2 -2
@@ -77,8 +77,8 @@ 

          assert_script_run 'ipa-server-install -U --uninstall', 300;

          # try and un-garble the screen that the above sometimes garbles

          # ...we may be on tty1 or tty3 now, so flip between them

-         send_key "ctrl-alt-f1";

-         send_key "ctrl-alt-f3";

+         select_console "tty1-console";

+         select_console "tty3-console";

      }

      else {

          assert_script_run "echo '${admin_pw}' | realm join --user=${admin_user} ${server}", 300;

@@ -36,8 +36,8 @@ 

      assert_script_run 'ipa-server-install -U --uninstall', 300;

      # try and un-garble the screen that the above sometimes garbles

      # ...we may be on tty1 or tty3 now, so flip between them

-     send_key "ctrl-alt-f1";

-     send_key "ctrl-alt-f3";

+     select_console "tty1-console";

+     select_console "tty3-console";

      # FIXME check server is decommissioned...how?

  }

  

@@ -7,9 +7,6 @@ 

  

  sub run {

      my $self = shift;

-     # on update flow, we need to ensure the ISO is mounted. this would

-     # be harmless but waste time on compose flow

-     repo_setup if (get_var("ADVISORY_OR_TASK"));

  

      # Start Cockpit

      start_cockpit(login => 1);

@@ -7,9 +7,6 @@ 

  

  sub run {

      my $self = shift;

-     # on update flow, we need to ensure the ISO is mounted. this would

-     # be harmless but waste time on compose flow

-     repo_setup if (get_var("ADVISORY_OR_TASK"));

  

      my $cockdate = "0";

      # Remove a package, disable repositories and enable test repositories, install the package

file modified
+3 -1
@@ -13,7 +13,9 @@ 

      if (index($testname, "upgrade_2") != -1) {

          $version = get_var("UP2REL");

      }

-     setup_workaround_repo $version;

+     # setup the workarounds repository for the pre-upgrade release,

+     # in case we need workarounds for that environment

+     setup_repos(waonly => 1, version => $version);

      # disable updates-testing, this is needed for the case of upgrade

      # from branched to rawhide to ensure we don't get packages from

      # updates-testing for anything we do between here and upgrade_run

Last year, we landed https://pagure.io/fedora-qa/fedora_openqa/c/d4ad4d9426b7ce3a864461078013b24974bc5320?branch=main to have the scheduler download the update/task and workaround packages for update tests, and inject them into the test as ISO images. The intent was to make update tests faster, particularly tests of large multi-package updates.

It did achieve that, but had several drawbacks, including two big ones: restarting tests from the web UI would fail once they were a few hours or days old (because the ISOs got garbage collected), and you could not schedule tests from outside the openQA cluster (it had to be done from a system with the openQA asset NFS share mounted). These are bad enough that I don't think the idea was a good one, in retrospect.

This PR first reverts to more or less the old way of doing things (but adjusted to maintain support for the later-added features of testing multiple tasks at once, and testing side tags) - the tests download the packages in-line, one at a time. Then it replaces that with an approach where the tests use a Python script that downloads the packages in concurrent batches of up to 20 and creates the repo config files, and then it switches to running the entire _repo_setup_updates process at a serial console instead of a normal console.

This aims to speed the process up significantly. Testing on a large multi-package update - 183 packages - the advisory_update step with the older approach takes 25m 42s. With this newer approach it takes 4m 45s. (The time for the 'scheduler download' approach was 4m 15s, so this gets pretty close to that). On a single-package update I got 6m 25s for the old way and 4m 49s for this way (though the times can vary some as most of the time is spent on dnf operations and those can depend on how loaded down the host is).

rebased onto 1da75ed1947a0b443c5e9d8a89d43be1da5fd587

4 months ago

rebased onto c000bd6

4 months ago

Note that this is deployed on stg for testing ATM.

3 new commits added

  • Run update repo setup steps from a serial console
  • update testing: use a concurrent script to download packages
  • Revert to having tests, not the scheduler, download packages (#108)
4 months ago

rebased onto 8251756

4 months ago

on the whole this seems to be working OK on stg, so I'm going to go ahead and merge it for prod. we can revert if there are issues.

Pull-Request has been merged by adamwill

4 months ago