#350 Add checks for SUPPORT_END (EOL) in /etc/os-release.
Merged 14 days ago by adamwill. Opened 2 months ago by lruzicka.

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

+ #!/usr/bin/python3

+ 

+ # Copyright Red Hat

+ #

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

+ #

+ # os-autoinst-distri-fedora 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 2 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: Lukas Ruzicka <lruzicka@redhat.com>

+ 

+ 

+ """

+ This script provides a simple test for Eof of Life dates on Fedora.

+ You can use it for two types of testing. The first test checks that

+ the SUPPORT_END value is at least a year ahead (in the time of testing),

+ which it should be. The second test checks if the End of Life date is

+ consisant across the three sources, the os-release file, Bodhi, and Fedora

+ Schedule.

+ 

+ When the test passes, it returns 0, otherwise there is one of the error codes.

+ """

+ 

+ 

+ import argparse

+ import sys

+ from datetime import date, datetime, timedelta

+ import requests

+ 

+ VERBOSE = False

+ RESULT = 100

+ 

+ 

+ def cli():

+     """Return the CLI arguments."""

+ 

+     parser = argparse.ArgumentParser(

+         description="Fedora '/etc/os-release' support date validator."

+     )

+ 

+     parser.add_argument(

+         "--test",

+         "-t",

+         type=str,

+         required=True,

+         help="Test to perform [future, compare]",

+     )

+ 

+     parser.add_argument(

+         "--release",

+         "-r",

+         type=str,

+         required=False,

+         help="Fedora release number (42, 43, ...)",

+     )

+ 

+     parser.add_argument(

+         "--verbose",

+         "-v",

+         action="store_true",

+         help="Prints detailed info on the screen.",

+     )

+ 

+     args = parser.parse_args()

+     return args

+ 

+ 

+ def log(*args, **kwargs):

+     """Print out messages on CLI if VERBOSE."""

+     if VERBOSE:

+         print(*args, **kwargs)

+     else:

+         pass

+ 

+ 

+ def epochdate(epoch: int) -> date:

+     """Return the date object calculated from the epoch integer."""

+     converted = datetime.fromtimestamp(epoch)

+     return converted.date()

+ 

+ 

+ def isodate(iso: str) -> date:

+     """Return the date object calculated from the ISO format."""

+     converted = date.fromisoformat(iso)

+     return converted

+ 

+ 

+ def get_file_support() -> date:

+     """Returns the support date from the os-release file."""

+     with open("/etc/os-release", "r", encoding="utf-8") as release:

+         lines = release.readlines()

+         log("The /etc/os-release successfully read.")

+ 

+     support_day = epochdate(0)

+     for line in lines:

+         if "SUPPORT_END" in line:

+             _, value = line.split("=")

+             value = value.strip()

+     if value:

+         support_day = isodate(value)

+     return support_day

+ 

+ 

+ def support_date_in_future(eol: date) -> bool:

+     """This function checks the support date from the os-release

+     file, compares it with the current system date and tests if

+     the os-release support date lies at least 12 months in the future."""

+ 

+     # Get the necessary values from the operating system.

+     today = datetime.today().date()

+     log("Current date on tested system is:", today)

+     tomorrow = today + timedelta(days=365)

+     log("Minimal SUPPORT_END calculated from system time is:", tomorrow)

+     log("Real /etc/os-release SUPPORT_END is:", eol)

+ 

+     # Test if the support end date is in the future.

+     result = False

+     if eol >= tomorrow:

+         log("Real SUPPORT_END is one year in the future.")

+         result = 0

+     else:

+         log("Real SUPPORT_END is NOT one year in the future.")

+         result = 1

+     return result

+ 

+ 

+ def compare_eol_dates(release: int, eol: date) -> bool:

+     """This function checks the support date on Fedora Schedule, Bodhi

+     and the os-release file and compares them whether they are the same

+     and fails if they are not."""

+     log("The EOL date shown by the os-release file is:", eol.isoformat())

+     # Get the Bodhi EOL date

+     bodhi_response = requests.get(

+         f"https://bodhi.fedoraproject.org/releases/F{release}", timeout=60

+     )

+     bodhi = bodhi_response.json()

