diff options
author | Igor Galić <me+git@igalic.co> | 2020-01-10 05:06:06 +0100 |
---|---|---|
committer | Chad Smith <chad.smith@canonical.com> | 2020-01-09 21:06:06 -0700 |
commit | c911afbfe5a38823971e9cdbd4d1848c6e5c16de (patch) | |
tree | 4c6f04f883e0394b6bfc1d24d94c7db294e76fdd /cloudinit | |
parent | 6e7f8590402967bffbdd0bb0ae241180910fcd2c (diff) | |
download | vyos-cloud-init-c911afbfe5a38823971e9cdbd4d1848c6e5c16de.tar.gz vyos-cloud-init-c911afbfe5a38823971e9cdbd4d1848c6e5c16de.zip |
util: move uptime's else branch into its own boottime function (#53)
Also fix bugs:
- pass binary instead of string to sysctlbyname(), and
- unpack the "return value" in a struct, rather than in single integer.
LP: #1853160
Co-Authored-By: Ryan Harper <ryan.harper@canonical.com>
Diffstat (limited to 'cloudinit')
-rw-r--r-- | cloudinit/tests/test_util.py | 15 | ||||
-rw-r--r-- | cloudinit/util.py | 39 |
2 files changed, 44 insertions, 10 deletions
diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py index be100646..11f37000 100644 --- a/cloudinit/tests/test_util.py +++ b/cloudinit/tests/test_util.py @@ -189,6 +189,21 @@ class TestUtil(CiTestCase): self.assertEqual(is_rw, False) +class TestUptime(CiTestCase): + + @mock.patch('cloudinit.util.boottime') + @mock.patch('cloudinit.util.os.path.exists') + @mock.patch('cloudinit.util.time.time') + def test_uptime_non_linux_path(self, m_time, m_exists, m_boottime): + boottime = 1000.0 + uptime = 10.0 + m_boottime.return_value = boottime + m_time.return_value = boottime + uptime + m_exists.return_value = False + result = util.uptime() + self.assertEqual(str(uptime), result) + + class TestShellify(CiTestCase): def test_input_dict_raises_type_error(self): diff --git a/cloudinit/util.py b/cloudinit/util.py index 830c8e54..76d7db78 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -10,7 +10,6 @@ import contextlib import copy as obj_copy -import ctypes import email import glob import grp @@ -1807,6 +1806,33 @@ def time_rfc2822(): return ts +def boottime(): + """Use sysctlbyname(3) via ctypes to find kern.boottime + + kern.boottime is of type struct timeval. Here we create a + private class to easier unpack it. + + @return boottime: float to be compatible with linux + """ + import ctypes + + NULL_BYTES = b"\x00" + + class timeval(ctypes.Structure): + _fields_ = [ + ("tv_sec", ctypes.c_int64), + ("tv_usec", ctypes.c_int64) + ] + libc = ctypes.CDLL('/lib/libc.so.7') + size = ctypes.c_size_t() + size.value = ctypes.sizeof(timeval) + buf = timeval() + if libc.sysctlbyname(b"kern.boottime" + NULL_BYTES, ctypes.byref(buf), + ctypes.byref(size), None, 0) != -1: + return buf.tv_sec + buf.tv_usec / 1000000.0 + raise RuntimeError("Unable to retrieve kern.boottime on this system") + + def uptime(): uptime_str = '??' method = 'unknown' @@ -1818,15 +1844,8 @@ def uptime(): uptime_str = contents.split()[0] else: method = 'ctypes' - libc = ctypes.CDLL('/lib/libc.so.7') - size = ctypes.c_size_t() - buf = ctypes.c_int() - size.value = ctypes.sizeof(buf) - libc.sysctlbyname("kern.boottime", ctypes.byref(buf), - ctypes.byref(size), None, 0) - now = time.time() - bootup = buf.value - uptime_str = now - bootup + # This is the *BSD codepath + uptime_str = str(time.time() - boottime()) except Exception: logexc(LOG, "Unable to read uptime using method: %s" % method) |