Skip to content

Commit 3afc87e

Browse files
committed
Split off random port selection into a separate callable.
- Allows selection of random ports within a certain range only as a first use case. - Closes: #102 via a different strategy. - Currently uses the traitlet Any, but should be Callable - but this is not in upstream traitlets, it is special to kubespawner. So leave Any for now and change later.
1 parent c91dc0b commit 3afc87e

File tree

4 files changed

+53
-3
lines changed

4 files changed

+53
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ clusters, as well as an option to run a local notebook directly on the jupyterhu
163163
* Pass the environment dictionary to the queue and cancel commands as well. This is mostly user environment, but may be useful to these commands as well in some cases. #108, #111
164164
* SlurmSpawner: add the `req_reservation` option. #
165165
* Improve debugging on failed submission by raising errors including error messages from the commands. #106
166+
* Allow selecting random ports via different logic, for example select a random port only within a certain range via: `c.BatchSpawner.random_port = batchspawner.utils.random_port_range(low, high)`.
166167
* Many other non-user or developer visible changes. #107 #106 #100
167168

168169
### v0.8.1 (bugfix release)

batchspawner/batchspawner.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
from jupyterhub.spawner import Spawner
3232
from traitlets import (
33-
Integer, Unicode, Float, Dict, default
33+
Integer, Unicode, Float, Dict, Any, default
3434
)
3535

3636
from jupyterhub.utils import random_port
@@ -164,6 +164,11 @@ def _req_keepvars_default(self):
164164
# Will get the address of the server as reported by job manager
165165
current_ip = Unicode()
166166

167+
# Random port function
168+
random_port = Any(random_port,
169+
help="Function to call to request a random port for singleuser spawer."
170+
).tag(config=True)
171+
167172
# Prepare substitution variables for templates using req_xyz traits
168173
def get_req_subvars(self):
169174
reqlist = [ t for t in self.trait_names() if t.startswith('req_') ]
@@ -348,7 +353,7 @@ def start(self):
348353
elif (jupyterhub.version_info < (0,7) and not self.user.server.port) or (
349354
jupyterhub.version_info >= (0,7) and not self.port
350355
):
351-
self.port = random_port()
356+
self.port = self.random_port()
352357
self.db.commit()
353358
job = yield self.submit_batch_script()
354359

batchspawner/tests/test_spawners.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ def run_command(self, cmd, input=None, env=None):
271271
# batch_poll_cmd
272272
status = io_loop.run_sync(spawner.poll, timeout=5)
273273
assert status == 1
274-
274+
return spawner
275275

276276

277277
def test_torque(db, io_loop):
@@ -475,3 +475,32 @@ def test_keepvars(db, io_loop):
475475
run_typical_slurm_spawner(db, io_loop,
476476
spawner_kwargs=spawner_kwargs,
477477
batch_script_re_list=batch_script_re_list)
478+
479+
480+
def test_random_port(db, io_loop):
481+
# Test single fixed port (probably don't ever use this!)
482+
spawner_kwargs = {
483+
'random_port': lambda: 12345,
484+
}
485+
spawner = run_typical_slurm_spawner(db, io_loop,
486+
spawner_kwargs=spawner_kwargs)
487+
assert spawner.port == 12345
488+
489+
# Random port range
490+
import batchspawner.utils as utils
491+
spawner_kwargs = {
492+
'random_port': utils.random_port_range(12300, 12301),
493+
}
494+
spawner = run_typical_slurm_spawner(db, io_loop,
495+
spawner_kwargs=spawner_kwargs)
496+
assert 12300 <= spawner.port and spawner.port <= 12301
497+
498+
# Arbitrary function
499+
def port_555():
500+
return 555
501+
spawner_kwargs = {
502+
'random_port': port_555,
503+
}
504+
spawner = run_typical_slurm_spawner(db, io_loop,
505+
spawner_kwargs=spawner_kwargs)
506+
assert spawner.port == 555

batchspawner/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Miscellaneous utilities
2+
3+
import random
4+
5+
def random_port_range(low, high):
6+
"""Factory function to select a random port number in the range [low,high].
7+
8+
Usage: c.BatchSpawner.random_port = random_port_range(low, high)
9+
"""
10+
# TODO: This does not prevent port number conflicts like
11+
# jupyterhub/utils.random_port tries to do. But we actually
12+
# can't, because we run on a different host, so
13+
# jupyterhub.utils.random_port actually doesn't work for us. #58
14+
# tries to do this better.
15+
return lambda: random.randint(low, high)

0 commit comments

Comments
 (0)