Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@

This is a Nagios/Icinga plugin to check if the currently installed operating system version is outdated. It checks whether the installed version is about to reach end-of-life or whether a newer release is available.

Currently only Debian and Ubuntu are supported.
Currently only Debian and Ubuntu are thoroughly supported. Experimental support
for Red Hat Linux derivatives has been added.

Information about releases and end-of-life dates is retrieved from https://salsa.debian.org/debian/distro-info-data/ or (if `--localDID` is specified) from the /usr/share/distro-info directory, which is provided by the distro-info-data package.

## Requirements

* Python 3
* internet access (to download the latest release data); or a local up-to-date installation of distro-info-data package (specify `--localDID` parameter to use this)


## Usage ##
```
usage: check_os_release [-h] [-v] [--eolWarningDays DAYS]
Expand Down Expand Up @@ -50,3 +45,42 @@ optional arguments:
--localDID use local distro-info-data, from /usr/share/distro-
info
```

## Requirements

* Python 3
* internet access (to download the latest release data); or a local up-to-date installation of distro-info-data package (specify `--localDID` parameter to use this)

### Debian/Ubuntu notes

When a distribution version goes EOL the "distro-info-data" package stops being
updated, so while it may well have the EOL date and warn about this version
being EOL the feature to tell you the latest version will not work.

### RedHat/CentOS/Fedora notes

The packages required to get this to work with older releases that do not have
python3 etc by default seem to be python3 and redhat-lsb (or maybe their
dependencies). Also, if you use it, watch out for SELinux labelling, compare
with other plugins if odd access issues ensue.

They stopped using codenames for their releases some time ago, which meant some
extra code to cope with this while Debian derived distributions continue to do
so.

RH does not seem to provide any dynamic feed for their EOL version data, so only
local csv files will work ("--localDID"). This carries a maintenance overhead
that the authors do not want long term, so we are hoping for volunteers to
update the relevant CSV files when new releases come out. The format is easy.
By the way the code will not explicitly stop you using non-local CSV files, in
case you wanted to centralise the data, or RH ever do start running such data
feeds in future (or if we just missed them!).

Because RH also does not seem to provide a package like 'distro-info-data' the
files need to be added into /usr/share/distro-info/ manually, or with a config
management system like ansible. Some playbooks et al for this may be added
later.

The one-off examples to get this working at a point in time (only very lightly
tested and checked) are in the rh-distro-info directory. Their content has been
sourced from pages on the very excellent Wikipedia.
83 changes: 83 additions & 0 deletions check_os_release
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,84 @@ distroDataBaseUrl = "https://debian.pages.debian.net/distro-info-data"
distroDataBaseDirectory = "/usr/share/distro-info"


def checkRedHatDerived(nagiosOutput, downloader, distroDataUrl, eolWarningDays, eolCriticalDays, eolIgnore,
releaseWarningDays, releaseCriticalDays, releaseIgnore, checkForLTS=False, checkForServer=False):
"""
Check currently installed Debian (or Ubuntu) release against online data from from distro-info-data package.
"""
currentCodename = subprocess.check_output(["lsb_release", "--codename", "--short"]).decode('utf-8').rstrip("\n")
currentRelease = subprocess.check_output(["lsb_release", "--release", "--short"]).decode('utf-8').rstrip("\n")
currentMajorRelease = currentRelease.split('.')[0]
currentMajorOneMinorRelease = currentRelease.split('.')[0] + "." + currentRelease.split('.')[1]

currentReleaseData = None

csvFp = StringIO(downloader.get(distroDataUrl).decode('utf-8'))
csvReader = csv.DictReader(csvFp)

for row in csvReader:
#print("CHK RH DERIVED series='%s', version='%s', currentCodename='%s', currentMajorRelease='%s'" % (row["series"], row["version"], currentCodename, currentMajorRelease))
if row["series"] != "" and row["series"] == currentCodename:
currentReleaseData = row
break
# CentOS
elif row["series"] == "" and row["version"] == currentMajorRelease:
currentReleaseData = row
break
# Fedora/RHEL
elif row["series"] == "" and row["version"] == currentMajorOneMinorRelease:
currentReleaseData = row
break
else:
raise RuntimeError("current release %s ('%s') not found in release list" % (currentMajorRelease, currentCodename))

def parseCsvDate(string):
return datetime.strptime(string, "%Y-%m-%d").date()
nowDate = date.today()

