You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ch...@apache.org on 2020/07/17 14:52:00 UTC

[qpid-dispatch] branch master updated: DISPATCH-1505: Qdstat shows policy and vhost entities

This is an automated email from the ASF dual-hosted git repository.

chug pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/master by this push:
     new f5b98a1  DISPATCH-1505: Qdstat shows policy and vhost entities
f5b98a1 is described below

commit f5b98a1e41f3f08b80fba87fbc798e1bc72400dc
Author: Chuck Rolke <ch...@apache.org>
AuthorDate: Fri Jul 17 10:50:24 2020 -0400

    DISPATCH-1505: Qdstat shows policy and vhost entities
    
      -p --policy   - base policy settings and status
      --vhosts      - vhost configuration with no group data
      --vhostgroups - vhost group configuration
      --vhoststats  - per-vhost statistics, per-vhost/user connections info
    
    Policy is present even if it is not specified in the router config file.
    Vhosts are present only if enabled in base policy.
    
    The vhostgroups display is kind of ugly with superwide rows and
    does not lend itself to the tabular format.  Similar to --log, it
    is excluded from --all-entities and printed only on demand.
    
    This closes #774
---
 python/qpid_dispatch_internal/tools/command.py |  12 ++
 tests/system_tests_edge_router.py              |   2 +-
 tests/system_tests_qdstat.py                   |  93 +++++++++++-
 tests/test_command.py                          |   4 +
 tools/qdstat.in                                | 198 +++++++++++++++++++++++++
 5 files changed, 306 insertions(+), 3 deletions(-)

diff --git a/python/qpid_dispatch_internal/tools/command.py b/python/qpid_dispatch_internal/tools/command.py
index e9d39c8..2943fe9 100644
--- a/python/qpid_dispatch_internal/tools/command.py
+++ b/python/qpid_dispatch_internal/tools/command.py
@@ -150,12 +150,24 @@ def _qdstat_add_display_args(parser, BusManager):
     display.add_argument("-m", "--memory", action="store_const", dest="show",
                          help="Show Router Memory Stats",
                          const=BusManager.displayMemory.__name__)
+    display.add_argument("-p", "--policy", action="store_const", dest="show",
+                         help="Show Router Policy",
+                         const=BusManager.displayPolicy.__name__)
     display.add_argument("--autolinks", action="store_const", dest="show",
                          help="Show Auto Links",
                          const=BusManager.displayAutolinks.__name__)
     display.add_argument("--linkroutes", action="store_const", dest="show",
                          help="Show Link Routes",
                          const=BusManager.displayLinkRoutes.__name__)
+    display.add_argument("--vhosts", action="store_const", dest="show",
+                         help="Show Vhosts",
+                         const=BusManager.displayVhosts.__name__)
+    display.add_argument("--vhostgroups", action="store_const", dest="show",
+                         help="Show Vhost Groups",
+                         const=BusManager.displayVhostgroups.__name__)
+    display.add_argument("--vhoststats", action="store_const", dest="show",
+                         help="Show Vhost Stats",
+                         const=BusManager.displayVhoststats.__name__)
     display.add_argument("--log", action="store_const", dest="show",
                          help="Show recent log entries",
                          const=BusManager.displayLog.__name__)
diff --git a/tests/system_tests_edge_router.py b/tests/system_tests_edge_router.py
index 5d42586..653e02d 100644
--- a/tests/system_tests_edge_router.py
+++ b/tests/system_tests_edge_router.py
@@ -1303,7 +1303,7 @@ class RouterTest(TestCase):
                                address=self.routers[0].addresses[0])
         self.assertEqual(outs.count("Router Links"), 2)
         self.assertEqual(outs.count("Router Addresses"), 2)
-        self.assertEqual(outs.count("Connections"), 4)
+        self.assertEqual(outs.count("Connections"), 12)
         self.assertEqual(outs.count("AutoLinks"), 2)
         self.assertEqual(outs.count("Auto Links"), 2)
         self.assertEqual(outs.count("Link Routes"), 4)
