From 81e3af47821320a7fddf0408ee50cfd1384b149e Mon Sep 17 00:00:00 2001 From: Philip Jenvey Date: Fri, 27 Jan 2017 08:27:32 -0800 Subject: [PATCH] feat: switch proxy_protocol -> proxy_protocol_port (#789) now toggles exposing a separate port w/ proxy protocol handling fixes #788 --- autopush/main.py | 28 ++++++++------- autopush/tests/test_integration.py | 51 +++++++++++++++++----------- autopush/tests/test_main.py | 4 +-- configs/autopush_endpoint.ini.sample | 5 +-- 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/autopush/main.py b/autopush/main.py index 16f7d9c3..8a25dec6 100644 --- a/autopush/main.py +++ b/autopush/main.py @@ -162,6 +162,7 @@ def obsolete_args(parser): parser.add_argument('--max_message_size', type=int, help="OBSOLETE") parser.add_argument('--s3_bucket', help='OBSOLETE') parser.add_argument('--senderid_expry', help='OBSOLETE') + parser.add_argument('--proxy_protocol', help="OBSOLETE") # old APNs args parser.add_argument('--apns_enabled', help="OBSOLETE") parser.add_argument('--apns_sandbox', help="OBSOLETE") @@ -316,10 +317,11 @@ def _parse_endpoint(sysargs, use_files=True): parser.add_argument('--client_certs', help="Allowed TLS client certificates", type=str, env_var='CLIENT_CERTS', default="{}") - parser.add_argument('--proxy_protocol', - help="Enable HAProxy Proxy Protocol handling", - action="store_true", default=False, - env_var='PROXY_PROTOCOL') + parser.add_argument('--proxy_protocol_port', + help="Enable a secondary Endpoint Port with HAProxy " + "Proxy Protocol handling", + type=int, default=None, + env_var='PROXY_PROTOCOL_PORT') add_shared_args(parser) @@ -602,20 +604,22 @@ def endpoint_main(sysargs=None, use_files=True): settings.metrics.start() - # start the senderIDs refresh timer - if args.ssl_key: + def create_endpoint(port): + if not args.ssl_key: + return TCP4ServerEndpoint(reactor, port) ssl_cf = AutopushSSLContextFactory( args.ssl_key, args.ssl_cert, dh_file=args.ssl_dh_param, require_peer_certs=settings.enable_tls_auth) - endpoint = SSL4ServerEndpoint(reactor, args.port, ssl_cf) - else: - endpoint = TCP4ServerEndpoint(reactor, args.port) - if args.proxy_protocol: - from twisted.protocols.haproxy import proxyEndpoint - endpoint = proxyEndpoint(endpoint) + return SSL4ServerEndpoint(reactor, port, ssl_cf) + + endpoint = create_endpoint(args.port) endpoint.listen(site) + if args.proxy_protocol_port: + from twisted.protocols.haproxy import proxyEndpoint + pendpoint = proxyEndpoint(create_endpoint(args.proxy_protocol_port)) + pendpoint.listen(site) # Start the table rotation checker/updater l = task.LoopingCall(settings.update_rotating_tables) diff --git a/autopush/tests/test_integration.py b/autopush/tests/test_integration.py index 6f017ecb..f0a4366b 100644 --- a/autopush/tests/test_integration.py +++ b/autopush/tests/test_integration.py @@ -350,6 +350,7 @@ def wait_for(self, func): class IntegrationBase(unittest.TestCase): track_objects = True track_objects_excludes = [AutopushSettings, WebSocketServerFactory] + proxy_protocol_port = None def setUp(self): import cyclone.web @@ -441,18 +442,25 @@ def setUp(self): ) mount_health_handlers(site, settings) self._settings = settings - if is_https: - ep = SSL4ServerEndpoint( - reactor, - self.endpoint_port, - self.endpoint_SSLCF()) - else: - ep = TCP4ServerEndpoint(reactor, self.endpoint_port) - ep = self.wrap_endpoint(ep) + + self.endpoints = [] + ep = self._create_endpoint(self.endpoint_port, is_https) ep.listen(site).addCallback(self._endpoint_listening) + if self.proxy_protocol_port: + from twisted.protocols.haproxy import proxyEndpoint + ep = proxyEndpoint( + self._create_endpoint(self.proxy_protocol_port, is_https) + ) + ep.listen(site).addCallback(self._endpoint_listening) + + def _create_endpoint(self, port, is_https): + if not is_https: + return TCP4ServerEndpoint(reactor, port) + return SSL4ServerEndpoint(reactor, port, self.endpoint_SSLCF()) + def _endpoint_listening(self, port): - self.website = port + self.endpoints.append(port) def make_client_certs(self): return None @@ -460,14 +468,10 @@ def make_client_certs(self): def endpoint_SSLCF(self): raise NotImplementedError # pragma: nocover - def wrap_endpoint(self, ep): - return ep - @inlineCallbacks def tearDown(self): - dones = [self.websocket.stopListening(), self.website.stopListening(), - self.ws_website.stopListening()] - for d in filter(None, dones): + sites = [self.websocket, self.ws_website] + self.endpoints + for d in filter(None, (site.stopListening() for site in sites)): yield d # Dirty reactor unless we shut down the cached connections @@ -2005,10 +2009,7 @@ def test_registration(self): class TestProxyProtocol(IntegrationBase): - - def wrap_endpoint(self, ep): - from twisted.protocols.haproxy import proxyEndpoint - return proxyEndpoint(ep) + proxy_protocol_port = 9021 @inlineCallbacks def test_proxy_protocol(self): @@ -2018,13 +2019,23 @@ def test_proxy_protocol(self): # it in before the verb response, body = yield _agent( '{}GET'.format(proto_line), - "http://localhost:9020/v1/err", + "http://localhost:{}/v1/err".format(self.proxy_protocol_port), ) eq_(response.code, 418) payload = json.loads(body) eq_(payload['error'], "Test Error") ok_(self.logs.logged_ci(lambda ci: ci.get('remote_ip') == ip)) + @inlineCallbacks + def test_no_proxy_protocol(self): + response, body = yield _agent( + 'GET', + "http://localhost:{}/v1/err".format(self.endpoint_port), + ) + eq_(response.code, 418) + payload = json.loads(body) + eq_(payload['error'], "Test Error") + @inlineCallbacks def _agent(method, url, contextFactory=None, headers=None, body=None): diff --git a/autopush/tests/test_main.py b/autopush/tests/test_main.py index 8cc3a1da..1aae04b3 100644 --- a/autopush/tests/test_main.py +++ b/autopush/tests/test_main.py @@ -300,9 +300,9 @@ def test_client_certs(self): ], False) ok_(not returncode) - def test_proxy_protocol(self): + def test_proxy_protocol_port(self): endpoint_main([ - "--proxy_protocol", + "--proxy_protocol_port=8081", ], False) @patch('hyper.tls', spec=hyper.tls) diff --git a/configs/autopush_endpoint.ini.sample b/configs/autopush_endpoint.ini.sample index 61580f9f..ac5bf740 100644 --- a/configs/autopush_endpoint.ini.sample +++ b/configs/autopush_endpoint.ini.sample @@ -38,5 +38,6 @@ port = 8082 ; {"client1": ["2C:78:31.."], "client2": ["3F:D0:E0..", "E2:19:B1.."]} #client_certs = -; Enable HAProxy Proxy Protocol handling -#proxy_protocol +; Enable a secondary port to listen for notifications with HAProxy +; Proxy Protocol handling +#proxy_protocol_port = 8083