Behind the scenes - How does it work?

Get eol data of a given product

  • A request to https://endoflife.date/api/v1/products/PRODUCTis made
  • The response is saved to /tmp/eol_<PRODUCT>.json

The local product specific JSON file is used as cache file and expires after 1 day. When checking the same product again the json data is taken from the cache file. This reduces the traffic to the endoflife.date server.

See details of the response in the documentation of the api: 🌐 https://endoflife.date/docs/api/v1/#/Products/product

Find latest version

The block with information of the latest version we get from cat "$API_OUT" | jq ".result .releases.[0]". Inside this block…

  • The current major version number is in the key .name.
  • The latest minor version is in .latest .name
$ cat "$API_OUT" | jq ".result .releases.[0]"
{
  "name": "8.4",
  "codename": null,
  "label": "8.4",
  "releaseDate": "2024-11-21",
  "isLts": false,
  "ltsFrom": null,
  "isEoas": false,
  "eoasFrom": "2026-12-31",
  "isEol": false,
  "eolFrom": "2028-12-31",
  "isMaintained": true,
  "latest": {
    "name": "8.4.8",
    "date": "2025-06-05",
    "link": "https://www.php.net/ChangeLog-8.php#8.4.8"
  },
  "custom": null
}

Find local version - Linux OS

When scanning EOL of a Linux OS using --os it uses an internal algorithm by reading /etc/os-release.

cat /etc/os-release | grep "^ID=" | cut -f 2 -d '"'

Hacks:

  • Centos steam has the ID="centos" - the same key like Centos. If the string “CentOS Stream” is found /etc/os-release then “centos-steam” will be set
  • Roky Linux has the ID="rocky". In the endoflife.data API the products key was changed to “rocky-linux” in Sep 5th 2025. An os mapping was added on top of the script in the comment section.

Find local version - automatically

In result -> versionCommand is a command to get the version of a locally installed product.

$ cat "$API_OUT" | jq ".result .versionCommand"
"php --version"

The given command will be executed. Its output won’t be cached.

If the command containes line breaks with \n (see response for “python”). Those lines are commands or coments starting with #. Then all lines will be executed until an output was found.

Hacks:

  • Some commands in the “versionCommand” field are unhandy. eg for PostgreSql you must establish a database connection or Docker needs to connect as well. In the comment section on top of the script is a mapping for product keys with another version cammand to execute
  • If the version is not properly detected, eg. a client tool is not in $PATH and you want to scan some locations - then you can creare custom scripts. See next chapter

Find local version - by custom file

Some versions are difficult to fetch eg with a non privikledged user eg. for monitoring. In the subdir ./eol_check-env/ are files per product to handle an override and detect a version in another way.

When using --verbose you see if it was used:

$ ./eol_check.sh -v postgres
DEBUG: Params: PRODUCT = postgres, PRODUCT_VERSION = 
DEBUG: Sourcing custom file for 'postgres' -> ./eol_check-env/postgres
...

Compare versions

The current version is compared with latest major and latest min or version.

Check support

We compare:

  • Is the current version still supported? see .isMaintained in the current release
  • Detect date for end of support
    • if .eoesFrom - end of extended security exists then this date will be used
    • otherwise of .eolFrom - end of life - will be used
    • If one of the date was found ist will be compared with the curent day to show how many days are left - or how long it is expired

Lessons learnt

At the initial point it seemed to be an easy script to code. I can detect a product version with the value of versionCommand. “Just execute that” and read STDOUT. Then comapre it somehow with data in a JSON. The first check was up and running quite fast.

Then came the reality :-)

  • Then I found “python” - it has multiple commands. Cut by \nand take the first item worked for me.
  • … bot my luck ended on another machine. Now I loop over all lines, exclude comments starting with #. The first successful command wins.
  • I found “java” - its version data is written to STDERR. I added 2>&1 on each version command.
  • Then there were tools where I “didn’t like” the version command. Docker and Postgres don’t read the version of the client but initialize a connection to a service. Because one usage of my EOL check is with an unpriviledged user. It doesn’t need access. Solution was: I created possibilities to override the version command. And yes, I know that this is a dirty hack.

We use the 1st line of the output from the version command. Sometimes it is just the version number. Sometimes there is the product in fron. Or text behind. I didn’t count it but the regex to fetch the version number several times was changed.