diff --git a/tests/system_tests_qdstat.py b/tests/system_tests_qdstat.py
index 7d5ff3a..2213837 100644
--- a/tests/system_tests_qdstat.py
+++ b/tests/system_tests_qdstat.py
@@ -245,6 +245,16 @@ class QdstatTest(system_test.TestCase):
         regexp = r'qdr_address_t","[0-9]+'
         assert re.search(regexp, out, re.I), "Can't find '%s' in '%s'" % (regexp, out)
 
+    def test_policy(self):
+        out = self.run_qdstat(['--policy'])
+        self.assertTrue("Maximum Concurrent Connections" in out)
+        self.assertTrue("Total Denials" in out)
+
+    def test_policy_csv(self):
+        out = self.run_qdstat(['-p', "--csv"])
+        self.assertTrue("Maximum Concurrent Connections" in out)
+        self.assertTrue("Total Denials" in out)
+
     def test_log(self):
         self.run_qdstat(['--log',  '--limit=5'], r'AGENT \(debug\).*GET-LOG')
 
@@ -437,6 +447,85 @@ class QdstatTest(system_test.TestCase):
         c.close()
 
 
+class QdstatTestVhostPolicy(system_test.TestCase):
+    """Test qdstat-with-policy tool output"""
+    @classmethod
+    def setUpClass(cls):
+        super(QdstatTestVhostPolicy, cls).setUpClass()
+        config = system_test.Qdrouterd.Config([
+            ('router', {'id': 'QDR.A', 'workerThreads': 1}),
+            ('listener', {'port': cls.tester.get_port()}),
+            ('policy', {'maxConnections': 100, 'enableVhostPolicy': 'true'}),
+            ('vhost', {
+                'hostname': '$default',
+                'maxConnections': 2,
+                'allowUnknownUser': 'true',
+                'groups': {
+                    '$default': {
+                        'users': '*',
+                        'remoteHosts': '*',
+                        'sources': '*',
+                        'targets': '*',
+                        'allowDynamicSource': True
+                    }
+                }
+            })
+        ])
+        cls.router = cls.tester.qdrouterd('test-router', config)
+
+    def run_qdstat(self, args, regexp=None, address=None):
+        if args:
+            popen_args = ['qdstat', '--bus', str(address or self.router.addresses[0]), '--timeout', str(system_test.TIMEOUT) ] + args
+        else:
+            popen_args = ['qdstat', '--bus',
+                          str(address or self.router.addresses[0]),
+                          '--timeout', str(system_test.TIMEOUT)]
+
+        p = self.popen(popen_args,
+            name='qdstat-'+self.id(), stdout=PIPE, expect=None,
+            universal_newlines=True)
+
+        out = p.communicate()[0]
+        assert p.returncode == 0, \
+            "qdstat exit status %s, output:\n%s" % (p.returncode, out)
+        if regexp: assert re.search(regexp, out, re.I), "Can't find '%s' in '%s'" % (regexp, out)
+        return out
+
+    def test_vhost(self):
+        out = self.run_qdstat(['--vhosts'])
+        self.assertTrue("Vhosts" in out)
+        self.assertTrue("allowUnknownUser" in out)
+
+    def test_vhost_csv(self):
+        out = self.run_qdstat(['--vhosts', '--csv'])
+        self.assertTrue("Vhosts" in out)
+        self.assertTrue("allowUnknownUser" in out)
+
+    def test_vhostgroups(self):
+        out = self.run_qdstat(['--vhostgroups'])
+        self.assertTrue("Vhost Groups" in out)
+        self.assertTrue("allowAdminStatusUpdate" in out)
+
+    def test_vhostgroups_csv(self):
+        out = self.run_qdstat(['--vhostgroups', '--csv'])
+        self.assertTrue("Vhost Groups" in out)
+        self.assertTrue("allowAdminStatusUpdate" in out)
+
+    def test_vhoststats(self):
+        out = self.run_qdstat(['--vhoststats'])
+        self.assertTrue("Vhost Stats" in out)
+        self.assertTrue("maxMessageSizeDenied" in out)
+        self.assertTrue("Vhost User Stats" in out)
+        self.assertTrue("remote hosts" in out)
+
+    def test_vhoststats_csv(self):
+        out = self.run_qdstat(['--vhoststats', '--csv'])
+        self.assertTrue("Vhost Stats" in out)
+        self.assertTrue("maxMessageSizeDenied" in out)
+        self.assertTrue("Vhost User Stats" in out)
+        self.assertTrue("remote hosts" in out)
+
+
 
 
 class QdstatLinkPriorityTest(system_test.TestCase):
