[Git][NTPsec/ntpsec][master] 2 commits: In pybtpq, improve implementation of showhostnames.

Eric S. Raymond gitlab at mg.gitlab.com
Thu Oct 27 19:15:12 UTC 2016


Eric S. Raymond pushed to branch master at NTPsec / ntpsec


Commits:
87cd3df4 by Eric S. Raymond at 2016-10-27T13:40:00-04:00
In pybtpq, improve implementation of showhostnames.

- - - - -
5f0de4cd by Eric S. Raymond at 2016-10-27T15:13:40-04:00
Refactoring step - make peer summary generator reusable.

- - - - -


2 changed files:

- ntpq/pyntpq
- pylib/util.py


Changes:

=====================================
ntpq/pyntpq
=====================================
--- a/ntpq/pyntpq
+++ b/ntpq/pyntpq
@@ -130,7 +130,6 @@ NTP_2BIT	= 0x9	# leap bits
 
 class Ntpq(cmd.Cmd):
     "ntpq command interpreter"
-
     def __init__(self, session):
         cmd.Cmd.__init__(self)
         self.session = session
@@ -150,25 +149,6 @@ class Ntpq(cmd.Cmd):
         self.debug = 0
         self.pktversion = NTP_OLDVERSION + 1
         self.uservars = collections.OrderedDict()
-        # By default, the peer spreadsheet layout is designed so lines just
-        # fit in 80 characters. This tells us how much extra horizontal space
-        # we have available on a wider terminal emulator
-        self.horizontal_slack = termsize()[1] - 80
-        # Peer spreadsheet column widths
-        self.namewidth = 15 + self.horizontal_slack
-        self.refidwidth = 15
-        # Compute peer spreadsheet headers 
-        self.__remote = "     remote    ".ljust(self.namewidth)
-        self.__common = "st t when poll reach   delay   offset  "
-        self.__opeerheader = self.__remote + \
-                             "       local      ".ljust(self.refidwidth) + \
-                             self.__common + "  disp\n"
-        self.__peerheader  = self.__remote + \
-                             "       refid      ".ljust(self.refidwidth) + \
-                             self.__common + "jitter\n"
-        self.__apeerheader = self.__remote + \
-                             "   refid   assid  ".ljust(self.refidwidth) + \
-                             self.__common + "jitter\n"
 
     def emptyline(self):
         "Called when an empty line is entered in response to the prompt."
@@ -188,15 +168,6 @@ usage: help [ command ]
 
     # Unexposed helper tables and functions begin here
 
-    @staticmethod
-    def high_truncate(hostname, maxlen):
-        "Truncate on the left using leading _ to indicate 'more'."
-        # Used for local IPv6 addresses, best distinguished by low bits
-        if len(hostname) <= maxlen:
-            return hostname
-        else:
-            return '-' + hostname[-maxlen+1:]
-
     def __dogetassoc(self):
         try:
             self.peers = self.session.readstat()
@@ -295,179 +266,23 @@ usage: help [ command ]
                      condition, last_event, event_count)
             self.say(display + "\n")
 
