forked from rpms/dnf-plugins-core
needs-restarting: Get boot time from systemd UnitsLoadStartTimestamp
Resolves: RHEL-14900
This commit is contained in:
parent
b4c0ac07e8
commit
32b466a0fd
159
0020-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
Normal file
159
0020-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
Normal file
@ -0,0 +1,159 @@
|
||||
From 8cf40027b920b3760d6d1df9eb280b4f3772f290 Mon Sep 17 00:00:00 2001
|
||||
From: Evan Goode <mail@evangoo.de>
|
||||
Date: Thu, 3 Oct 2024 21:37:58 +0000
|
||||
Subject: [PATCH] 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 309a216..9c77af7 100644
|
||||
--- a/plugins/needs_restarting.py
|
||||
+++ b/plugins/needs_restarting.py
|
||||
@@ -203,36 +203,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():
|
||||
@@ -241,10 +294,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.47.0
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
Name: dnf-plugins-core
|
||||
Version: 4.3.0
|
||||
Release: 17%{?dist}
|
||||
Release: 18%{?dist}
|
||||
Summary: Core Plugins for DNF
|
||||
License: GPLv2+
|
||||
URL: https://github.com/rpm-software-management/dnf-plugins-core
|
||||
@ -55,6 +55,7 @@ Patch13: 0013-Fix-for-issue-with-binary-garbage-in-smaps-files.patch
|
||||
Patch14: 0014-needs-restarting-Add-microcode_ctl-to-a-reboot-list.patch
|
||||
Patch18: 0018-system-upgrade-change-http-to-https-in-unit-file.patch
|
||||
Patch19: 0019-reposync-Respect-norepopath-with-metadata-path.patch
|
||||
Patch20: 0020-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
|
||||
|
||||
BuildArch: noarch
|
||||
BuildRequires: cmake
|
||||
@ -802,6 +803,9 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Thu Nov 21 2024 Evan Goode <egoode@redhat.com> - 4.3.0-18
|
||||
- needs-restarting: Get boot time from systemd UnitsLoadStartTimestamp (RHEL-14900)
|
||||
|
||||
* Thu Oct 10 2024 Pavla Kratochvilova <pkratoch@redhat.com> - 4.3.0-17
|
||||
- reposync: Respect --norepopath with --metadata-path (RHEL-40914)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user