@@ -561,7 +650,7 @@ class QdstatLinkPriorityTest(system_test.TestCase):
         self.assertTrue(out.count('UTC') == 1)
         self.assertTrue(out.count('Router Links') == 1)
         self.assertTrue(out.count('Router Addresses') == 1)
-        self.assertTrue(out.count('Connections') == 2)
+        self.assertTrue(out.count('Connections') == 6)
         self.assertTrue(out.count('AutoLinks') == 2)
         self.assertTrue(out.count('Link Routes') == 3)
         self.assertTrue(out.count('Router Statistics') == 1)
@@ -579,7 +668,7 @@ class QdstatLinkPriorityTest(system_test.TestCase):
         self.assertTrue(out.count('UTC') == 1)
         self.assertTrue(out.count('Router Links') == 2)
         self.assertTrue(out.count('Router Addresses') == 2)
-        self.assertTrue(out.count('Connections') == 4)
+        self.assertTrue(out.count('Connections') == 12)
         self.assertTrue(out.count('AutoLinks') == 4)
         self.assertTrue(out.count('Link Routes') == 6)
         self.assertTrue(out.count('Router Statistics') == 2)
diff --git a/tests/test_command.py b/tests/test_command.py
index c364b01..9e7f3e3 100644
--- a/tests/test_command.py
+++ b/tests/test_command.py
@@ -45,6 +45,10 @@ class FakeBusManager:
     def displayEdges(self): pass
     def displayAddresses(self): pass
     def displayMemory(self): pass
+    def displayPolicy(self): pass
+    def displayVhosts(self): pass
+    def displayVhostgroups(self): pass
+    def displayVhoststats(self): pass
     def displayAutolinks(self): pass
     def displayLinkRoutes(self): pass
     def displayLog(self): pass
diff --git a/tools/qdstat.in b/tools/qdstat.in
index 32aeb4b..1423c3d 100755
--- a/tools/qdstat.in
+++ b/tools/qdstat.in
@@ -767,6 +767,195 @@ class BusManager(Node):
                              Header("Pooled", Header.KiMiGi)],
                             [rows])
 