+     # Only convert the date if it is present, otherwise record 0.

+     if bodhi["eol"]:

+         bodhi_eol = isodate(bodhi["eol"])

+     else:

+         bodhi_eol = epochdate(0)

+     log("The EOL date shown by Bodhi is:", bodhi_eol.isoformat())

+ 

+     # Get the Schedule EOL date

+     schedule_response = requests.get(

+         f"https://fedorapeople.org/groups/schedule/f-{release}/"

+         f"f-{release}-key.json",

+         timeout=60,

+     )

+     schedule = schedule_response.json()

+     tasks = schedule["tasks"][0]["tasks"][0]["tasks"]

+     schedule_eol = epochdate(0)

+     for task in tasks:

+         if "End of Life" in task["name"]:

+             schedule_eol = epochdate(int(task["end"]))

+             break

+     log("The EOL date shown by Fedora Schedule is:", schedule_eol.isoformat())

+ 

+     # Compare the dates

+     result = None

+     if eol == bodhi_eol and eol == schedule_eol:

+         log("All EOL dates have the same value.")

+         result = 0

+     elif eol == bodhi_eol:

+         log("The os-release matches Bodhi but Fedora Schedule is different.")

+         result = 1

+     elif eol == schedule_eol:

+         log("The os-release matches Fedora Schedule but Bodhi is different.")

+         result = 2

+     elif bodhi_eol == schedule_eol:

+         log("Bodhi matches Fedora Schedule, but os-release is different.")

+         result = 3

+     else:

+         log("All EOL dates have different values.")

+         result = 4

+     return result

+ 

+ 

+ arguments = cli()

+ VERBOSE = arguments.verbose

+ os_release_eol = get_file_support()

+ 

+ codebook = {

+     100: "Something went terribly bad in the testing script.",

+     1: "Fedora Schedule shows a different EOL value than other sources.",

+     2: "Bodhi shows a different EOL value than other sources.",

+     3: "The os-release file shows a different EOL value than other sources.",

+     4: "All sources have a different EOL value.",

+     5: "For this type of test, you need to use the --release option.",

+ }

+ 

+ if arguments.test == "compare":

+     if not arguments.release:

+         # No arguments, exit

+         sys.exit(codebook[5])

+ 

+     RESULT = compare_eol_dates(arguments.release, os_release_eol)

+ else:

+     RESULT = support_date_in_future(os_release_eol)

+ 

+ if RESULT != 0:

+     # Exit with an error message.

+     log("Test failed.", codebook[RESULT])

+     sys.exit(codebook[RESULT])

+ else:

+     # Exit cleanly if result is 0

+     log("Test passed.")

+     sys.exit(0)

file modified
+16
@@ -12,6 +12,13 @@ 

      return $string;

  }

  

+ sub download_python_tests {

+     # Download the Python test script and change mode to rwx,rx,rx.

+     assert_script_run("curl https://pagure.io/fedora-qa/os-autoinst-distri-fedora/raw/os-release-addon/f/check-release.py -o ~/check-release.py --retry 10 --retry-delay 2", timeout => 60);

+     assert_script_run("chmod 755 ~/check-release.py", timeout => 20);

+     sleep(5);

+ }

+ 

  sub run {

      # First, let us define some variables needed to run the program.

      my $self = shift;
@@ -181,6 +188,15 @@ 

          print "VARIANT_ID was not tested because the compose is not Workstation or Server Edition.\n";

      }

  

+ 

+     # Download Python test script to run the tests.

+     download_python_tests();

+     # Test for EOL date in the distant future.

+     assert_script_run("~/check-release.py --test future --verbose");

+ 

+     # Test for EOL dates match each other.

+     assert_script_run("~/check-release.py --test compare --release $version_id --verbose");

+ 

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

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.

rebased onto c255a91

2 months ago

rebased onto 62ec566

2 months ago

