From df9766b051af1ed63dd65b54d2383ac94237f898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20R=C5=AF=C5=BEi=C4=8Dka?= Date: Tue, 26 Nov 2024 14:39:07 +0100 Subject: [PATCH] Add checks for SUPPORT_END (EOL) in /etc/os-release. Fixes #347. This PR adds two tests to check the EOL written in the /etc/os-release file. The first test checks that the SUPPORT_END value lies at least 12 months in the future. The second test checks the EOL values in Fedora Schedule, Bodhi, and /etc/os-release if they are the same. --- templates.fif.json | 2 +- tests/collect_web_data.pm | 34 +++++++++ tests/os_release.pm | 145 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 tests/collect_web_data.pm diff --git a/templates.fif.json b/templates.fif.json index 82f02218..214891f2 100644 --- a/templates.fif.json +++ b/templates.fif.json @@ -2509,7 +2509,7 @@ }, "settings": { "BOOTFROM": "c", - "ENTRYPOINT": "text_login_gui fedora_release os_release", + "ENTRYPOINT": "text_login_gui collect_web_data fedora_release os_release", "HDD_1": "disk_%FLAVOR%_%MACHINE%.qcow2", "START_AFTER_TEST": "%DEPLOY_UPLOAD_TEST%", "USER_LOGIN": "false" diff --git a/tests/collect_web_data.pm b/tests/collect_web_data.pm new file mode 100644 index 00000000..c8340b17 --- /dev/null +++ b/tests/collect_web_data.pm @@ -0,0 +1,34 @@ +use base "installedtest"; +use strict; +use testapi; +use utils; + +sub run { + my $self = shift; + + # Let's get the $target release version. + my $target = get_release_number(); + # The $current release version is the last stable release + # around that we want to compare. + my $current = get_var('CURRREL'); + + # Go to the home directory, create a new directory there + # and collect the data + assert_script_run('cd'); + assert_script_run('mkdir version_data'); + assert_script_run('cd version_data'); + + # We will fetch the version data from various locations. + # Download data from Bodhi for + assert_script_run("curl -o bodhi-$target.json https://bodhi.fedoraproject.org/releases/F$target"); + # Download data from Fedora Schedule + assert_script_run("curl -o schedule-$target.json https://fedorapeople.org/groups/schedule/f-$target/f-$target-key.json"); + # Install jq to modify the downloaded jsons and make sure, they will be correctly formed. + assert_script_run("dnf install -y jq", timeout => 60); +} + +sub test_flags { + return {fatal => 1, milestone => 1}; +} +1; +# vim: set sw=4 et: diff --git a/tests/os_release.pm b/tests/os_release.pm index e82a75ab..acaa7eba 100644 --- a/tests/os_release.pm +++ b/tests/os_release.pm @@ -1,5 +1,7 @@ use base "installedtest"; use strict; +use JSON; +use Time::Piece; use testapi; use utils; @@ -12,6 +14,138 @@ sub strip_marks { return $string; } +sub json_to_hash { + # Take a string formed as json and return a valid Perl hash + # for further processing. + my $json = shift; + my $hash = decode_json($json); + # If the json is not decoded correctly, fail. + die("Failed to parse JSON: $@") if ($@); + return $hash; +} + +sub date_to_epoch { + # Take the date as YYYY-MM-DD and convert it into epoch. + my $dstring = shift; + my $date = Time::Piece->strptime($dstring, '%Y-%m-%d'); + my $epoch = $date->epoch; + return $epoch; +} + +sub epoch_to_date { + # Take the epoch and return YYYY-MM-DD. + my $epoch = shift; + my $time = localtime($epoch); + my $date = $time->strftime('%Y-%m-%d'); + return $date; +} + +sub get_bodhi_eol { + # Load the Bodhi json file and return the EOL epoch. + my $ver = shift; + # Use the openQA script output to read the json file. We use jq to make + # sure that the content is a valid json file. + my $json = script_output("cat ~/version_data/bodhi-$ver.json | jq -c"); + my $bodhi = json_to_hash($json); + my $eol = $bodhi->{"eol"}; + $eol = date_to_epoch($eol); + return $eol; +} + +sub get_schedule_eol { + # Load the Fedora Schedule json file and return the EOL epoch. + my $ver = shift; + my $json = script_output("cat ~/version_data/schedule-$ver.json | jq -c"); + my $schedule = json_to_hash($json); + my $eol; + # Identify the events and find the EOL field. + my $tasks = $schedule->{'tasks'}[0]{'tasks'}[0]{'tasks'}; + my $eol; + foreach my $task (@$tasks) { + if ($task->{'name'} and $task->{'name'} =~ /End of Life/) { + $eol = $task->{'end'}; + last; + } + } + # The EOL is already formed as epoch, just return it. + return $eol; +} + +sub get_current_date { + # This returns the current date in as the epoch and YYYY-MM-DD. + # which we need to see if the EOL is correctly set in the future. + my $time = localtime; + my $dates = {}; + $dates->{'date'} = $time->strftime('%Y-%m-%d'); + $dates->{'epoch'} = date_to_epoch($dates->{'date'}); + return $dates; +} + +sub check_eol_in_year { + # This reads the EOL date from the /etc/os-release + # file and checks that it is at least a year in + # the future (when tested on non-published ISOs). + # Returns true if successful. + my $tested = shift; + $tested = date_to_epoch($tested); + my $dates = get_current_date(); + my $current = $dates->{epoch}; + # The EOL in the os-release.pm must be at least a year + # in the future, so we calculate the epoch difference + # between $tested and $current. + # An epoch year should be + # 1 * 60 (min) *60 (hour) *24 (day) *365 (year) + my $year = 1 * 60 * 60 * 24 * 365; + my $delta = $tested - $current; + my $bool = 1; + if ($delta < $year) { + $bool = 0; + } + return $bool; +} + +sub check_eols_match { + # This takes the EOL dates from the /etc/os-release + # file and compares the value with those from + # Bodhi and Fedora Schedule and will succeed when they + # match each other. + my $tested = shift; + my $version = get_release_number(); + my $bodhi = get_bodhi_eol($version); + $bodhi = epoch_to_date($bodhi); + my $schedule = get_schedule_eol($version); + $schedule = epoch_to_date($schedule); + # Let's set the return code to 0 to indicate that none of the EOL date + # can be matched with another one. + my $rcode = 0; + my $overall = 1; + # Start comparisons among the EOL dates. + if ($bodhi eq $schedule and $bodhi eq $tested) { + $rcode = 1; + } + elsif ($bodhi eq $schedule) { + $rcode = 2; + } + elsif ($tested eq $bodhi) { + $rcode = 3; + } + elsif ($tested eq $schedule) { + $rcode = 4; + } + # If the EOL dates do not match each other, consider this a test failure. + $overall = 0 if ($rcode != 1); + my $return_codes = { + 0 => "No EOL dates do match:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule", + 2 => "The os-release doesn't match Bodhi or Schedule, but they match each other:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule", + 3 => "The os-release file matches Bodhi but Schedule differs:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule", + 4 => "The os-release file matches Schedule but Bodhi differs:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule", + 1 => "All EOL dates match:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule" + }; + + my $result = [$overall, $return_codes->{$rcode}]; + return $result; +} + sub run { # First, let us define some variables needed to run the program. my $self = shift; @@ -181,6 +315,17 @@ sub run { print "VARIANT_ID was not tested because the compose is not Workstation or Server Edition.\n"; } + + # Test for EOL date in the distant future. + my $os_release_eol = $content{'SUPPORT_END'}; + my $result = check_eol_in_year($os_release_eol); + my $current = get_current_date(); + rec_log("The SUPPORT_END date is $os_release_eol which is at least a year ahead in time (now is $current->{date})", $result == 1, $failref); + + # Test for EOL dates match each other. + $result = check_eols_match($os_release_eol); + rec_log($result->[1], $result->[0] == 1, $failref); + # Check for fails, count them, collect their messages and die if something was found. my $failcount = scalar @fails; script_run "echo \"There were $failcount failures in total.\" >> /tmp/os-release.log";