You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
5.3 KiB
Python
191 lines
5.3 KiB
Python
#!/usr/bin/python3
|
|
from __future__ import division
|
|
import posixpath
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
class Version(object):
|
|
"""Crude version abstraction for systems without distutils.version"""
|
|
|
|
def __init__(self, version_str):
|
|
self.version_str = version_str
|
|
|
|
def __str__(self):
|
|
return self.version_str
|
|
|
|
def __repr__(self):
|
|
return 'Version(\'%s\')' % self.version_str
|
|
|
|
def components(self):
|
|
# Split the version into components, by word boundaries, or a
|
|
# change between numbers and non-numbers and vice-versa. re.split()
|
|
# does not work on zero-length delimiters, so we have to use a
|
|
# sub+split.
|
|
return re.sub(r'\b|(?<=\d)(?=\D)|(?<=\D)(?=\d)', '\n',
|
|
self.version_str).split('\n')
|
|
|
|
def __eq__(self, other):
|
|
return self.version_str == other.version_str
|
|
|
|
def __gt__(self, other):
|
|
def num_gt(str_, str_other):
|
|
m = re.search('^\d+', str_)
|
|
m_other = re.search('^\d+', str_other)
|
|
if m and m_other:
|
|
return int(m.group(0)) > int(m_other.group(0))
|
|
else:
|
|
return str_ > str_other
|
|
|
|
for self_c, other_c in zip(self.components(), other.components()):
|
|
if self_c == other_c:
|
|
continue
|
|
else:
|
|
return num_gt(self_c, other_c)
|
|
return False
|
|
|
|
# Note: not using functools.total_ordering to support Python 2.6
|
|
|
|
def __lt__(self, other):
|
|
return not (self == other) and not (self > other)
|
|
|
|
|
|
def proc_version():
|
|
"""Return the content of /proc/version"""
|
|
|
|
proc_version = None
|
|
|
|
# Not using a with statement here, to support Python 2.4
|
|
v = open('/proc/version', 'r')
|
|
try:
|
|
proc_version = v.read()
|
|
finally:
|
|
v.close()
|
|
return proc_version
|
|
|
|
|
|
def running_kernel_version():
|
|
proc_version_ = proc_version()
|
|
|
|
if re.search('Debian', proc_version_):
|
|
# Remove gcc version first
|
|
proc_version_ = re.sub('\(gcc.*?\)', '', proc_version_)
|
|
|
|
# Then look for the Debian kernel version
|
|
m = re.search('((?<=Debian )(\S+)|(?<=PVE )(\S+))', proc_version_)
|
|
if m:
|
|
version_str = m.group(1).strip('()')
|
|
version = clean_kernel_version(version_str)
|
|
return version
|
|
|
|
else:
|
|
m = re.search('(?<=Linux version )(\S+)', proc_version_)
|
|
if m:
|
|
version = clean_kernel_version(m.group(0))
|
|
return version
|
|
|
|
|
|
def is_debian():
|
|
return posixpath.exists('/etc/debian_version')
|
|
|
|
|
|
def is_fedora():
|
|
return posixpath.exists('/etc/fedora-release')
|
|
|
|
|
|
def is_redhat():
|
|
return posixpath.exists('/etc/redhat-release')
|
|
|
|
|
|
def installed_kernel_versions():
|
|
"""
|
|
Debian-based kernels come in different flavors.
|
|
|
|
On some of them, like Proxmox' PVE kernels, special care has to be taken
|
|
when selecting the right packages to run `dpkg-query` on.
|
|
"""
|
|
if is_debian():
|
|
return \
|
|
installed_kernel_versions_debian(pkgname='linux-image') \
|
|
or installed_kernel_versions_debian(pkgname='pve-kernel',
|
|
pkgquery='pve-kernel*-pve')
|
|
if is_fedora() or is_redhat():
|
|
return installed_kernel_versions_fedora()
|
|
return [None]
|
|
|
|
|
|
def check_output(cmd):
|
|
"""Emulate subprocess.check_output for ancient Python versions"""
|
|
return subprocess.Popen(
|
|
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
|
).communicate()[0]
|
|
|
|
|
|
def installed_kernel_versions_debian(pkgname='linux-image', pkgquery=None):
|
|
if not pkgquery:
|
|
pkgquery = '%s*' % pkgname
|
|
dpkg_out = check_output(
|
|
['dpkg-query',
|
|
'--show', '--showformat', '${Package} ${Version}\n',
|
|
pkgquery])
|
|
dpkg_out = dpkg_out.decode('ascii', 'ignore').strip()
|
|
|
|
versions = dpkg_out.split('\n')
|
|
versions = [v for v in versions if re.search('^%s-\d.* \S+$' % pkgname, v)]
|
|
versions = [clean_kernel_version(v.split(' ')[1]) for v in versions]
|
|
|
|
return versions
|
|
|
|
|
|
def installed_kernel_versions_fedora():
|
|
rpm_out = check_output(
|
|
['rpm', '--queryformat=%{VERSION}-%{RELEASE}\n', '-q', 'kernel'])
|
|
rpm_out = rpm_out.decode('ascii', 'ignore').strip()
|
|
|
|
versions = rpm_out.split('\n')
|
|
versions = [clean_kernel_version(v) for v in versions]
|
|
|
|
return versions
|
|
|
|
|
|
def installed_kernel_version():
|
|
installed = sorted(installed_kernel_versions())
|
|
if not installed:
|
|
print('KERNEL UNKNOWN - unable to determine installed kernel version')
|
|
sys.exit(3)
|
|
return installed[-1]
|
|
|
|
|
|
def clean_kernel_version(version):
|
|
# arch
|
|
version = re.sub('\.(x86_64|i[3-6]86)', '', version)
|
|
# Fedora release
|
|
version = re.sub('\.fc\d+', '', version)
|
|
# RHEL release
|
|
version = re.sub('\.el[\d\._]+$', '', version)
|
|
|
|
return Version(version)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) > 1:
|
|
print('This plugin no longer takes the expected kernel version as' +
|
|
'an argument')
|
|
sys.exit(3)
|
|
|
|
running = running_kernel_version()
|
|
installed = installed_kernel_version()
|
|
|
|
if running == installed:
|
|
print('KERNEL OK - running version %s' % running)
|
|
sys.exit(0)
|
|
else:
|
|
print('KERNEL WARNING - running version %s, installed: %s' %
|
|
(running, installed))
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|