[Git][NTPsec/ntpsec][master] 5 commits: ntpq: Re-add synthetic garbage for group, then single value grab fails
James Browning (@jamesb_fe80)
gitlab at mg.gitlab.com
Thu Feb 10 16:00:53 UTC 2022
James Browning pushed to branch master at NTPsec / ntpsec
Commits:
9d7ef0ca by James Browning at 2022-02-10T13:34:23+00:00
ntpq: Re-add synthetic garbage for group, then single value grab fails
- - - - -
1c7defb7 by James Browning at 2022-02-10T13:34:23+00:00
ntp.util: Add duration&packet count helpers/tests, uptime now lambda.
- - - - -
e6cc59fd by James Browning at 2022-02-10T13:34:23+00:00
ntpw: Attach yet unused duration/packet count helpers bar sysstats..
- - - - -
0e9ceccd by James Browning at 2022-02-10T13:34:23+00:00
ntpq: make sysstats 3-5 columns wide, much else 2-3.
- - - - -
fb5cb3a1 by James Browning at 2022-02-10T13:34:23+00:00
ntp.util, ntpq: clip some trailing whitespace.
- - - - -
3 changed files:
- ntpclients/ntpq.py
- pylib/util.py
- tests/pylib/test_util.py
Changes:
=====================================
ntpclients/ntpq.py
=====================================
@@ -53,7 +53,8 @@ NTP_LFP = 0x7 # NTP timestamp
NTP_MODE = 0x8 # peer mode
NTP_2BIT = 0x9 # leap bits
NTP_FLOAT = 0xa # Float value
-NTP_UPTIME = 0xb # uptime in days H:M:S (no frac)
+NTP_UPTIME = 0xb # uptime in daysD H:M:S (usually no frac)
+NTP_PACKETS = 0xc # packet counts
class Ntpq(cmd.Cmd):
@@ -415,7 +416,7 @@ usage: timeout [ msec ]
items.append((name, (value, rawvalue)))
except ntp.packet.ControlException as e:
if ntp.control.CERR_UNKNOWNVAR == e.errorcode:
- items.append((var, "???"))
+ items.append((var, ("???", None)))
continue
raise e
queried = ntp.util.OrderedDict(items)
@@ -429,6 +430,7 @@ usage: timeout [ msec ]
self.say(self.session.response)
return
try:
+ runs, runl = None, None
for (name, legend, fmt) in variables:
if name not in queried:
continue
@@ -437,19 +439,34 @@ usage: timeout [ msec ]
value2 = queried[name + '_r'][0]
rawvalue2 = queried[name + '_r'][1]
if fmt in (NTP_UINT, NTP_INT, NTP_FLOAT):
- if self.showunits:
- displayvalue = ntp.util.unitifyvar(rawvalue, name)
- displayvalue2 = ntp.util.unitifyvar(rawvalue2, name)
+ if self.showunits and isinstance(rawvalue, (int, float)):
+ display = ntp.util.unitifyvar(rawvalue, name)
else:
- displayvalue = value
- displayvalue2 = value2
- self.say("%13s \t%9d\t%9d\n" %
- (legend, displayvalue, displayvalue2))
+ display = value
+ if self.showunits and isinstance(rawvalue2, (int, float)):
+ display2 = ntp.util.unitifyvar(rawvalue2, name)
+ else:
+ display2 = value2
+ self.say("%13s %12s %12s\n" %
+ (legend, display, display2))
+ elif fmt == NTP_PACKETS:
+ self.say(
+ "{0:<13} {1[0]:>15} {2[0]:>15} {1[1]:>12}{1[2]:<3} {2[1]:>12}{2[2]:<3}\n".format(
+ legend,
+ ntp.util.packetize(value, runs),
+ ntp.util.packetize(
+ value2, runl, periodized=True, clipdigits=3
+ ),
+ )
+ )
elif fmt == NTP_UPTIME:
- self.say("%13s %s\t%s\n" % (legend, ntp.util.prettyuptime(
- value), ntp.util.prettyuptime(value2)))
+ runs, display = ntp.util.periodize(value)
+ runl, display2 = ntp.util.periodize(value2)
+ self.say(
+ "{0:<13} {1:>15} {2:>15}\n".format(legend, display, display2)
+ )
else:
- self.warn("unexpected vc type %s for %s, value %s"
+ self.warn("unexpected vc type %s for %s, value %s %s "
% (fmt, name, value, value2))
except KeyboardInterrupt:
self.warn("display interrupted")
@@ -495,13 +512,14 @@ usage: timeout [ msec ]
% (associd, self.session.rstatus,
ntp.ntpc.statustoa(statype, self.session.rstatus)))
try:
+ run = 1
for (name, legend, fmt) in variables:
if name not in queried:
continue
value = queried[name][0]
rawvalue = queried[name][1]
if fmt in (NTP_ADD, NTP_ADP):
- if self.showhostnames & 1: # if & 1, display names
+ if self.showhostnames & 1: # if & 1, display names
if self.debug:
self.say("DNS lookup begins...")
value = ntp.util.canonicalize_dns(
@@ -517,7 +535,7 @@ usage: timeout [ msec ]
displayvalue = ntp.util.unitifyvar(rawvalue, name)
else:
displayvalue = value
- self.say("%s %s\n" % (legend, displayvalue))
+ self.say("%13s %13s\n" % (legend, displayvalue))
elif fmt == NTP_LFP:
self.say("%s %s\n" % (legend, ntp.ntpc.prettydate(value)))
elif fmt == NTP_2BIT:
@@ -533,6 +551,15 @@ usage: timeout [ msec ]
self.say("%s %s\n" % (legend, modes[value]))
except IndexError:
self.say("%s %s%d\n" % (legend, "mode#", value))
+ elif fmt == NTP_PACKETS:
+ self.say(
+ "{0:<13} {1[0]:>15} {1[1]:>8}{1[2]:<3}\n".format(
+ legend, ntp.util.packetize(value, run)
+ )
+ )
+ elif fmt == NTP_UPTIME:
+ run, display = ntp.util.periodize(value)
+ self.say("{0:<13} {1:>15}\n".format(legend, display))
else:
self.warn("unexpected vc type %s for %s, value %s"
% (fmt, name, value))
@@ -1139,8 +1166,8 @@ usage: cv [ assocID ] [ name=value[,...] ]
pstats = (
("srcadr", "remote host: ", NTP_ADD),
("dstadr", "local address: ", NTP_ADD),
- ("timerec", "time last received: ", NTP_INT),
- ("timer", "time until next send: ", NTP_INT),
+ ("timerec", "time last received: ", NTP_UPTIME),
+ ("timer", "time until next send: ", NTP_UPTIME),
("timereach", "reachability change: ", NTP_INT),
("sent", "packets sent: ", NTP_INT),
("received", "packets received: ", NTP_INT),
@@ -1524,21 +1551,24 @@ usage: kerninfo
def do_sysstats(self, _line):
"display system uptime and packet counts"
sysstats = (
- ("ss_uptime", "uptime: ", NTP_INT),
+ ("ss_uptime", "uptime: ", NTP_UPTIME),
("ss_numctlreq", "control requests: ", NTP_INT),
+ )
+ sysstats2 = (
("ss_reset", "sysstats reset: ", NTP_UPTIME),
- ("ss_received", "packets received: ", NTP_INT),
- ("ss_thisver", "current version: ", NTP_INT),
- ("ss_oldver", "older version: ", NTP_INT),
- ("ss_badformat", "bad length or format: ", NTP_INT),
- ("ss_badauth", "authentication failed:", NTP_INT),
- ("ss_declined", "declined: ", NTP_INT),
- ("ss_restricted", "restricted: ", NTP_INT),
- ("ss_limited", "rate limited: ", NTP_INT),
- ("ss_kodsent", "KoD responses: ", NTP_INT),
- ("ss_processed", "processed for time: ", NTP_INT),
+ ("ss_received", "packets received: ", NTP_PACKETS),
+ ("ss_thisver", "current version: ", NTP_PACKETS),
+ ("ss_oldver", "older version: ", NTP_PACKETS),
+ ("ss_badformat", "bad length or format: ", NTP_PACKETS),
+ ("ss_badauth", "authentication failed:", NTP_PACKETS),
+ ("ss_declined", "declined: ", NTP_PACKETS),
+ ("ss_restricted", "restricted: ", NTP_PACKETS),
+ ("ss_limited", "rate limited: ", NTP_PACKETS),
+ ("ss_kodsent", "KoD responses: ", NTP_PACKETS),
+ ("ss_processed", "processed for time: ", NTP_PACKETS),
)
self.collect_display(associd=0, variables=sysstats, decodestatus=False)
+ self.collect_display2(variables=sysstats2)
def help_sysstats(self):
self.say("""\
@@ -1557,8 +1587,8 @@ usage: sysstats
("mru_deepest", "peak addresses: ", NTP_INT),
("mru_maxdepth", "maximum addresses: ", NTP_INT),
("mru_mindepth", "reclaim above count: ", NTP_INT),
- ("mru_maxage", "reclaim maxage: ", NTP_INT),
- ("mru_minage", "reclaim minage: ", NTP_INT),
+ ("mru_maxage", "reclaim maxage: ", NTP_UPTIME),
+ ("mru_minage", "reclaim minage: ", NTP_UPTIME),
("mru_mem", "kilobytes: ", NTP_INT),
("mru_maxmem", "maximum kilobytes: ", NTP_INT),
("mru_exists", "alloc: exists: ", NTP_INT),
@@ -1566,7 +1596,7 @@ usage: sysstats
("mru_recycleold", "alloc: recycle old: ", NTP_INT),
("mru_recyclefull", "alloc: recycle full: ", NTP_INT),
("mru_none", "alloc: none: ", NTP_INT),
- ("mru_oldest_age", "age of oldest slot: ", NTP_INT),
+ ("mru_oldest_age", "age of oldest slot: ", NTP_UPTIME),
)
self.collect_display(associd=0, variables=monstats, decodestatus=False)
@@ -1581,19 +1611,19 @@ usage: monstats
def do_authinfo(self, _line):
"display symmetric authentication counters"
authinfo = (
- ("authreset", "time since reset: ", NTP_INT),
+ ("authreset", "time since reset: ", NTP_UPTIME),
("authkeys", "stored keys: ", NTP_INT),
("authfreek", "free keys: ", NTP_INT),
("authklookups", "key lookups: ", NTP_INT),
("authknotfound", "keys not found: ", NTP_INT),
- ("authencrypts", "encryptions: ", NTP_INT),
- ("authdigestencrypts", "digest encryptions: ", NTP_INT),
- ("authcmacencrypts", "CMAC encryptions: ", NTP_INT),
- ("authdecrypts", "decryptions: ", NTP_INT),
- ("authdigestdecrypts", "digest decryptions: ", NTP_INT),
- ("authdigestfails", "digest failures: ", NTP_INT),
- ("authcmacdecrypts", "CMAC decryptions: ", NTP_INT),
- ("authcmacfails", "CMAC failures: ", NTP_INT),
+ ("authencrypts", "encryptions: ", NTP_PACKETS),
+ ("authdigestencrypts", "digest encryptions: ", NTP_PACKETS),
+ ("authcmacencrypts", "CMAC encryptions: ", NTP_PACKETS),
+ ("authdecrypts", "decryptions: ", NTP_PACKETS),
+ ("authdigestdecrypts", "digest decryptions: ", NTP_PACKETS),
+ ("authdigestfails", "digest failures: ", NTP_PACKETS),
+ ("authcmacdecrypts", "CMAC decryptions: ", NTP_PACKETS),
+ ("authcmacfails", "CMAC failures: ", NTP_PACKETS),
# Old variables no longer supported.
# Interesting if looking at an old system.
("authkuncached", "uncached keys: ", NTP_INT),
@@ -1642,16 +1672,16 @@ usage: ntsinfo
def do_iostats(self, _line):
"display network input and output counters"
iostats = (
- ("iostats_reset", "time since reset: ", NTP_INT),
+ ("iostats_reset", "time since reset: ", NTP_UPTIME),
("total_rbuf", "receive buffers: ", NTP_INT),
("free_rbuf", "free receive buffers: ", NTP_INT),
("used_rbuf", "used receive buffers: ", NTP_INT),
("rbuf_lowater", "low water refills: ", NTP_INT),
- ("io_dropped", "dropped packets: ", NTP_INT),
- ("io_ignored", "ignored packets: ", NTP_INT),
- ("io_received", "received packets: ", NTP_INT),
- ("io_sent", "packets sent: ", NTP_INT),
- ("io_sendfailed", "packet send failures: ", NTP_INT),
+ ("io_dropped", "dropped packets: ", NTP_PACKETS),
+ ("io_ignored", "ignored packets: ", NTP_PACKETS),
+ ("io_received", "received packets: ", NTP_PACKETS),
+ ("io_sent", "packets sent: ", NTP_PACKETS),
+ ("io_sendfailed", "packet send failures: ", NTP_PACKETS),
("io_wakeups", "input wakeups: ", NTP_INT),
("io_goodwakeups", "useful input wakeups: ", NTP_INT),
)
@@ -1668,7 +1698,7 @@ usage: iostats
def do_timerstats(self, line):
"display interval timer counters"
timerstats = (
- ("timerstats_reset", "time since reset: ", NTP_INT),
+ ("timerstats_reset", "time since reset: ", NTP_UPTIME),
("timer_overruns", "timer overruns: ", NTP_INT),
("timer_xmts", "calls to transmit: ", NTP_INT),
)
=====================================
pylib/util.py
=====================================
@@ -1221,7 +1221,7 @@ class MRUSummary:
self.debug = debug
self.logfp = logfp
self.now = None
- self.showhostnames = showhostnames # if & 1, display names
+ self.showhostnames = showhostnames # if & 1, display names
self.wideremote = wideremote
header = " lstint avgint rstr r m v count score drop rport remote address"
@@ -1435,11 +1435,42 @@ except ImportError: # pragma: no cover
yield key
-def prettyuptime(uptime):
- result = ''
- if uptime >= 86400:
- result += '%dD ' % (uptime // 86400)
- result += '%02d:%02d:%02d' % ((uptime % 86400) //
- 3600, (uptime % 3600) // 60, uptime % 60)
- return result
+def packetize(packets, period, clipdigits=0, periodized=False):
+ """Given a number of packets and a duration (s) return a tuple.
+
+ return the packet quantity, and a two part rate in packets/seconds
+ or seconds/packet. On error the latter fields should be blank, the
+ first the number of packets if zero otherwise unhelpful text."""
+ if not isinstance(packets, int):
+ return ("???", "", "")
+ if packets == 0 or not isinstance(period, (int, float)):
+ return (packets, "", "")
+ if packets > period:
+ return (packets, round(packets / period, clipdigits), "p/s")
+ if periodized:
+ return (packets, periodize(period / packets, clipdigits)[1], "/p")
+ return (packets, round(period / packets, clipdigits), "s/p")
+
+
+def periodize(period, clipdigits=0):
+ """Given a number of seconds, return number and pretty string.
+
+ On error return None for the number and an unhelpful string."""
+ clip = clipdigits if isinstance(clipdigits, (int, float)) else 0
+ if not isinstance(period, (int, float)):
+ return (None, "???")
+ result = ""
+ _ = round(period, clip)
+ nperiod = int(_) if clip < 1 else _
+ if nperiod >= 86400:
+ result += "%dD " % (nperiod // 86400)
+ result += "%02d:%02d:%02d" % (
+ (nperiod % 86400) // 3600,
+ (nperiod % 3600) // 60,
+ nperiod % 60,
+ )
+ return (nperiod, result)
+
+
+uptime = lambda p: periodize(p)[1]
# end
=====================================
tests/pylib/test_util.py
=====================================
@@ -2,6 +2,7 @@
from __future__ import print_function
+import inspect
import unittest
import ntp.util
import ntp.packet
@@ -1273,5 +1274,118 @@ class TestPeerSummary(unittest.TestCase):
self.assertEqual(cls.polls, [])
+class NtpqRvInfoStats(unittest.TestCase):
+ """Test functions by controlling their diet and examining output.
+
+ Iterate through casees a 3 tuple, first element is a sub tuple
+ it gets fed to the subject. The second is compared to the output.
+ The third is a string to append to the test when things break.
+ """
+
+ periodic = 230258.509299404568402
+ packets = 9586785
+
+ def test_periodize(self):
+ """Test ntp.util.periodize by coqtavoric gavage and scatology."""
+ # def periodize(period, clipdigits=0)
+ cases = (
+ ((self.periodic, 5), (round(self.periodic, 5), "2D 15:57:38"), "normal"),
+ ((str(self.periodic), 5), (None, "???"), "period is str"),
+ (
+ (self.periodic, None),
+ (round(self.periodic), "2D 15:57:39"),
+ "clipdigits is None",
+ ),
+ # (('there', 'is'),('no', 'cake'),'broca'), # False test
+ )
+ shot_test(self, ntp.util.periodize, cases)
+
+ def test_packetize(self):
+ """Test ntp.util.packetize by coqtavoric gavage and scatology."""
+ # def packetize(packets, period, clipdigits=0, periodized=False)
+ cases = (
+ ((7.5, self.periodic), ("???", "", ""), "packets is float"),
+ ((0, self.periodic), (0, "", ""), "packets == 0"),
+ (
+ (self.packets, str(self.periodic)),
+ (self.packets, "", ""),
+ "period is str",
+ ),
+ (
+ (self.packets, self.periodic, 0),
+ (self.packets, 42.0, "p/s"),
+ "more packets, clipdigits == 0",
+ ),
+ (
+ (self.packets, self.periodic, 5),
+ (self.packets, 41.63488, "p/s"),
+ "more packets, clipdigits = 5",
+ ),
+ (
+ (self.packets // 200, self.periodic, 0, True),
+ (self.packets // 200, "00:00:05", "/p"),
+ "more time, clipdigits == 5, stringify",
+ ),
+ (
+ (self.packets // 200, self.periodic, 5, True),
+ (self.packets // 200, "00:00:04", "/p"),
+ "more time, clipdigits == 5, stringify",
+ ),
+ (
+ (self.packets // 200, self.periodic, 0, False),
+ (self.packets // 200, 5.0, "s/p"),
+ "more time, clipdigits == 5, float",
+ ),
+ (
+ (self.packets // 200, self.periodic, 5, False),
+ (self.packets // 200, 4.80376, "s/p"),
+ "more time, clipdigits == 5, float",
+ ),
+ # ((50, 10, 0, True),('the', 'cake', 'lies'),'broca') # False test
+ )
+ shot_test(self, ntp.util.packetize, cases)
+
+ def test_uptime(self):
+ # def uptime(period):
+ """Test ntp.util.uptime by coqtavoric gavage and scatology."""
+ cases = [
+ # [['cake'], 'you will be baked', 'broca'],
+ [[-2.6], "23:59:57", "-float"],
+ [[0.0], "00:00:00", "0float"],
+ [[2.3], "00:00:02", "+float"],
+ [[-2], "23:59:58", "-int"],
+ [[0], "00:00:00", "0int"],
+ [[2], "00:00:02", "+int"],
+ ]
+ shot_test(self, ntp.util.uptime, cases)
+
+
+def shot_test(classy, hook, cases):
+ if "msg" in inspect.getargspec(classy.assertEqual).args:
+ aeq = lambda r, l, d: classy.assertEqual(r, l, d)
+ else:
+ aeq = lambda r, l, d: classy.assertEqual(r, l) # d
+
+ if hasattr(NtpqRvInfoStats, "subTest"):
+
+ def st(h, c):
+ for s in c:
+ with classy.subTest(s=s):
+ aeq(h(*s[0]), s[1], s[2])
+
+ else:
+
+ def st(h, c):
+ l_e, l_r, m = [], [], []
+ for s in c:
+ i = h(*s[0])
+ l_r.append([i])
+ l_e.append([s[1]])
+ m.append([s[2]])
+ aeq(l_e, l_r, m)
+
+ st(hook, cases)
+
+
if __name__ == '__main__':
unittest.main()
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/2bf5e4f6f5b6658174201d7541efe5523d41c1ee...fb5cb3a150cd866dae3e9bd468de3094724c3443
--
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/2bf5e4f6f5b6658174201d7541efe5523d41c1ee...fb5cb3a150cd866dae3e9bd468de3094724c3443
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20220210/aad523d5/attachment-0001.htm>
More information about the vc
mailing list