-    @staticmethod
-    def prettyinterval(diff):
-        "Print an interval in natural time units."
-        if diff <= 0:
-            return "-"
-        if diff <= 2048:
-            return str(diff)
-        diff = (diff + 29) / 60
-        if diff <= 300:
-            return "%dm" % diff
-        diff = (diff + 29) / 60
-        if diff <= 96:
-            return "%dh" % diff
-        diff = (diff + 11) / 24
-        return "%dd" % diff
-
-    def __doprintpeers(self, variables, header, associd):
-        hmode = 0
-        srchost = None
-        srcport = 0
-        srcaddr = None
-        dstadr_refid = ""
-        ppoll = 0
-        hpoll = 0
-        reach = 0
-        ptype = '?'
-        have_jitter = False
-        clock_name = ''
-
-        now = time.time()
-
-        for (name, value) in variables.items():
-            if name in ("srcadr", "peeradr"):
-                srcaddr = value
-            elif name == "srchost":
-                srchost = value
-            elif name == "dstadr":
-                # The C code tried to get a fallback pytpe from this in case
-                # the hmode field was not included
-                if "local" in header:
-                    dstadr_refid = value
-            elif name == "hmode":
-                hmode = value
-            elif name == "refid":
-                # The C code for this looked crazily overelaborate.  Best
-                # guess is that it was designed to deal with formats that
-                # no longer occur in this field.
-                if "refid" in header:
-                    dstadr_refid = value
-            elif name == "hpoll":
-                hpoll = value
-                if hpoll < 0:
-                    hpoll = NTP_MINPOLL
-            elif name == "ppoll":
-                ppoll = value
-                if ppoll < 0:
-                    ppoll = NTP_MINPOLL
-            elif name == "reach":
-                # Shipped as hex, displayed in octal
-                reach = value
-            elif name == "delay":
-                estdelay = value
-            elif name == "offset":
-                estoffset = value
-            elif name == "jitter":
-                if "jitter" in header:
-                    estjitter = value
-                    have_jitter = True
-            elif name == "rootdisp" or name == "dispersion":
-                estdisp = value
-            elif name == "rec":
-                rec = value	# l_fp timestamp
-            elif name == "srcport" or name == "peerport":
-                srcport = value
-            elif name == "reftime":
-                reftime = value	# l_fp timestamp
-        if hmode == MODE_BCLIENT:
-            # broadcastclient or multicastclient
-            ptype = 'b'
-        elif hmode == MODE_BROADCAST:
-            # broadcast or multicast server
-            if srcaddr.startswith("224."):	# IANA multicast address prefix
-                ptype = 'M'
-            else:
-                ptype = 'B'
-        elif hmode == MODE_CLIENT:
-            if srchost and '(' in srchost:
-                ptype = 'l'	# local refclock
-            elif dstadr_refid == "POOL":
-                ptype = 'p'	# pool
-            elif srcaddr.startswith("224."):
-                ptype = 'a'	# manycastclient
-            else:
-                ptype = 'u'	# unicast
-        elif hmode == MODE_ACTIVE:
-            ptype = 's'		# symmetric active
-        elif hmode == MODE_PASSIVE:
-            ptype = 'S'		# symmetric passive
-
-        #
-        # Got everything, format the line
-        #
-        poll_sec = 1 << min(ppoll, hpoll)
-        if self.pktversion > NTP_OLDVERSION:
-            c = " x.-+#*o"[CTL_PEER_STATVAL(self.session.rstatus) & 0x7]
-        else:
-            c = " .+*"[CTL_PEER_STATVAL(self.session.rstatus) & 0x3]
-        if len(self.chosts) > 1:
-            maxhostlen = max([len(host) for (host, _af) in self.chosts])
-            self.say(Ntpq.high_truncate(self.session.hostname, maxhostlen)+ " ")
-        # Source host or clockname
-        if srchost != None:
-            clock_name = srchost
-        else:
-            clock_name = canonicalize_dns(srcaddr)
-        if interpreter.wideremote and len(clock_name) > self.namewidth:
-            self.say("%c%s\n" % (c, clock_name))
-            sys.stdout(" " * (self.namewidth + 2))
-        else:
-            self.say("%c%-*.*s " % \
-                             (c, self.namewidth, self.namewidth, clock_name[:self.namewidth]))
-        # Destination address, assoc ID or refid.
-        assocwidth = 7 if "assid" in header else 0
-        if "." not in dstadr_refid:
-            dstadr_refid = "." + dstadr_refid + "."
-        if assocwidth and len(dstadr_refid) >= self.refidwidth - assocwidth:
-            visible = "..."
-        else:
-            visible = dstadr_refid
-        self.say(visible)
-        if "assid" in header:
-            self.say(" " * (self.refidwidth - len(visible) - assocwidth + 1))
-            self.say("%-6d" % (associd))
-        else:
-            self.say(" " * (self.refidwidth - len(visible)))
-        # The rest of the story
-        last_sync = variables.get("rec") or variables.get("reftime")
-        jd = estjitter if have_jitter else estdisp
-        jd = "      -" if jd >= 999 else ("%7.3f" % jd)
-        self.say(
-            " %2ld %c %4.4s %4.4s  %3lo  %7.3f %8.3f %s\n" % \
-            (variables.get("stratum", 0),
-             ptype,
-             Ntpq.prettyinterval(now if last_sync is None else int(now - lfptofloat(last_sync))),
-             Ntpq.prettyinterval(poll_sec),
-             reach, estdelay, estoffset,
-             jd))
-        return True
-
-    def __dogetpeers(self, header, associd):
-        try:
-            variables = self.session.readvar(associd)
-        except Mode6Exception as e:
-            print(e.message)
-            return False
-        if not variables:
-            if len(self.chosts) > 1:
-                self.warn("server=%s ", self.session.hostname)
-            self.warn("***No information returned for association %d\n" \
-                             % associd)
-            return False;
-        return self.__doprintpeers(variables, header, associd);
-
-    def __dopeers(self, showall, header):
+    def __dopeers(self, showall, mode):
         if not self.__dogetassoc():
             return
