DISPATCH-1617 - Added some new rules that would prevent certain kinds of listeners and connectors to be added to the router config. This closes #722.
diff --git a/python/qpid_dispatch_internal/management/qdrouter.py b/python/qpid_dispatch_internal/management/qdrouter.py
index 616d903..09fefb3 100644
--- a/python/qpid_dispatch_internal/management/qdrouter.py
+++ b/python/qpid_dispatch_internal/management/qdrouter.py
@@ -56,16 +56,35 @@
entities = list(entities) # Iterate twice
super(QdSchema, self).validate_add(attributes, entities)
entities.append(attributes)
- inter_router = not_interior = None
+ router_mode = listener_connector_role = listener_role = None
for e in entities:
short_type = self.short_name(e['type'])
- if short_type == "router" and e['mode'] != "interior":
- not_interior = e['mode']
- if short_type in ["listener", "connector"] and e['role'] == "inter-router":
- inter_router = e
- if not_interior and inter_router:
- raise schema.ValidationError(
- "role='inter-router' only allowed with router mode='interior' for %s." % inter_router)
+ if short_type == "router":
+ router_mode = e['mode']
+ if short_type in ["listener", "connector"]:
+ if short_type == "listener":
+ listener_role = e['role']
+ list_conn_entity = e
+ listener_connector_role = e['role']
+
+ # There are 4 roles for listeners - normal, inter-router, route-container, edge
+ if router_mode and listener_connector_role:
+ # Standalone routers cannot have inter-router or edge listeners/connectors
+ if router_mode == "standalone" and (listener_connector_role == "inter-router" or listener_connector_role == "edge"):
+ raise schema.ValidationError(
+ "role='standalone' not allowed to connect to or accept connections from other routers.")
+
+ # Only interior routers can have inter-router listeners/connectors
+ if router_mode != "interior" and listener_connector_role == "inter-router":
+ raise schema.ValidationError(
+ "role='inter-router' only allowed with router mode='interior' for %s" % list_conn_entity)
+
+ if router_mode and listener_role:
+ # Edge routers cannot have edge listeners. Other edge routers cannot make connections into this
+ # edge router
+ if router_mode == "edge" and listener_role == "edge":
+ raise schema.ValidationError(
+ "role='edge' only allowed with router mode='interior' for %s" % list_conn_entity)
def is_configuration(self, entity_type):
return entity_type and self.configuration_entity in entity_type.all_bases
diff --git a/tests/system_tests_one_router.py b/tests/system_tests_one_router.py
index 1942b33..310cf52 100644
--- a/tests/system_tests_one_router.py
+++ b/tests/system_tests_one_router.py
@@ -31,7 +31,7 @@
from proton import VERSION as PROTON_VERSION
from proton import Terminus
from proton import Data
-from qpid_dispatch.management.client import Node
+from qpid_dispatch.management.client import Node, BadRequestStatus
import os, json
from subprocess import PIPE, STDOUT
from time import sleep
@@ -59,6 +59,266 @@
def on_timer_task(self, event):
self.parent.timeout ( self.name )
+class StandaloneRouterQdManageTest(TestCase):
+ @classmethod
+ def setUpClass(cls):
+ super(StandaloneRouterQdManageTest, cls).setUpClass()
+ name = "test-router"
+ config = Qdrouterd.Config([
+ ('router', {'mode': 'standalone', 'id': 'QDR'}),
+ ('listener', {'port': cls.tester.get_port(), 'role': 'normal', 'host': '0.0.0.0'})
+ ])
+ cls.router = cls.tester.qdrouterd(name, config, wait=True)
+
+ def test_49_add_interrouter_connector_to_standalone_router(self):
+ """
+ This test tries adding an inter-router connector to a stanalone router.
+ A standalone router can have a route container connector
+ but never an inter-router connector. Inter router connectors
+ are allowed only with interior routers.
+ """
+ mgmt = QdManager(self, address=self.router.addresses[0])
+ test_pass = False
+ try:
+ out = mgmt.create("org.apache.qpid.dispatch.connector",
+ {"host": "0.0.0.0",
+ "port": "77777",
+ "role":"inter-router"})
+ except Exception as e:
+ if "BadRequestStatus: role='standalone' not allowed to connect to or accept connections from other routers." in str(e):
+ test_pass = True
+
+ self.assertTrue(test_pass)
+
+ def test_50_add_edge_listener_to_standalone_router(self):
+ """
+ This test tries to add an edge listener to a standalone router.
+ Since this is a standalone router, other routers (interior or edge routers)
+ cannot connect to this router.
+ """
+ mgmt = QdManager(self, address=self.router.addresses[0])
+ test_pass = False
+ try:
+ out = mgmt.create("org.apache.qpid.dispatch.listener",
+ {"host": "0.0.0.0",
+ "port": "77777",
+ "role":"edge",
+ "authenticatePeer": "no"})
+ except Exception as e:
+ if "BadRequestStatus: role='standalone' not allowed to connect to or accept connections from other routers." in str(e):
+ test_pass = True
+
+ self.assertTrue(test_pass)
+
+
+ def test_51_add_interrouter_listener_to_standalone_router(self):
+ """
+ This test tries to add an inter-router listener to a standalone router.
+ Since this is a standalone router, other routers (interior or edge routers)
+ cannot connect to this router.
+ """
+ mgmt = QdManager(self, address=self.router.addresses[0])
+ test_pass = False
+ try:
+ out = mgmt.create("org.apache.qpid.dispatch.listener",
+ {"host": "0.0.0.0",
+ "port": "77777",
+ "role":"inter-router",
+ "authenticatePeer": "no"})
+ except Exception as e:
+ if "BadRequestStatus: role='standalone' not allowed to connect to or accept connections from other routers." in str(e):
+ test_pass = True
+
+ self.assertTrue(test_pass)
+
+class EdgeRouterQdManageTest(TestCase):
+ @classmethod
+ def setUpClass(cls):
+ super(EdgeRouterQdManageTest, cls).setUpClass()
+ name = "test-router"
+ config = Qdrouterd.Config([
+ ('router', {'mode': 'edge', 'id': 'QDR'}),
+ ('listener', {'port': cls.tester.get_port(), 'role': 'normal', 'host': '0.0.0.0'})
+ ])
+ cls.router = cls.tester.qdrouterd(name, config, wait=True)
+
+ def test_52_add_interrouter_connector_to_edge_router(self):
+ """
+ This test tries adding an inter-router connector to an edge router. An edge
+ router can have an edge connector or route container connector
+ but never an inter-router connector. Inter router connectors
+ are allowed only with interior routers.
+ """
+ mgmt = QdManager(self, address=self.router.addresses[0])
+ test_pass = False
+ try:
+ out = mgmt.create("org.apache.qpid.dispatch.connector",
+ {"host": "0.0.0.0",
+ "port": "77777",
+ "role":"inter-router"})
+ except Exception as e:
+ if "BadRequestStatus: role='inter-router' only allowed with router mode='interior'" in str(e):
+ test_pass = True
+
+ self.assertTrue(test_pass)
+
+ def test_53_add_edge_listener_to_edge_router(self):
+ """
+ This test tries to add an edge listener to an edge router which means
+ an edge router can connect to another edge router and that is not
+ allowed.
+ """
+ mgmt = QdManager(self, address=self.router.addresses[0])
+ test_pass = False
+ try:
+ out = mgmt.create("org.apache.qpid.dispatch.listener",
+ {"host": "0.0.0.0",
+ "port": "77777",
+ "role":"edge",
+ "authenticatePeer": "no"})
+ except Exception as e:
+ if "BadRequestStatus: role='edge' only allowed with router mode='interior'" in str(e):
+ test_pass = True
+
+ self.assertTrue(test_pass)
+
+ def test_54_add_interrouter_listener_to_edge_router(self):
+ """
+ This test tries to add an edge listener to an edge router which means
+ an edge router can connect to another edge router and that is not
+ allowed.
+ """
+ mgmt = QdManager(self, address=self.router.addresses[0])
+ test_pass = False
+ try:
+ out = mgmt.create("org.apache.qpid.dispatch.listener",
+ {"host": "0.0.0.0",
+ "port": "77777",
+ "role":"inter-router",
+ "authenticatePeer": "no"})
+ except Exception as e:
+ if "BadRequestStatus: role='inter-router' only allowed with router mode='interior'" in str(e):
+ test_pass = True
+
+ self.assertTrue(test_pass)
+
+class StandaloneEdgeRouterConfigTest(TestCase):
+ """
+ Try to start the router with bad config and make sure the router
+ does not start and scan the log files for appropriate error messages.
+ """
+ @classmethod
+ def setUpClass(cls):
+ super(StandaloneEdgeRouterConfigTest, cls).setUpClass()
+ name = "test-router"
+
+ # A standalone router cannot have an edge listener because it cannot accept edge connections.
+ config = Qdrouterd.Config([
+ ('router', {'mode': 'standalone', 'id': 'QDR'}),
+ ('listener', {'port': cls.tester.get_port(), 'role': 'edge', 'host': '0.0.0.0'})
+ ])
+ cls.router = cls.tester.qdrouterd(name, config, wait=False, perform_teardown=False)
+
+ # A standalone router cannot have inter-router connectors.
+ name = "test-router-1"
+ config_1 = Qdrouterd.Config([
+ ('router', {'mode': 'standalone', 'id': 'QDR'}),
+ ('connector', {'port': cls.tester.get_port(), 'role': 'inter-router', 'host': '0.0.0.0'})
+ ])
+ cls.router_1 = cls.tester.qdrouterd(name, config_1, wait=False, perform_teardown=False)
+
+ # An edge router cannot have edge listeners.
+ # Edge routers can have connectors that connect to interior routers
+ # or route-containers. One edge router cannot connect to another edge router.
+ name = "test-router-2"
+ config_2 = Qdrouterd.Config([
+ ('router', {'mode': 'edge', 'id': 'QDR'}),
+ ('listener', {'port': cls.tester.get_port(), 'role': 'edge', 'host': '0.0.0.0'})
+ ])
+ cls.router_2 = cls.tester.qdrouterd(name, config_2, wait=False, perform_teardown=False)
+
+ # Edge routers cannot have inter-router listeners. Only interior
+ # routers can have inter-router listeners.
+ name = "test-router-3"
+ config_3 = Qdrouterd.Config([
+ ('router', {'mode': 'edge', 'id': 'QDR'}),
+ ('listener', {'port': cls.tester.get_port(), 'role': 'inter-router', 'host': '0.0.0.0'})
+ ])
+ cls.router_3 = cls.tester.qdrouterd(name, config_3, wait=False, perform_teardown=False)
+
+ # Edge routers cannot have inter-router connectors
+ # Inter-router connectors are allowed only on interior routers.
+ name = "test-router-4"
+ config_4 = Qdrouterd.Config([
+ ('router', {'mode': 'edge', 'id': 'QDR'}),
+ ('connector', {'port': cls.tester.get_port(), 'role': 'inter-router', 'host': '0.0.0.0'})
+ ])
+ cls.router_4 = cls.tester.qdrouterd(name, config_4, wait=False, perform_teardown=False)
+
+ # A standalone router cannot have an inter-router listener because
+ # it cannot accept inter-router connections.
+ name = "test-router-5"
+ config_5 = Qdrouterd.Config([
+ ('router', {'mode': 'standalone', 'id': 'QDR'}),
+ ('listener', {'port': cls.tester.get_port(), 'role': 'inter-router', 'host': '0.0.0.0'})
+ ])
+ cls.router_5 = cls.tester.qdrouterd(name, config_5, wait=False, perform_teardown=False)
+
+ # Give some time for the test to write to the .out file. Without
+ # this sleep, the tests execute too
+ # fast and find that nothing has yet been written to the .out files.
+ sleep(3)
+
+
+ def test_48_router_in_error(self):
+ test_pass = False
+ with open(self.router.outfile + '.out', 'r') as out_file:
+ for line in out_file:
+ if "Exception: Cannot load configuration file test-router.conf: role='standalone' not allowed to connect to or accept connections from other routers." in line:
+ test_pass = True
+ break
+ self.assertTrue(test_pass)
+
+ test_pass = False
+ with open(self.router_1.outfile + '.out', 'r') as out_file:
+ for line in out_file:
+ if "Exception: Cannot load configuration file test-router-1.conf: role='standalone' not allowed to connect to or accept connections from other routers." in line:
+ test_pass = True
+ break
+ self.assertTrue(test_pass)
+
+ test_pass = False
+ with open(self.router_2.outfile + '.out', 'r') as out_file:
+ for line in out_file:
+ if "Exception: Cannot load configuration file test-router-2.conf: role='edge' only allowed with router mode='interior'" in line:
+ test_pass = True
+ break
+ self.assertTrue(test_pass)
+
+ test_pass = False
+ with open(self.router_3.outfile + '.out', 'r') as out_file:
+ for line in out_file:
+ if "Exception: Cannot load configuration file test-router-3.conf: role='inter-router' only allowed with router mode='interior'" in line:
+ test_pass = True
+ break
+ self.assertTrue(test_pass)
+
+ test_pass = False
+ with open(self.router_4.outfile + '.out', 'r') as out_file:
+ for line in out_file:
+ if "Exception: Cannot load configuration file test-router-4.conf: role='inter-router' only allowed with router mode='interior'" in line:
+ test_pass = True
+ break
+ self.assertTrue(test_pass)
+
+ test_pass = False
+ with open(self.router_5.outfile + '.out', 'r') as out_file:
+ for line in out_file:
+ if "Exception: Cannot load configuration file test-router-5.conf: role='standalone' not allowed to connect to or accept connections from other routers." in line:
+ test_pass = True
+ break
+ self.assertTrue(test_pass)
+
class OneRouterTest(TestCase):
"""System tests involving a single router"""