from neutron import context
from neutron.openstack.common import log as logging
from neutron.openstack.common import loopingcall
+from neutron.openstack.common import service
from neutron import wsgi
LOG = logging.getLogger(__name__)
server)
+class WorkerService(wsgi.WorkerService):
+ def start(self):
+ self._server = self._service.pool.spawn(self._service._run,
+ self._application,
+ self._service._socket)
+
+
class UnixDomainWSGIServer(wsgi.Server):
- def start(self, application, file_socket, backlog=128):
- sock = eventlet.listen(file_socket,
- family=socket.AF_UNIX,
- backlog=backlog)
- self.pool.spawn_n(self._run, application, sock)
+ def __init__(self, name):
+ self._socket = None
+ self._launcher = None
+ self._server = None
+ super(UnixDomainWSGIServer, self).__init__(name)
+
+ def start(self, application, file_socket, workers, backlog=128):
+ self._socket = eventlet.listen(file_socket,
+ family=socket.AF_UNIX,
+ backlog=backlog)
+ if workers < 1:
+ # For the case where only one process is required.
+ self._server = self.pool.spawn_n(self._run, application,
+ self._socket)
+ else:
+ # Minimize the cost of checking for child exit by extending the
+ # wait interval past the default of 0.01s.
+ self._launcher = service.ProcessLauncher(wait_interval=1.0)
+ self._server = WorkerService(self, application)
+ self._launcher.launch_service(self._server, workers=workers)
def _run(self, application, socket):
"""Start a WSGI service in a new green thread."""
OPTS = [
cfg.StrOpt('metadata_proxy_socket',
default='$state_path/metadata_proxy',
- help=_('Location for Metadata Proxy UNIX domain socket'))
+ help=_('Location for Metadata Proxy UNIX domain socket')),
+ cfg.IntOpt('metadata_workers',
+ default=0,
+ help=_('Number of separate worker processes for metadata '
+ 'server'))
]
def __init__(self, conf):
def run(self):
server = UnixDomainWSGIServer('neutron-metadata-agent')
server.start(MetadataProxyHandler(self.conf),
- self.conf.metadata_proxy_socket)
+ self.conf.metadata_proxy_socket,
+ workers=self.conf.metadata_workers)
server.wait()
def test_start(self):
mock_app = mock.Mock()
with mock.patch.object(self.server, 'pool') as pool:
- self.server.start(mock_app, '/the/path')
+ self.server.start(mock_app, '/the/path', workers=0)
self.eventlet.assert_has_calls([
mock.call.listen(
'/the/path',
self.eventlet.listen.return_value
)
+ @mock.patch('neutron.openstack.common.service.ProcessLauncher')
+ def test_start_multiple_workers(self, process_launcher):
+ launcher = process_launcher.return_value
+
+ mock_app = mock.Mock()
+ self.server.start(mock_app, '/the/path', workers=2)
+ launcher.running = True
+ launcher.launch_service.assert_called_once_with(self.server._server,
+ workers=2)
+
+ self.server.stop()
+ self.assertFalse(launcher.running)
+
+ self.server.wait()
+ launcher.wait.assert_called_once_with()
+
def test_run(self):
with mock.patch.object(agent, 'logging') as logging:
self.server._run('app', 'sock')
self.looping_mock = looping_call_p.start()
self.addCleanup(mock.patch.stopall)
self.cfg.CONF.metadata_proxy_socket = '/the/path'
+ self.cfg.CONF.metadata_workers = 0
def test_init_doesnot_exists(self):
with mock.patch('os.path.isdir') as isdir:
server.assert_has_calls([
mock.call('neutron-metadata-agent'),
mock.call().start(handler.return_value,
- '/the/path'),
+ '/the/path', workers=0),
mock.call().wait()]
)