# check if there is a newer release available (by continuing to read from CSV buffer):
newestWarningUpgrade = None
newestCriticalUpgrade = None
newestAnyUpgrade = None
for row in csvReader:
if checkForLTS and not(row["version"].endswith(" LTS")):
continue
if row["release"] is not None:
releaseDate = parseCsvDate(row["release"])
if not releaseIgnore and nowDate >= releaseDate + timedelta(days=releaseWarningDays):
newestWarningUpgrade = row
if not releaseIgnore and nowDate >= releaseDate + timedelta(days=releaseCriticalDays):
newestCriticalUpgrade = row
if nowDate >= releaseDate:
newestAnyUpgrade = row
if newestCriticalUpgrade is not None:
nagiosOutput.addResult(NagiosOutput.LEVEL_CRITICAL, "newer release '%s' (%s) is available" % (newestCriticalUpgrade["series"], newestCriticalUpgrade["version"]))
elif newestWarningUpgrade is not None:
nagiosOutput.addResult(NagiosOutput.LEVEL_WARN, "newer release '%s' (%s) is available" % (newestWarningUpgrade["series"], newestWarningUpgrade["version"]))
elif newestAnyUpgrade is not None:
nagiosOutput.addResult(NagiosOutput.LEVEL_OK, "newer release '%s' (%s) is available" % (newestAnyUpgrade["series"], newestAnyUpgrade["version"]))
else:
nagiosOutput.addResult(NagiosOutput.LEVEL_OK, "release '%s' (%s) is most current" % (currentReleaseData["series"], currentReleaseData["version"]))

# check if current release is EOL
if checkForServer and currentReleaseData.has_key("eol-server") and currentReleaseData["eol-server"] is not None:
eolDate = parseCsvDate(currentReleaseData["eol-server"])
elif currentReleaseData["eol"] is not None:
eolDate = parseCsvDate(currentReleaseData["eol"])
else:
eolDate = None
if eolDate:
if nowDate > eolDate:
msg = "release '%s' has been EOL for %d days" % (currentCodename, (nowDate - eolDate).days)
else:
msg = "release '%s' will be EOL in %d days" % (currentCodename, (eolDate - nowDate).days)
if not eolIgnore and nowDate > eolDate - timedelta(days=eolCriticalDays):
nagiosOutput.addResult(NagiosOutput.LEVEL_CRITICAL, msg)
elif not eolIgnore and nowDate > eolDate - timedelta(days=eolWarningDays):
nagiosOutput.addResult(NagiosOutput.LEVEL_WARN, msg)
else:
nagiosOutput.addResult(NagiosOutput.LEVEL_OK, msg)