So...a couple of things:

  • Why is collect_web_data a separate test module? Why is it not just inline in os_release.pm ?
  • I'd maybe suggest we consider writing this whole thing as a Python script which the test just downloads and runs - like lorax-parser.py , ostree-parse-pungi.py , setup_repos.py , and updvercheck.py . I feel like it's more comfortable to have these kinds of things as separate scripts rather than in-line a lot of coding in the tests. And Python has datetime in its stdlib, which is a rather more comfortable way of handling all this strptime/strftime/calculating deltas stuff, without pulling in another external perl dep for these tests. I think the test code should just get the python script and run it with args expressing the necessary stuff (release number and whether it's a pre-release, I guess), then the python script would take care of downloading all the JSON and doing the comparisons. It could use differing exit codes to indicate different types of failure, or possibly have two modes to run, one for checking EOLs match, one for checking they're far enough in the future.

WDYT?

So...a couple of things:

  • Why is collect_web_data a separate test module? Why is it not just inline in os_release.pm ?
  • I'd maybe suggest we consider writing this whole thing as a Python script which the test just downloads

WDYT?

Yeah, why not. I wanted to make this in Perl only to get some practice, but I'd like Python practice too, so I am all in :D

1 new commit added

  • Add Python checking script.
2 months ago

1 new commit added

  • Fix some pylint problems.
2 months ago

1 new commit added

  • Fix pylint and black the file.
2 months ago

1 new commit added

  • Use Python script to test for EOL.
2 months ago

1 new commit added

  • Fix typos
2 months ago

1 new commit added

  • Fix a type error on the script.
2 months ago

Now, the test suite uses an external Python script to check for the EOL dates and it does its job:

https://openqa.stg.fedoraproject.org/tests/4538282#step/os_release/42

rebased onto 564d019

2 months ago

2 new commits added

  • Do the EOL checks through a Python script.
  • Add checks for SUPPORT_END (EOL) in /etc/os-release.
2 months ago

there are two RESULT = 100 declarations, remove one.

we don't use jq any more. I kinda feel like maybe the python script should download the necessary data files (use the 'requests' library) and this file should just go away?

this is a leftover line, is it not? we don't have a $content.

this rec_log stuff isn't going to work any more. i think we just want to make these simple assert_script_run calls, as the script output should tell us the problem if it fails.

there is no fedora_release any more, is there? and if we get rid of collect_web_data too (see comment there), no change is needed here.

1 new commit added

  • Delete collect_web_data as it is no longer needed.
2 months ago

1 new commit added

  • Fix the Python script to exit differently and use it inthe test script.
2 months ago

rebased onto 1cf138c

2 months ago

1 new commit added

  • Remove unused libraries
2 months ago

rebased onto 1cf138c

2 months ago

cool, looks nicer now. will try and test it out today.

ok, so the test works fine but fails on Rawhide as Bodhi has no EOL date for F42. I'm not sure if that's 'normal' or we want it to match the fairly notional date in os-release and the schedule. Maybe we should clear that up with @mattia and @amoloney .

rebased onto 5a88596

2 months ago

rebased onto 3359810

2 months ago

rebased onto 3359810

2 months ago

ok, so the test works fine but fails on Rawhide as Bodhi has no EOL date for F42. I'm not sure if that's 'normal' or we want it to match the fairly notional date in os-release and the schedule. Maybe we should clear that up with @mattia and @amoloney .

I think releng SOP is the place to adjust? I'm not sure a EOL date exists at Rawhide creation time, since the release date is not certain. But perhaps nothing could be hurt by adding a predicted one and changing it at release time?

ok, so the test works fine but fails on Rawhide as Bodhi has no EOL date for F42. I'm not sure if that's 'normal' or we want it to match the fairly notional date in os-release and the schedule. Maybe we should clear that up with @mattia and @amoloney .

I think releng SOP is the place to adjust? I'm not sure a EOL date exists at Rawhide creation time, since the release date is not certain. But perhaps nothing could be hurt by adding a predicted one and changing it at release time?

Sure. This would be a sufficient option for us. I would also assume that it is ok for the test to fail on Rawhide to start passing once we branch out and the EOL dates are set. WDYT?

rebased onto bd687aa

14 days ago

oh, sorry, forgot about this. let's go ahead and merge it, we can tweak the checks and pass/fail status as we go, if necessary. thanks!

rebased onto 4554992

14 days ago

Pull-Request has been merged by adamwill

14 days ago
Metadata