Skip to content

Commit 7413a54

Browse files
committed
Port can be specified for servers
1 parent 9c9e4af commit 7413a54

File tree

3 files changed

+21
-4
lines changed

3 files changed

+21
-4
lines changed

docs/server-process.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ pairs.
8484
Defaults to *False*.
8585

8686

87+
#. **port**
88+
89+
Set the port that the service will listen on. The default is to
90+
automatically select an unused port.
91+
92+
8793
#. **launcher_entry**
8894

8995
A dictionary with options on if / how an entry in the classic Jupyter Notebook

jupyter_server_proxy/config.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from collections import namedtuple
1010
from .utils import call_with_asked_args
1111

12-
def _make_serverproxy_handler(name, command, environment, timeout, absolute_url):
12+
def _make_serverproxy_handler(name, command, environment, timeout, absolute_url, port):
1313
"""
1414
Create a SuperviseAndProxyHandler subclass with given parameters
1515
"""
@@ -20,6 +20,7 @@ def __init__(self, *args, **kwargs):
2020
self.name = name
2121
self.proxy_base = name
2222
self.absolute_url = absolute_url
23+
self.requested_port = port
2324

2425
@property
2526
def process_args(self):
@@ -80,6 +81,7 @@ def make_handlers(base_url, server_processes):
8081
sp.environment,
8182
sp.timeout,
8283
sp.absolute_url,
84+
sp.port,
8385
)
8486
handlers.append((
8587
ujoin(base_url, sp.name, r'(.*)'), handler, dict(state={}),
@@ -91,7 +93,7 @@ def make_handlers(base_url, server_processes):
9193

9294
LauncherEntry = namedtuple('LauncherEntry', ['enabled', 'icon_path', 'title'])
9395
ServerProcess = namedtuple('ServerProcess', [
94-
'name', 'command', 'environment', 'timeout', 'absolute_url', 'launcher_entry'])
96+
'name', 'command', 'environment', 'timeout', 'absolute_url', 'port', 'launcher_entry'])
9597

9698
def make_server_process(name, server_process_config):
9799
le = server_process_config.get('launcher_entry', {})
@@ -101,6 +103,7 @@ def make_server_process(name, server_process_config):
101103
environment=server_process_config.get('environment', {}),
102104
timeout=server_process_config.get('timeout', 5),
103105
absolute_url=server_process_config.get('absolute_url', False),
106+
port=server_process_config.get('port', 0),
104107
launcher_entry=LauncherEntry(
105108
enabled=le.get('enabled', True),
106109
icon_path=le.get('icon_path'),
@@ -138,6 +141,9 @@ class ServerProxy(Configurable):
138141
Proxy requests default to being rewritten to '/'. If this is True,
139142
the absolute URL will be sent to the backend instead.
140143
144+
port
145+
Set the port that the service will listen on. The default is to automatically select an unused port.
146+
141147
launcher_entry
142148
A dictionary of various options for entries in classic notebook / jupyterlab launchers.
143149

jupyter_server_proxy/handlers.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ def select_subprotocol(self, subprotocols):
284284
class SuperviseAndProxyHandler(LocalProxyHandler):
285285
'''Manage a given process and requests to it '''
286286

287+
def __init__(self, *args, **kwargs):
288+
self.requested_port = 0
289+
super().__init__(*args, **kwargs)
290+
287291
def initialize(self, state):
288292
self.state = state
289293
if 'proc_lock' not in state:
@@ -294,11 +298,12 @@ def initialize(self, state):
294298
@property
295299
def port(self):
296300
"""
297-
Allocate a random empty port for use by application
301+
Allocate either the requested port or a random empty port for use by
302+
application
298303
"""
299304
if 'port' not in self.state:
300305
sock = socket.socket()
301-
sock.bind(('', 0))
306+
sock.bind(('', self.requested_port))
302307
self.state['port'] = sock.getsockname()[1]
303308
sock.close()
304309
return self.state['port']

0 commit comments

Comments
 (0)