def checkDebianUbuntu(nagiosOutput, downloader, distroDataUrl, eolWarningDays, eolCriticalDays, eolIgnore,
releaseWarningDays, releaseCriticalDays, releaseIgnore, checkForLTS=False, checkForServer=False):
"""
Expand Down Expand Up @@ -220,6 +298,11 @@ if __name__ == "__main__":
checkDebianUbuntu(nagiosOutput, downloader, "%s/debian.csv" % distroDataBase, args.eolWarningDays, args.eolCriticalDays, args.eolIgnore, args.releaseWarningDays, args.releaseCriticalDays, args.releaseIgnore)
elif distro == "Ubuntu":
checkDebianUbuntu(nagiosOutput, downloader, "%s/ubuntu.csv" % distroDataBase, args.eolWarningDays, args.eolCriticalDays, args.eolIgnore, args.releaseWarningDays, args.releaseCriticalDays, args.releaseIgnore, args.lts, args.server)
elif distro == "CentOS":
checkRedHatDerived(nagiosOutput, downloader, "%s/centos.csv" % distroDataBase, args.eolWarningDays, args.eolCriticalDays, args.eolIgnore, args.releaseWarningDays, args.releaseCriticalDays, args.releaseIgnore, args.lts, args.server)
elif distro == "Fedora":
checkRedHatDerived(nagiosOutput, downloader, "%s/fedora.csv" % distroDataBase, args.eolWarningDays, args.eolCriticalDays, args.eolIgnore, args.releaseWarningDays, args.releaseCriticalDays, args.releaseIgnore, args.lts, args.server)
# RHEL?
else:
raise NotImplementedError("unknown distribution '%s'" % distro)
nagiosOutput.reportAndExit()
7 changes: 7 additions & 0 deletions rh-distro-info/centos.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version,codename,series,created,release,eol
3,3,,2004-03-19,2006-07-20,2010-10-31
4,4,,2005-03-09,2009-03-31,2012-02-29
5,5,,2007-04-12,2014-01-31,2017-03-31
6,6,,2011-07-10,2017-05-10,2020-11-30
7,7,,2014-07-07,2020-08-06,2024-06-30
8,8,,2019-09-24,2021-12-31,2021-12-31
38 changes: 38 additions & 0 deletions rh-distro-info/fedora.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
version,codename,series,created,release,eol
1,Yarrow,yarrow,2003-11-06,2003-11-06,2004-09-20
2,Tettnang,Tettnang,2004-05-18,2004-05-18,2005-04-11
3,Heidelberg,Heidelberg,2004-11-08,2004-11-08,2006-01-16
4,Stentz,Stentz,2005-06-13,2005-06-13,2006-08-07
5,Bordeaux,Bordeaux,2006-03-20,2006-03-20,2007-07-02
6,Zod,Zod,2006-10-24,2006-10-24,2007-12-07
7,Moonshine,Moonshine,2007-05-31,2007-05-31,2008-06-13
8,Werewolf,Werewolf,2007-11-08,2007-11-08,2009-01-07
9,Sulphur,Sulphur,2008-05-13,2008-05-13,2009-07-10
10,Cambridge,Cambridge,2008-11-25,2008-11-25,2009-12-18
11,Leonidas,Leonidas,2009-06-09,2009-06-09,2010-06-25
12,Constantine,Constantine,2009-11-17,2009-11-17,2010-12-02
13,Goddard,Goddard,2010-05-25,2010-05-25,2011-06-24
14,Laughlin,Laughlin,2010-11-02,2010-11-02,2011-12-08
15,Lovelock,Lovelock,2011-05-24,2011-05-24,2012-06-26
16,Verne,Verne,2011-11-08,2011-11-08,2013-02-12
17,Beefy Miracle,Beefy Miracle,2012-05-29,2012-05-29,2013-07-30
18,Spherical Cow,Spherical Cow,2013-01-15,2013-01-15,2014-01-14
19,Schrödinger's Cat,Schrödinger's Cat,2013-07-02,2013-07-02,2015-01-06
20,Heisenbug,Heisenbug,2013-12-17,2013-12-17,2015-06-23
21,21,21,2014-12-09,2014-12-09,2015-12-01
22,22,22,2015-05-26,2015-05-26,2016-07-19
23,23,23,2015-11-03,2015-11-03,2016-12-20
24,24,24,2016-06-21,2016-06-21,2017-08-08
25,25,25,2016-11-22,2016-11-22,2017-12-12
26,26,26,2017-07-11,2017-07-11,2018-05-29
27,27,27,2017-11-14,2017-11-14,2018-11-30
28,28,28,2018-05-01,2018-05-01,2019-05-28
29,29,29,2018-10-30,2018-10-30,2019-11-26
30,30,30,2019-05-07,2019-05-07,2020-05-26
31,31,31,2019-10-29,2019-10-29,2020-11-24
32,32,32,2020-04-28,2020-04-28,2021-05-25
33,33,33,2020-10-27,2020-10-27,2021-11-30
34,34,34,2021-04-27,2021-04-27,2022-05-17
35,35,35,2021-11-02,2021-11-02,2022-12-07
36,36,36,2022-05-03,2022-05-03,2023-05-24
37,37,37,2022-10-18,2022-10-18,2023-11-22
8 changes: 8 additions & 0 deletions rh-distro-info/rhel.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version,codename,series,created,release,eol,version
2.1,Pensacola,Pensacola,2003-05-01,2003-05-01,0000-00-00,2.1
3,Taroon,Taroon3,2003-10-23,2003-10-23,2014-01-30,3
4,Nahant,Nahant,2005-02-14,2005-02-14,2017-03-31,4
5,Tikanga,Tikanga,2007-03-14,2007-03-14,2020-11-30,5
6,Santiago,Santiago,2010-11-10,2010-11-10,2024-06-30,6
7,Maipo,Maipo,2014-06-10,2014-06-10,2026-06-30,7
8,Ootpa,Ootpa,2019-05-08,2019-05-08,2026-06-30,8