+
+    def displayPolicy(self, show_date_id=True):
+        disp = Display(prefix="  ", bodyFormat=self.bodyFormat)
+        heads = []
+        heads.append(Header("attr"))
+        heads.append(Header("value"))
+        rows = []
+
+        objects = self.query('org.apache.qpid.dispatch.policy')
+
+        policy = objects[0]
+
+        if show_date_id:
+            self.display_datetime_router_id()
+
+        rows.append(('Maximum Concurrent Connections', PlainNum(policy.maxConnections)))
+        rows.append(('Maximum Message Size',           PlainNum(policy.maxMessageSize)))
+        rows.append(('Enable Vhost Policy',            policy.enableVhostPolicy))
+        rows.append(('Enable Vhost Name Patterns',     policy.enableVhostNamePatterns))
+        rows.append(('Policy Directory',               policy.policyDir if len(policy.policyDir) > 0 else '(nil)'))
+        rows.append(('Default Vhost',                  policy.defaultVhost if len(policy.defaultVhost) > 0 else '(nil)'))
+
+        disp.formattedTable("Policy Configuration", heads, rows)
+
+        heads = []
+        heads.append(Header("attr"))
+        heads.append(Header("value"))
+        rows = []
+
+        rows.append(('Connections Processed',       PlainNum(policy.connectionsProcessed)))
+        rows.append(('Connections Denied',          PlainNum(policy.connectionsDenied)))
+        rows.append(('Connections Current',         PlainNum(policy.connectionsCurrent)))
+        rows.append(('Links Denied',                PlainNum(policy.linksDenied)))
+        rows.append(('Maximum Message Size Denied', PlainNum(policy.maxMessageSizeDenied)))
+        rows.append(('Total Denials',               PlainNum(policy.totalDenials)))
+
+        disp.formattedTable("\nPolicy Status", heads, rows)
+
+    def showNodefaultString(self, dict, key):
+        return dict[key] if key in dict else "."
+
+    def showNodefaultInt(self, dict, key):
+        return PlainNum(dict[key]) if key in dict else "."
+
+    def displayVhosts(self, show_date_id=True):
+        disp = Display(prefix="  ", bodyFormat=self.bodyFormat)
+
+        vhosts = self.query('org.apache.qpid.dispatch.vhost')
+
+        if len(vhosts) == 0:
+            print("No Vhosts")
+            return
+        heads = []
+        heads.append(Header("hostname"))
+        heads.append(Header("maxConnections"))
+        heads.append(Header("maxMessageSize"))
+        heads.append(Header("maxConnectionsPerUser"))
+        heads.append(Header("maxConnectionsPerHost"))
+        heads.append(Header("allowUnknownUser"))
+        heads.append(Header("groups"))
+        rows = []
+        for vhost in vhosts:
+            rows.append((
+                vhost.hostname,
+                PlainNum(vhost.maxConnections),
+                PlainNum(vhost.maxMessageSize),
+                PlainNum(vhost.maxConnectionsPerUser),
+                PlainNum(vhost.maxConnectionsPerHost),
+                vhost.allowUnknownUser,
+                PlainNum(len(vhost.groups))
+                ))
+        disp.formattedTable("Vhosts", heads, rows)
+
+    def displayVhostgroups(self, show_date_id=True):
+        disp = Display(prefix="  ", bodyFormat=self.bodyFormat)
+
+        vhosts = self.query('org.apache.qpid.dispatch.vhost')
+
+        if len(vhosts) == 0:
+            print("No Vhosts")
+            return
+        heads = []
+        heads.append(Header("vhost"))
+        heads.append(Header("group"))
+        heads.append(Header("users"))
+        heads.append(Header("remoteHosts"))
+        heads.append(Header("maxConnectionsPerUser"))
+        heads.append(Header("maxConnectionsPerHost"))
+        heads.append(Header("maxMessageSize"))
+        heads.append(Header("maxFrameSize"))
+        heads.append(Header("maxSessionWindow"))
+        heads.append(Header("maxSessions"))
+        heads.append(Header("maxSenders"))
+        heads.append(Header("maxReceivers"))
+        heads.append(Header("allowDynamicSource"))
+        heads.append(Header("allowAnonymousSender"))
+        heads.append(Header("allowUserIdProxy"))
+        heads.append(Header("allowWaypointLinks"))
+        heads.append(Header("allowDynamicLinkRoutes"))
+        heads.append(Header("allowAdminStatusUpdate"))
+        heads.append(Header("allowFallbackLinks"))
+        heads.append(Header("sources"))
+        heads.append(Header("targets"))
+        heads.append(Header("sourcePattern"))
+        heads.append(Header("targetPattern"))
+        rows = []
+        for vhost in vhosts:
+            groups = vhost["groups"]
+            if len(groups) > 0:
+                for groupname in groups:
+                    group = groups[groupname]
+                    rows.append((
+                        vhost.hostname,
+                        groupname,
+                        self.showNodefaultString(group, "users"),
+                        self.showNodefaultString(group, "remoteHosts"),
+                        self.showNodefaultInt(group, "maxConnectionsPerUser"),
+                        self.showNodefaultInt(group, "maxConnectionsPerHost"),
+                        self.showNodefaultInt(group, "maxMessageSize"),
+                        self.showNodefaultInt(group, "maxFrameSize"),
+                        self.showNodefaultInt(group, "maxSessionWindow"),
+                        self.showNodefaultInt(group, "maxSessions"),
+                        self.showNodefaultInt(group, "maxSenders"),
+                        self.showNodefaultInt(group, "maxReceivers"),
+                        self.showNodefaultString(group, "allowDynamicSource"),
+                        self.showNodefaultString(group, "allowAnonymousSender"),
+                        self.showNodefaultString(group, "allowUserIdProxy"),
+                        self.showNodefaultString(group, "allowWaypointLinks"),
+                        self.showNodefaultString(group, "allowDynamicLinkRoutes"),
+                        self.showNodefaultString(group, "allowAdminStatusUpdate"),
+                        self.showNodefaultString(group, "allowFallbackLinks"),
+                        self.showNodefaultString(group, "sources"),
+                        self.showNodefaultString(group, "targets"),
+                        self.showNodefaultString(group, "sourcePattern"),
+                        self.showNodefaultString(group, "targetPattern")
+                    ))
+        disp.formattedTable("Vhost Groups", heads, rows)
+
+    def displayVhoststats(self, show_date_id=True):
+        disp = Display(prefix="  ", bodyFormat=self.bodyFormat)
+
+        vstats = self.query('org.apache.qpid.dispatch.vhostStats')
+
+        if len(vstats) == 0:
+            print("No Vhost Stats")
+            return
+        heads = []
+        heads.append(Header("hostname"))
+        heads.append(Header("connectionsApproved"))
+        heads.append(Header("connectionsDenied"))
+        heads.append(Header("connectionsCurrent"))
+        heads.append(Header("sessionDenied"))
+        heads.append(Header("senderDenied"))
+        heads.append(Header("receiverDenied"))
+        heads.append(Header("maxMessageSizeDenied"))
+        rows = []
+
+        for vstat in vstats:
+            rows.append((
+                vstat.hostname,
+                PlainNum(vstat.connectionsApproved),
+                PlainNum(vstat.connectionsDenied),
+                PlainNum(vstat.connectionsCurrent),
+                PlainNum(vstat.sessionDenied),
+                PlainNum(vstat.senderDenied),
+                PlainNum(vstat.receiverDenied),
+                PlainNum(vstat.maxMessageSizeDenied)
+                ))
+        disp.formattedTable("Vhost Stats", heads, rows)
+
+        heads = []
+        heads.append(Header("vhost"))
+        heads.append(Header("user"))
+        heads.append(Header("remote hosts"))
+        rows = []
+
+        for vstat in vstats:
+            ustates = vstat["perUserState"]
+            if len(ustates) > 0:
+                for ustate in ustates:
+                    rows.append((
+                        vstat.hostname,
+                        ustate,
+                        ustates[ustate]
+                        ))
+        disp.formattedTable("\nVhost User Stats", heads, rows)
+
+
+
     def displayLog(self):
         log = self.get_log(limit=self.opts.limit)
         for line in log:
@@ -793,6 +982,15 @@ class BusManager(Node):
         print("")
         self.displayMemory(show_date_id=False)
         print("")
+        self.displayPolicy(show_date_id=False)
+        print("")
+        self.displayVhosts(show_date_id=False)
+        print("")
+        # Groups is an ugly display. Show it only on demand.
+        # self.displayVhostgroups(show_date_id=False)
+        # print("")
+        self.displayVhoststats(show_date_id=False)
+        print("")
 
     def has_nodes(self):
         all_nodes = super(BusManager, self).get_mgmt_nodes()


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org