+        report = PeerSummary(mode,
+                             self.pktversion,
+                             self.showhostnames,
+                             self.wideremote)
         maxhostlen = 0
         if len(self.chosts) > 1:
             maxhostlen = max([len(host) for (host, _af) in self.chosts])
             self.say("%-*.*s " % \
                              (maxhostlen, maxhostlen+1, "server"))
-        self.say(header)
-        self.say(("=" * (maxhostlen + 78 + self.horizontal_slack)) + "\n")
+        self.say(report.header() + "\n")
+        if len(self.chosts) > 1:
+            maxhostlen = max([len(host) for (host, _af) in self.chosts])
+            self.say("=" * (maxhostlen + 1))
+        self.say(("=" * report.width()) + "\n")
         for peer in self.peers:
             if not showall and \
 		    not (CTL_PEER_STATVAL(peer.status)
@@ -475,8 +290,21 @@ usage: help [ command ]
                 if self.debug:
                     self.warn(stderr, "eliding [%d]\n" % peer.associd)
                 continue
-            if not self.__dogetpeers(header, peer.associd):
+            try:
+                variables = self.session.readvar(peer.associd)
+            except Mode6Exception as e:
+                print(e.message)
                 return
+            if not variables:
+                if len(self.chosts) > 1:
+                    self.warn("server=%s ", self.session.hostname)
+                self.warn("***No information returned for association %d\n" \
+                                 % associd)
+                continue
+            if len(self.chosts) > 1:
+                self.say(PeerSummary.high_truncate(self.session.hostname, maxhostlen)+ " ")
+            self.say(report.summary(self.session.rstatus,
+                                    variables, peer.associd))
 
     def __assoc_valid(self, line, required=False):
         "Process a numeric associd or index."
@@ -1220,7 +1048,7 @@ usage: pstats assocID
 
     def do_peers(self, line):
         "obtain and print a list of the server's peers [IP version]"
-        self.__dopeers(showall=False, header=self.__peerheader)
+        self.__dopeers(showall=False, mode="peers")
 
     def help_peers(self):
         self.say("""\
@@ -1230,7 +1058,7 @@ usage: peers
 
     def do_apeers(self, line):
         "obtain and print a list of the server's peers and their assocIDs [IP version]"
-        self.__dopeers(showall=False, header=self.__apeerheader)
+        self.__dopeers(showall=False, mode="apeers")
 
     def help_apeers(self):
         self.say("""\
@@ -1240,7 +1068,7 @@ usage: apeers
 
     def do_lpeers(self, line):
         "obtain and print a list of all peers and clients [IP version]"
-        self.__dopeers(showall=True, header=self.__peerheader)
+        self.__dopeers(showall=True, mode="peers")
 
     def help_lpeers(self):
         self.say("""\
@@ -1250,7 +1078,7 @@ usage: lpeers
 
     def do_opeers(self, line):
         "print peer list the old way, with dstadr shown rather than refid [IP version]"
-        self.__dopeers(showall=False, header=self.__opeerheader)
+        self.__dopeers(showall=False, mode="opeers")
 
     def help_opeers(self):
         self.say("""\


=====================================
pylib/util.py
=====================================
--- a/pylib/util.py
+++ b/pylib/util.py
@@ -5,6 +5,10 @@ from __future__ import print_function
 import socket
 import sys
 import subprocess
+import time
+import ntp.ntpc
+
+from ntp.packet import *
 
 def canonicalize_dns(hostname):
     portsuffix = ""
@@ -42,4 +46,202 @@ def termsize():
     else:
         return (24, 80)
 
+class PeerSummary:
+    "Reusable report generator for peer statistics"
+    def __init__(self, displaymode, pktversion, showhostnames, wideremote):
+        self.displaymode = displaymode		# peers/apeers.opeers
+        self.pktversion = pktversion		# interpretation of flash bits
+        self.showhostnames = showhostnames	# If false, display numeric IPs
+        self.wideremote = wideremote		# show wide remote names?
+        # By default, the peer spreadsheet layout is designed so lines just
+        # fit in 80 characters. This tells us how much extra horizontal space
+        # we have available on a wider terminal emulator
+        self.horizontal_slack = termsize()[1] - 80
+        # Peer spreadsheet column widths
+        self.namewidth = 15 + self.horizontal_slack
+        self.refidwidth = 15
+        # Compute peer spreadsheet headers 
+        self.__remote = "     remote    ".ljust(self.namewidth)
+        self.__common = "st t when poll reach   delay   offset  "
+        self.__header = None
+
+    @staticmethod
+    def prettyinterval(diff):
+        "Print an interval in natural time units."
+        if diff <= 0:
+            return "-"
+        if diff <= 2048:
+            return str(diff)
+        diff = (diff + 29) / 60
+        if diff <= 300:
+            return "%dm" % diff
+        diff = (diff + 29) / 60
+        if diff <= 96:
+            return "%dh" % diff
+        diff = (diff + 11) / 24
+        return "%dd" % diff
+
+    @staticmethod
+    def high_truncate(hostname, maxlen):
+        "Truncate on the left using leading _ to indicate 'more'."
+        # Used for local IPv6 addresses, best distinguished by low bits
+        if len(hostname) <= maxlen:
+            return hostname
+        else:
+            return '-' + hostname[-maxlen+1:]
+
+    def header(self):
+        "Column headers for peer display"
+        if self.displaymode == "apeers":
+            self.__header = self.__remote + \
+                             "   refid   assid  ".ljust(self.refidwidth) + \
+                             self.__common + "jitter"
+        elif self.displaymode == "opeers":
+            self.__header = self.__remote + \
+                             "       local      ".ljust(self.refidwidth) + \
+                             self.__common + "  disp"
+        else:
+            self.__header  = self.__remote + \
+                             "       refid      ".ljust(self.refidwidth) + \
+                             self.__common + "jitter"
+        return self.__header
+
+    def width(self):
+        "Width of display"
+        return 78 + self.horizontal_slack
+
+    def summary(self, rstatus, variables, associd):
+        "Peer status summary line."
+        hmode = 0
+        srchost = None
+        srcport = 0
+        srcadr = None
+        dstadr_refid = ""
+        ppoll = 0
+        hpoll = 0
+        reach = 0
+        ptype = '?'
+        have_jitter = False
+        clock_name = ''
+
+        now = time.time()
+
+        for (name, value) in variables.items():
+            if name in ("srcadr", "peeradr"):
+                srcadr = value
+            elif name == "srchost":
+                srchost = value
+            elif name == "dstadr":
+                # The C code tried to get a fallback pytpe from this in case
+                # the hmode field was not included
+                if "local" in self.__header:
+                    dstadr_refid = value
+            elif name == "hmode":
+                hmode = value
+            elif name == "refid":
+                # The C code for this looked crazily overelaborate.  Best
+                # guess is that it was designed to deal with formats that
+                # no longer occur in this field.
+                if "refid" in self.__header:
+                    dstadr_refid = value
+            elif name == "hpoll":
+                hpoll = value
+                if hpoll < 0:
+                    hpoll = NTP_MINPOLL
+            elif name == "ppoll":
+                ppoll = value
+                if ppoll < 0:
+                    ppoll = NTP_MINPOLL
+            elif name == "reach":
+                # Shipped as hex, displayed in octal
+                reach = value
+            elif name == "delay":
+                estdelay = value
+            elif name == "offset":
+                estoffset = value
+            elif name == "jitter":
+                if "jitter" in self.__header:
+                    estjitter = value
+                    have_jitter = True
+            elif name == "rootdisp" or name == "dispersion":
+                estdisp = value
+            elif name == "rec":
+                rec = value	# l_fp timestamp
+            elif name == "srcport" or name == "peerport":
+                srcport = value
+            elif name == "reftime":
+                reftime = value	# l_fp timestamp
+        if hmode == MODE_BCLIENT:
+            # broadcastclient or multicastclient
+            ptype = 'b'
+        elif hmode == MODE_BROADCAST:
+            # broadcast or multicast server
+            if srcadr.startswith("224."):	# IANA multicast address prefix
+                ptype = 'M'
+            else:
+                ptype = 'B'
+        elif hmode == MODE_CLIENT:
+            if srchost and '(' in srchost:
+                ptype = 'l'	# local refclock
+            elif dstadr_refid == "POOL":
+                ptype = 'p'	# pool
+            elif srcadr.startswith("224."):
+                ptype = 'a'	# manycastclient
+            else:
+                ptype = 'u'	# unicast
+        elif hmode == MODE_ACTIVE:
+            ptype = 's'		# symmetric active
+        elif hmode == MODE_PASSIVE:
+            ptype = 'S'		# symmetric passive
+
+        #
+        # Got everything, format the line
+        #
+        line = ""
+        poll_sec = 1 << min(ppoll, hpoll)
+        if self.pktversion > NTP_OLDVERSION:
+            c = " x.-+#*o"[CTL_PEER_STATVAL(rstatus) & 0x7]
+        else:
+            c = " .+*"[CTL_PEER_STATVAL(rstatus) & 0x3]
+        # Source host or clockname
+        if srchost != None:
+            clock_name = srchost
+        elif self.showhostnames:
+            clock_name = canonicalize_dns(srcadr)
+        else:
+            clock_name = srcadr
+        if self.wideremote and len(clock_name) > self.namewidth:
+            line += ("%c%s\n" % (c, clock_name))
+            line + (" " * (self.namewidth + 2))
+        else:
+            line += ("%c%-*.*s " % \
+                             (c, self.namewidth, self.namewidth, clock_name[:self.namewidth]))
+        # Destination address, assoc ID or refid.
+        assocwidth = 7 if self.displaymode == "apeers" else 0
+        if "." not in dstadr_refid and ":" not in dstadr_refid:
+            dstadr_refid = "." + dstadr_refid + "."
+        if assocwidth and len(dstadr_refid) >= self.refidwidth - assocwidth:
+            visible = "..."
+        else:
+            visible = dstadr_refid
+        line += self.high_truncate(visible, self.refidwidth)
+        if self.displaymode == "apeers":
+            line += (" " * (self.refidwidth - len(visible) - assocwidth + 1))
+            line += ("%-6d" % (associd))
+        else:
+            line += (" " * (self.refidwidth - len(visible)))
+        # The rest of the story
+        last_sync = variables.get("rec") or variables.get("reftime")
+        jd = estjitter if have_jitter else estdisp
+        jd = "      -" if jd >= 999 else ("%7.3f" % jd)
+        line += (
+            " %2ld %c %4.4s %4.4s  %3lo  %7.3f %8.3f %s\n" % \
+            (variables.get("stratum", 0),
+             ptype,
+             PeerSummary.prettyinterval(now if last_sync is None else int(now - ntp.ntpc.lfptofloat(last_sync))),
+             PeerSummary.prettyinterval(poll_sec),
+             reach, estdelay, estoffset,
+             jd))
+        return line
+
 # end



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/44fa6c229ec38c6bdb33ae60418f071ab46f2764...5f0de4cdb4fc63a4b8be1ccb3436685aa63936c3
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ntpsec.org/pipermail/vc/attachments/20161027/cb6d439f/attachment.html>


More information about the vc mailing list