Move create of ComputeAPI object in websocketproxy

Currently, we create a compute.rpcapi.ComputeAPI object during
NovaProxyRequestHandler.__init__ in order to make calls to nova-compute
for console token authorizations (port validation). This is problematic
in the event that we receive a TCP RST as it results in constructing a
ComputeAPI object only to throw it away and a large number of TCP RST
sent can cause excessive resource consumption.

This moves the creation of the ComputeAPI object from __init__ to being
lazily instantiated upon first use by access of a property, thus
avoiding creation of ComputeAPI objects when we receive TCP RST
messages.

Closes-Bug: #1816727

Change-Id: I3fe5540ea460fb32767b5e681295fdaf89ce17c5
This commit is contained in:
melanie witt 2019-03-20 19:01:33 +00:00
parent 926e584136
commit e4fa061f17
2 changed files with 20 additions and 4 deletions

View File

@ -304,12 +304,18 @@ class NovaProxyRequestHandlerBase(object):
class NovaProxyRequestHandler(NovaProxyRequestHandlerBase,
websockify.ProxyRequestHandler):
def __init__(self, *args, **kwargs):
# Order matters here. ProxyRequestHandler.__init__() will eventually
# call new_websocket_client() and we need self.compute_rpcapi set
# before then.
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
self._compute_rpcapi = None
websockify.ProxyRequestHandler.__init__(self, *args, **kwargs)
@property
def compute_rpcapi(self):
# Lazy load the rpcapi/ComputeAPI upon first use for this connection.
# This way, if we receive a TCP RST, we will not create a ComputeAPI
# object we won't use.
if not self._compute_rpcapi:
self._compute_rpcapi = compute_rpcapi.ComputeAPI()
return self._compute_rpcapi
def socket(self, *args, **kwargs):
return websockify.WebSocketServer.socket(*args, **kwargs)

View File

@ -706,6 +706,16 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
self.wh.socket.assert_called_with('node1', 10000, connect=True)
self.wh.do_proxy.assert_called_with('<socket>')
def test_tcp_rst_no_compute_rpcapi(self):
# Tests that we don't create a ComputeAPI object if we receive a
# TCP RST message. Simulate by raising the socket.err upon recv.
err = socket.error('[Errno 104] Connection reset by peer')
self.wh.socket.recv.side_effect = err
conn = mock.MagicMock()
address = mock.MagicMock()
self.wh.server.top_new_client(conn, address)
self.assertIsNone(self.wh._compute_rpcapi)
class NovaWebsocketSecurityProxyTestCase(test.NoDBTestCase):