needs-restarting: Get boot time from systemd UnitsLoadStartTimestamp
Resolves: RHEL-35577
This commit is contained in:
parent
2997344d02
commit
f51fac7f6e
159
0008-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
Normal file
159
0008-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
Normal file
@ -0,0 +1,159 @@
|
||||
From 1966c63fcc99513603e06b8579cabfce15123b4f Mon Sep 17 00:00:00 2001
|
||||
From: Evan Goode <mail@evangoo.de>
|
||||
Date: Thu, 3 Oct 2024 21:37:58 +0000
|
||||
Subject: [PATCH 1/2] needs-restarting: Get boot time from systemd
|
||||
UnitsLoadStartTimestamp
|
||||
|
||||
Resolves https://issues.redhat.com/browse/RHEL-35577.
|
||||
|
||||
Get the boot time from UnitsLoadStartTimestamp if systemd is available,
|
||||
but make sure to use the kernel boot time for calculating process start
|
||||
times using data from procfs. The previous attempt [1] at this failed to
|
||||
do so and introduced a regression [2].
|
||||
|
||||
Also, get the kernel boot time from the btime field of /proc/stat instead of
|
||||
calculating it from /proc/uptime, to be consistent with what procps-ng
|
||||
does.
|
||||
|
||||
[1] https://github.com/rpm-software-management/dnf-plugins-core/pull/527
|
||||
[2] https://issues.redhat.com/browse/RHEL-39775
|
||||
---
|
||||
plugins/needs_restarting.py | 106 +++++++++++++++++++++++++++---------
|
||||
1 file changed, 81 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
|
||||
index cbb7a81..8e01aba 100644
|
||||
--- a/plugins/needs_restarting.py
|
||||
+++ b/plugins/needs_restarting.py
|
||||
@@ -206,36 +206,89 @@ class OpenedFile(object):
|
||||
return match.group(1)
|
||||
return self.name
|
||||
|
||||
-
|
||||
class ProcessStart(object):
|
||||
def __init__(self):
|
||||
- self.boot_time = self.get_boot_time()
|
||||
- self.sc_clk_tck = self.get_sc_clk_tck()
|
||||
+ self.kernel_boot_time = ProcessStart.get_kernel_boot_time()
|
||||
+ self.boot_time = ProcessStart.get_boot_time(self.kernel_boot_time)
|
||||
+ self.sc_clk_tck = ProcessStart.get_sc_clk_tck()
|
||||
+
|
||||
+ @staticmethod
|
||||
+ def get_kernel_boot_time():
|
||||
+ try:
|
||||
+ with open('/proc/stat', 'r') as file:
|
||||
+ for line in file:
|
||||
+ if line.startswith("btime "):
|
||||
+ key, value = line.split()
|
||||
+ return float(value)
|
||||
+ except OSError as e:
|
||||
+ logger.debug("Couldn't read /proc/stat: %s", e)
|
||||
+ return 0
|
||||
|
||||
@staticmethod
|
||||
- def get_boot_time():
|
||||
+ def get_boot_time(kernel_boot_time):
|
||||
"""
|
||||
- We have two sources from which to derive the boot time. These values vary
|
||||
+ We have three sources from which to derive the boot time. These values vary
|
||||
depending on containerization, existence of a Real Time Clock, etc.
|
||||
- For our purposes we want the latest derived value.
|
||||
+ - UnitsLoadStartTimestamp property on /org/freedesktop/systemd1
|
||||
+ The start time of the service manager, according to systemd itself.
|
||||
+ Seems to be more reliable than UserspaceTimestamp when the RTC is
|
||||
+ in local time. Works unless the system was not booted with systemd,
|
||||
+ such as in (most) containers.
|
||||
- st_mtime of /proc/1
|
||||
- Reflects the time the first process was run after booting
|
||||
- This works for all known cases except machines without
|
||||
- a RTC - they awake at the start of the epoch.
|
||||
- - /proc/uptime
|
||||
- Seconds field of /proc/uptime subtracted from the current time
|
||||
- Works for machines without RTC iff the current time is reasonably correct.
|
||||
- Does not work on containers which share their kernel with the
|
||||
- host - there the host kernel uptime is returned
|
||||
+ Reflects the time the first process was run after booting. This
|
||||
+ works for all known cases except machines without a RTC---they
|
||||
+ awake at the start of the epoch.
|
||||
+ - btime field of /proc/stat
|
||||
+ Reflects the time when the kernel started. Works for machines
|
||||
+ without RTC iff the current time is reasonably correct. Does not
|
||||
+ work on containers which share their kernel with the host---there,
|
||||
+ the host kernel uptime is returned.
|
||||
"""
|
||||
|
||||
- proc_1_boot_time = int(os.stat('/proc/1').st_mtime)
|
||||
- if os.path.isfile('/proc/uptime'):
|
||||
- with open('/proc/uptime', 'rb') as f:
|
||||
- uptime = f.readline().strip().split()[0].strip()
|
||||
- proc_uptime_boot_time = int(time.time() - float(uptime))
|
||||
- return max(proc_1_boot_time, proc_uptime_boot_time)
|
||||
- return proc_1_boot_time
|
||||
+ units_load_start_timestamp = None
|
||||
+ try:
|
||||
+ # systemd timestamps are the preferred method to determine boot
|
||||
+ # time. max(proc_1_boot_time, kernel_boot_time) does not allow us
|
||||
+ # to disambiguate between an unreliable RTC (e.g. the RTC is in
|
||||
+ # UTC+1 instead of UTC) and a container with a proc_1_boot_time >
|
||||
+ # kernel_boot_time. So we use UnitsLoadStartTimestamp if it's
|
||||
+ # available, else fall back to the other methods.
|
||||
+ bus = dbus.SystemBus()
|
||||
+ systemd1 = bus.get_object(
|
||||
+ 'org.freedesktop.systemd1',
|
||||
+ '/org/freedesktop/systemd1'
|
||||
+ )
|
||||
+ props = dbus.Interface(
|
||||
+ systemd1,
|
||||
+ dbus.PROPERTIES_IFACE
|
||||
+ )
|
||||
+ units_load_start_timestamp = props.Get(
|
||||
+ 'org.freedesktop.systemd1.Manager',
|
||||
+ 'UnitsLoadStartTimestamp'
|
||||
+ )
|
||||
+ if units_load_start_timestamp != 0:
|
||||
+ systemd_boot_time = units_load_start_timestamp / (1000 * 1000)
|
||||
+ logger.debug("Got boot time from systemd: %s", systemd_boot_time)
|
||||
+ return systemd_boot_time
|
||||
+ except dbus.exceptions.DBusException as e:
|
||||
+ logger.debug("D-Bus error getting boot time from systemd: %s", e)
|
||||
+
|
||||
+ logger.debug("Couldn't get boot time from systemd, checking st_mtime of /proc/1 and btime field of /proc/stat.")
|
||||
+
|
||||
+ try:
|
||||
+ proc_1_boot_time = float(os.stat('/proc/1').st_mtime)
|
||||
+ except OSError as e:
|
||||
+ logger.debug("Couldn't stat /proc/1: %s", e)
|
||||
+ proc_1_boot_time = 1
|
||||
+ kernel_boot_time = kernel_boot_time
|
||||
+
|
||||
+ boot_time = max(proc_1_boot_time, kernel_boot_time)
|
||||
+
|
||||
+ logger.debug("st_mtime of /proc/1: %s", proc_1_boot_time)
|
||||
+ logger.debug("btime field of /proc/stat: %s", kernel_boot_time)
|
||||
+ logger.debug("Using %s as the system boot time.", boot_time)
|
||||
+
|
||||
+ return boot_time
|
||||
|
||||
@staticmethod
|
||||
def get_sc_clk_tck():
|
||||
@@ -244,10 +297,13 @@ class ProcessStart(object):
|
||||
def __call__(self, pid):
|
||||
stat_fn = '/proc/%d/stat' % pid
|
||||
with open(stat_fn) as stat_file:
|
||||
- stats = stat_file.read().strip().split()
|
||||
- ticks_after_boot = int(stats[21])
|
||||
- secs_after_boot = ticks_after_boot // self.sc_clk_tck
|
||||
- return self.boot_time + secs_after_boot
|
||||
+ stats = stat_file.read().split()
|
||||
+ ticks_after_kernel_boot = int(stats[21])
|
||||
+ secs_after_kernel_boot = ticks_after_kernel_boot / self.sc_clk_tck
|
||||
+
|
||||
+ # The process's start time is always measured relative to the kernel
|
||||
+ # start time, not either of the other methods we use to get "boot time".
|
||||
+ return self.kernel_boot_time + secs_after_kernel_boot
|
||||
|
||||
|
||||
@dnf.plugin.register_command
|
||||
--
|
||||
2.48.1
|
||||
|
@ -0,0 +1,31 @@
|
||||
From 54b9f83879dfb7bccfd610845ae9981c55f776b5 Mon Sep 17 00:00:00 2001
|
||||
From: Evan Goode <mail@evangoo.de>
|
||||
Date: Wed, 22 Jan 2025 16:46:52 +0000
|
||||
Subject: [PATCH 2/2] doc: needs-restarting uses UnitsLoadStartTimestamp boot
|
||||
time
|
||||
|
||||
---
|
||||
doc/needs_restarting.rst | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/doc/needs_restarting.rst b/doc/needs_restarting.rst
|
||||
index e1fae48..fea407e 100644
|
||||
--- a/doc/needs_restarting.rst
|
||||
+++ b/doc/needs_restarting.rst
|
||||
@@ -36,8 +36,12 @@ Description
|
||||
Note that in most cases a process should survive update of its binary and libraries it is using without requiring to be restarted for proper operation. There are however specific cases when this does not apply. Separately, processes often need to be restarted to reflect security updates.
|
||||
|
||||
.. note::
|
||||
- Needs-restarting will try to guess the boot time using two different methods:
|
||||
+ Needs-restarting will try to guess the boot time using three different methods:
|
||||
|
||||
+ ``UnitsLoadStartTimestamp``
|
||||
+ D-Bus property on ``/org/freedesktop/systemd1``.
|
||||
+ Works unless the system was not booted with systemd,
|
||||
+ such as in (most) containers.
|
||||
``st_mtime of /proc/1``
|
||||
Reflects the time the first process was run after booting.
|
||||
This works for all known cases except machines without
|
||||
--
|
||||
2.48.1
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
Name: dnf-plugins-core
|
||||
Version: 4.7.0
|
||||
Release: 7%{?dist}
|
||||
Release: 8%{?dist}
|
||||
Summary: Core Plugins for DNF
|
||||
License: GPL-2.0-or-later
|
||||
URL: https://github.com/rpm-software-management/dnf-plugins-core
|
||||
@ -54,6 +54,8 @@ Patch4: 0004-s-Differnt-Different.patch
|
||||
Patch5: 0005-Enable-leaves-and-show-leaves-plugins-for-RHEL.patch
|
||||
Patch6: 0006-needs-restarting-Add-exclude-services.patch
|
||||
Patch7: 0007-needs-restarting-Add-exclude-services-to-man-page.patch
|
||||
Patch8: 0008-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
|
||||
Patch9: 0009-doc-needs-restarting-uses-UnitsLoadStartTimestamp-bo.patch
|
||||
BuildArch: noarch
|
||||
BuildRequires: cmake
|
||||
BuildRequires: gettext
|
||||
@ -884,6 +886,10 @@ ln -sf %{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/man1/repotrack.1
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Thu Jan 23 2025 Evan Goode <egoode@redhat.com> - 4.7.0-8
|
||||
- needs-restarting: Get boot time from systemd UnitsLoadStartTimestamp
|
||||
(RHEL-35577)
|
||||
|
||||
* Mon Jan 06 2025 Evan Goode <egoode@redhat.com> - 4.7.0-7
|
||||
- needs-restarting: Add --exclude-services flag
|
||||
Resolves: RHEL-56137
|
||||
|
Loading…
Reference in New Issue
Block a user