|
23 | 23 |
|
24 | 24 | import time
|
25 | 25 | from system_test import TestCase, main_module, Qdrouterd, unittest, retry
|
26 |
| -from system_test import CA_CERT, SSL_PROFILE_TYPE, CONNECTION_TYPE |
| 26 | +from system_test import CA_CERT, SSL_PROFILE_TYPE, CONNECTION_TYPE, ROUTER_LINK_TYPE |
27 | 27 | from system_test import CLIENT_CERTIFICATE, CLIENT_PRIVATE_KEY, CLIENT_PRIVATE_KEY_PASSWORD
|
28 | 28 | from system_test import SERVER_CERTIFICATE, SERVER_PRIVATE_KEY, SERVER_PRIVATE_KEY_PASSWORD
|
| 29 | +from tcp_streamer import TcpStreamerThread |
29 | 30 |
|
30 | 31 |
|
31 | 32 | class InterRouterCertRotationTest(TestCase):
|
@@ -56,6 +57,23 @@ def wait_inter_router_conns(self, router, count):
|
56 | 57 | len(self.get_inter_router_conns(rtr)) == ct)
|
57 | 58 | self.assertTrue(ok, f"Failed to get {count} i.r. conns: {self.get_inter_router_conns(router)}")
|
58 | 59 |
|
| 60 | + def get_inter_router_data_conns(self, router): |
| 61 | + dconns = self.get_inter_router_conns(router) |
| 62 | + return [c for c in dconns if c['role'] == 'inter-router-data'] |
| 63 | + |
| 64 | + def get_links_by_conn_id(self, router, conn_id): |
| 65 | + mgmt = router.management |
| 66 | + links = mgmt.query(type=ROUTER_LINK_TYPE).get_dicts() |
| 67 | + return [link for link in links if link['connectionId'] == conn_id] |
| 68 | + |
| 69 | + def get_streaming_data_links(self, router): |
| 70 | + ir_conns = self.get_inter_router_data_conns(router) |
| 71 | + links = [] |
| 72 | + for conn in ir_conns: |
| 73 | + links.extend([link for link in self.get_links_by_conn_id(router, conn['identity']) |
| 74 | + if link['linkType'] == 'endpoint']) |
| 75 | + return links |
| 76 | + |
59 | 77 | def test_01_ordinal_updates(self):
|
60 | 78 | """
|
61 | 79 | Verify that ordinal updates create new inter-router connections. Verify
|
@@ -194,6 +212,95 @@ def test_02_drop_old(self):
|
194 | 212 | router_L.teardown()
|
195 | 213 | router_C.teardown()
|
196 | 214 |
|
| 215 | + def test_03_tcp_streams(self): |
| 216 | + """ |
| 217 | + Verify that existing TCP streams are not interrupted when new |
| 218 | + inter-router connections are established. |
| 219 | + """ |
| 220 | + data_conn_count = 4 |
| 221 | + inter_router_port = self.tester.get_port() |
| 222 | + tcp_listener_port = self.tester.get_port() |
| 223 | + tcp_connector_port = self.tester.get_port() |
| 224 | + |
| 225 | + router_L = self.router("RouterL", |
| 226 | + [('sslProfile', {'name': 'ListenerSslProfile', |
| 227 | + 'caCertFile': CA_CERT, |
| 228 | + 'certFile': SERVER_CERTIFICATE, |
| 229 | + 'privateKeyFile': SERVER_PRIVATE_KEY, |
| 230 | + 'password': SERVER_PRIVATE_KEY_PASSWORD}), |
| 231 | + ('listener', {'name': 'Listener01', |
| 232 | + 'role': 'inter-router', |
| 233 | + 'host': '0.0.0.0', |
| 234 | + 'port': inter_router_port, |
| 235 | + 'requireSsl': 'yes', |
| 236 | + 'sslProfile': 'ListenerSslProfile'}), |
| 237 | + ('tcpListener', {'name': 'tcpListener01', |
| 238 | + 'address': 'tcp/streaming', |
| 239 | + 'port': tcp_listener_port})], |
| 240 | + data_conn_count, wait=False) |
| 241 | + router_C = self.router("RouterC", |
| 242 | + [('sslProfile', {'name': "ConnectorSslProfile", |
| 243 | + 'ordinal': 0, |
| 244 | + 'oldestValidOrdinal': 0, |
| 245 | + 'caCertFile': CA_CERT, |
| 246 | + 'certFile': CLIENT_CERTIFICATE, |
| 247 | + 'privateKeyFile': CLIENT_PRIVATE_KEY, |
| 248 | + 'password': CLIENT_PRIVATE_KEY_PASSWORD}), |
| 249 | + ('connector', {'role': 'inter-router', |
| 250 | + 'host': 'localhost', |
| 251 | + 'port': inter_router_port, |
| 252 | + 'verifyHostname': 'yes', |
| 253 | + 'sslProfile': 'ConnectorSslProfile'}), |
| 254 | + ('tcpConnector', {'name': 'tcpConnector01', |
| 255 | + 'address': 'tcp/streaming', |
| 256 | + 'host': 'localhost', |
| 257 | + 'port': tcp_connector_port})], |
| 258 | + data_conn_count, wait=True) |
| 259 | + router_C.wait_router_connected("RouterL") |
| 260 | + |
| 261 | + # wait for the inter-router connections to come up |
| 262 | + self.wait_inter_router_conns(router_C, data_conn_count + 1) |
| 263 | + |
| 264 | + # start TCP streaming connections across the routers |
| 265 | + tcp_streamer = TcpStreamerThread(client_addr=('localhost', tcp_listener_port), |
| 266 | + server_addr=('0.0.0.0', tcp_connector_port), |
| 267 | + client_count=10, poll_timeout=0.2) |
| 268 | + |
| 269 | + # Now wait until the streams have established (2 links per client) and |
| 270 | + # traffic is passing |
| 271 | + ok = retry(lambda rtr=router_C: |
| 272 | + len(self.get_streaming_data_links(rtr)) == 20) |
| 273 | + self.assertTrue(ok, f"Failed to get 20 links: {self.get_streaming_data_links(router_C)}") |
| 274 | + begin_recv = tcp_streamer.bytes_received |
| 275 | + ok = retry(lambda: tcp_streamer.bytes_received > begin_recv) |
| 276 | + self.assertTrue(ok, f"Failed to stream data {tcp_streamer.bytes_received}") |
| 277 | + |
| 278 | + # Now rotate the certs |
| 279 | + # update tlsOrdinal to 3 and wait for new conns to appear |
| 280 | + router_C.management.update(type=SSL_PROFILE_TYPE, |
| 281 | + attributes={'ordinal': 3}, |
| 282 | + name='ConnectorSslProfile') |
| 283 | + self.wait_inter_router_conns(router_C, 2 * (data_conn_count + 1)) |
| 284 | + |
| 285 | + # verify that the streamer is still running and the streams are still passing traffic |
| 286 | + begin_recv = tcp_streamer.bytes_received |
| 287 | + ok = retry(lambda: tcp_streamer.bytes_received > begin_recv) |
| 288 | + self.assertTrue(ok, f"Failed to stream data {tcp_streamer.bytes_received}") |
| 289 | + self.assertTrue(tcp_streamer.is_alive, "Streamer has failed!") |
| 290 | + |
| 291 | + # Update oldestValidOrdinal to 3. Expect the connections that carry the |
| 292 | + # streaming data to close |
| 293 | + router_C.management.update(type=SSL_PROFILE_TYPE, |
| 294 | + attributes={'oldestValidOrdinal': 3}, |
| 295 | + name='ConnectorSslProfile') |
| 296 | + self.wait_inter_router_conns(router_C, data_conn_count + 1) |
| 297 | + ok = retry(lambda: tcp_streamer.is_alive is False) |
| 298 | + self.assertTrue(ok, "Failed to terminate the streamer") |
| 299 | + |
| 300 | + router_L.teardown() |
| 301 | + router_C.teardown() |
| 302 | + tcp_streamer.join() |
| 303 | + |
197 | 304 |
|
198 | 305 | if __name__ == '__main__':
|
199 | 306 | unittest.main(main_module())
|
0 commit comments