229 Commits

Author SHA1 Message Date
pre-commit-ci[bot]
4973a55b47 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.21.0 → v3.21.2](https://github.com/asottile/pyupgrade/compare/v3.21.0...v3.21.2)
- [github.com/psf/black-pre-commit-mirror: 25.9.0 → 25.11.0](https://github.com/psf/black-pre-commit-mirror/compare/25.9.0...25.11.0)
2025-12-01 21:31:32 +00:00
Simon Li
1df02de795 Merge pull request #1050 from jasongrout/plausible
Add plausible stats tracking, consolidated with jupyter.org stats
2025-11-18 12:02:59 +00:00
pre-commit-ci[bot]
181aa975f5 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-11-17 19:01:13 +00:00
Jason Grout
243fcf7be0 Add plausible stats tracking, consolidated with jupyter.org stats
This PR is similar to https://github.com/jupyter/jupyter/pull/797
2025-11-17 11:59:37 -07:00
Min RK
8b55d5f5bc Merge pull request #1038 from zonca/update-jetstream-docs
Update jetstream docs
2025-11-04 11:42:37 -08:00
Min RK
c9d971b239 Merge pull request #1049 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2025-11-04 11:35:20 -08:00
pre-commit-ci[bot]
a047de1e79 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.20.0 → v3.21.0](https://github.com/asottile/pyupgrade/compare/v3.20.0...v3.21.0)
- [github.com/pycqa/isort: 6.1.0 → 7.0.0](https://github.com/pycqa/isort/compare/6.1.0...7.0.0)
2025-11-03 21:11:40 +00:00
Yuvi
96550b678a Merge pull request #1048 from teward/patch-1
Update systemd.md with clearer override instructions
2025-10-26 12:21:28 -07:00
pre-commit-ci[bot]
1bbbeacc06 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-10-19 04:38:21 +00:00
Thomas Ward
d906fe8c5d Update systemd.md with clearer override instructions
Clarify instructions for overriding traefik settings.

SystemD has inbuilt ways to *create* the override files without users having to create the files themselves.

To that end, just using `sudo systemctl edit [SERVICENAME].service` will work to create the service's override files.
2025-10-19 00:38:00 -04:00
Andrea Zonca
79adc7de2a add the last of @julianpistorious fixes 2025-10-15 13:12:28 -07:00
Min RK
27cf17d68c Merge pull request #1041 from jrdnbradford/fixme-req-url
Installer `FIXME`: Only warn on failed install from requirements url
2025-10-07 12:02:54 -07:00
Min RK
ca25444915 Merge pull request #1040 from jrdnbradford/testing-updates
Local integration testing updates
2025-10-07 12:02:06 -07:00
Min RK
5415cc471a Merge pull request #1045 from jrdnbradford/remove-tests
Remove deprecated tests due to image changes
2025-10-07 11:25:28 -07:00
Min RK
5891f0456b Merge pull request #1046 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2025-10-07 11:25:02 -07:00
Min RK
36efbc52f8 Merge pull request #1047 from jrdnbradford/pycurl-whl
Use `pycurl` `.whl` for hub environment
2025-10-07 11:24:50 -07:00
Jordan Bradford
dbcaf22ae0 Use pycurl .whl 2025-10-07 12:27:18 -04:00
pre-commit-ci[bot]
74b863ce22 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pycqa/isort: 6.0.1 → 6.1.0](https://github.com/pycqa/isort/compare/6.0.1...6.1.0)
- https://github.com/psf/blackhttps://github.com/psf/black-pre-commit-mirror
- [github.com/psf/black-pre-commit-mirror: 25.1.0 → 25.9.0](https://github.com/psf/black-pre-commit-mirror/compare/25.1.0...25.9.0)
2025-10-06 21:54:59 +00:00
Jordan Bradford
0b1da67264 Add curl for codecov-action 2025-10-05 20:28:10 -04:00
Jordan Bradford
9802473764 Remove old miniconda test 2025-10-05 20:14:40 -04:00
Jordan Bradford
9d8c66467c Remove 0.2.0 upgrade test 2025-10-05 20:14:09 -04:00
Erik Sundell
c9efb93278 Merge pull request #1042 from jupyterhub/dependabot/github_actions/actions/setup-python-6
Bump actions/setup-python from 5 to 6
2025-10-01 08:15:40 +02:00
dependabot[bot]
596984ccbd Bump actions/setup-python from 5 to 6
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-01 06:08:59 +00:00
Erik Sundell
a2e80cc89d Merge pull request #1043 from jupyterhub/dependabot/github_actions/actions/checkout-5
Bump actions/checkout from 4 to 5
2025-10-01 08:07:37 +02:00
dependabot[bot]
f49c59898a Bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-01 05:01:32 +00:00
Jordan Bradford
fb1e1063d2 Revert doc change 2025-09-30 23:01:03 -04:00
Jordan Bradford
939c2b37fd Fix mising link 2025-09-29 20:41:39 -04:00
Jordan Bradford
da5a5abafa Only warn on failed install from requirements url 2025-09-28 14:18:51 -04:00
Jordan Bradford
784e237831 Update test docs 2025-09-27 22:11:32 -04:00
Jordan Bradford
50a74417f6 Update run-test args 2025-09-27 22:07:47 -04:00
Andrea Zonca
72967f2b17 Document how to reveal exouser passphrase in Exosphere 2025-09-23 22:21:09 -07:00
Andrea Zonca
6b2d93aacf Apply suggestion from @julianpistorius
Co-authored-by: Julian Pistorius <github@soulsick.net>
2025-09-23 22:09:31 -07:00
pre-commit-ci[bot]
752f605c53 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-09-24 05:07:44 +00:00
Andrea Zonca
0cd259b6a1 Apply suggestion from @julianpistorius
Co-authored-by: Julian Pistorius <github@soulsick.net>
2025-09-23 22:07:42 -07:00
Andrea Zonca
684481fd5d Apply suggestion from @julianpistorius
Co-authored-by: Julian Pistorius <github@soulsick.net>
2025-09-23 22:07:32 -07:00
Andrea Zonca
c639c75637 Apply suggestion from @julianpistorius
Co-authored-by: Julian Pistorius <github@soulsick.net>
2025-09-23 22:07:20 -07:00
Andrea Zonca
45bec8e9f8 Apply suggestion from @julianpistorius
Co-authored-by: Julian Pistorius <github@soulsick.net>
2025-09-23 22:07:13 -07:00
Andrea Zonca
519415395f Apply suggestion from @julianpistorius
Co-authored-by: Julian Pistorius <github@soulsick.net>
2025-09-23 22:06:52 -07:00
pre-commit-ci[bot]
c3703985ee [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-09-24 05:05:30 +00:00
Andrea Zonca
e6851d946d Apply suggestions from code review
Co-authored-by: Julian Pistorius <github@soulsick.net>
2025-09-23 22:05:19 -07:00
Min RK
f13aef7568 Merge pull request #1011 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2025-09-04 14:13:54 -07:00
pre-commit-ci[bot]
354a8d47cc [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-09-01 20:46:41 +00:00
pre-commit-ci[bot]
4263e4c85e [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.17.0 → v3.20.0](https://github.com/asottile/pyupgrade/compare/v3.17.0...v3.20.0)
- [github.com/pycqa/isort: 5.13.2 → 6.0.1](https://github.com/pycqa/isort/compare/5.13.2...6.0.1)
- [github.com/psf/black: 24.8.0 → 25.1.0](https://github.com/psf/black/compare/24.8.0...25.1.0)
- [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v6.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.6.0...v6.0.0)
- [github.com/pycqa/flake8: 7.1.1 → 7.3.0](https://github.com/pycqa/flake8/compare/7.1.1...7.3.0)
2025-09-01 20:44:35 +00:00
pre-commit-ci[bot]
4807b7da89 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-08-27 00:18:19 +00:00
Andrea Zonca
ae503c3096 Clarify instructions for running the TLJH bootstrap script in the Jetstream installation guide 2025-08-26 17:17:58 -07:00
pre-commit-ci[bot]
512935abb7 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-08-27 00:14:45 +00:00
Andrea Zonca
a4858da978 Update Jetstream tutorial 2025-08-26 17:12:01 -07:00
Yuvi
134ddd9ef6 Merge pull request #1035 from paololazzari/patch-1
Fix default settings for culler instructions
2025-08-15 09:49:37 -07:00
Paolo
7e929fb78c Fix default settings for culler 2025-05-15 11:30:19 +02:00
Sarah Gibson
3eeb028f1f Merge pull request #1026 from jrdnbradford/schema-unittests
`tljh-config` JSON schema unit tests
2025-04-17 13:39:57 +01:00
Sarah Gibson
0384a46720 Merge pull request #1031 from GeorgianaElena/rm-old-ubuntu
Remove unit tests against Ubuntu 20.04 and Python 3.9
2025-04-17 12:50:30 +01:00
pre-commit-ci[bot]
142d22616c [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-04-16 17:30:33 +00:00
Jordan Bradford
5ff2c8aa6f Simplify testing of schema 2025-04-16 13:30:14 -04:00
Georgiana Dolocan
bba39bdfde Rm test with old Ubuntu and Python version 2025-04-16 20:05:37 +03:00
Sarah Gibson
c1134a5341 Merge pull request #1025 from jrdnbradford/integration-test-extensions
Fix `test_serverextensions` integration test
2025-04-16 17:51:36 +01:00
Sarah Gibson
989f772872 Merge pull request #1030 from jnywong/update-docs
Remove references to tls.domain config
2025-04-16 17:44:47 +01:00
Jordan Bradford
d5752b6c76 decode instead of capture_text 2025-04-15 13:15:24 -04:00
jnywong
dcdf2dc9b4 Remove references to tls.domain config 2025-04-15 15:51:27 +01:00
Jordan Bradford
251099caac Remove tls tests 2025-03-11 14:42:22 -04:00
Jordan Bradford
fa83068cdb Remove required properties for TLS 2025-03-11 14:38:26 -04:00
Jordan Bradford
3ee67e1581 Add test file for config validation 2025-03-11 14:13:28 -04:00
Jordan Bradford
a1f1c5e046 Remove FIXME 2025-03-11 14:12:40 -04:00
Jordan Bradford
8e318586c3 Make cert and key required for TLS 2025-03-11 14:12:09 -04:00
Jordan Bradford
a099bf647d Capture text output 2025-03-07 16:41:09 -05:00
Yuvi Panda
8cb42a9fc1 Merge pull request #1022 from manics/readme-ubuntu
Fix Ubuntu version in README
2025-02-18 10:38:31 -08:00
Simon Li
29dda40b33 Fix Ubuntu version in README 2025-02-14 16:24:30 +00:00
Min RK
4b066766d9 Merge pull request #1015 from yuvipanda/local-dev
Set development env vars in dev documentation correctly
2024-12-10 10:49:22 +01:00
Min RK
947eb028a9 Merge pull request #1016 from yuvipanda/classi
Link what 'jupyterlab' and 'classic' link to
2024-12-09 10:40:37 +01:00
YuviPanda
d695d29a6d Link what 'jupyterlab' and 'classic' link to 2024-12-08 19:31:41 -08:00
YuviPanda
53eceabd11 Set development env vars in dev documentation correctly
Without this, the current dev setup documentation does not
work.
2024-12-08 19:23:21 -08:00
Min RK
0f7d4f4748 Merge pull request #1014 from jupyterhub/dependabot/github_actions/codecov/codecov-action-5
Bump codecov/codecov-action from 4 to 5
2024-12-02 08:57:30 +01:00
dependabot[bot]
0907ca4ad4 Bump codecov/codecov-action from 4 to 5
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 05:16:04 +00:00
Min RK
3397e75dc5 Merge pull request #1013 from jrdnbradford/fix-cpu-schema
Fix `cpu` and `memory` config validation in JSON schema
2024-11-15 08:26:36 +01:00
Jordan Bradford
cd53b41b49 Also allow None for memory 2024-11-14 23:17:32 -05:00
Jordan Bradford
5916407a50 Update tljh/config_schema.py
Co-authored-by: Min RK <benjaminrk@gmail.com>
2024-11-14 23:14:17 -05:00
Jordan Bradford
e515bcad26 Fix None config test 2024-11-14 22:56:43 -05:00
Jordan Bradford
5a9cb2b395 Update tljh-config --help 2024-11-14 22:51:43 -05:00
Jordan Bradford
9ed2a92585 Parse None 2024-11-14 22:51:15 -05:00
Jordan Bradford
e7555ae29c Remove integer 2024-11-14 15:01:57 -05:00
Jordan Bradford
73331f28fd Use anyOf 2024-11-14 12:07:35 -05:00
Jordan Bradford
6531b6b7aa Update cpu types 2024-11-14 11:49:54 -05:00
Erik Sundell
c0563ab573 Bump to 2.0.1.dev 2024-10-21 10:26:00 +02:00
Erik Sundell
a47a171850 Bump to 2.0.0 2024-10-21 10:25:07 +02:00
Erik Sundell
04e2568fb3 Merge pull request #1010 from consideRatio/pr/cl200
Add changelog for 2.0.0
2024-10-21 10:24:18 +02:00
Erik Sundell
145d58f86e Add changelog for 2.0.0 2024-10-20 21:22:24 +02:00
Erik Sundell
3ebdbe1d83 Merge pull request #1009 from consideRatio/pr/betastate
Remove mention about beta state
2024-10-20 21:05:00 +02:00
Erik Sundell
f573525bf0 Remove mention about beta state 2024-10-20 21:01:28 +02:00
Erik Sundell
0370b57b32 Merge pull request #1008 from consideRatio/pr/unpin-jh
Update jupyterhub pinning to >=5.2.0,<6 from ==5.1.0
2024-10-20 15:49:33 +02:00
Erik Sundell
cbe577e596 Update systemdspawner pinning to >=1.0.2,<2 from >=1.0.1,<2 2024-10-20 14:53:50 +02:00
Erik Sundell
64790b4c95 Update jupyterhub pinning to >=5.2.0,<6 from ==5.1.0 2024-10-20 10:32:17 +02:00
Min RK
d2b0fd2c6c Merge pull request #1006 from consideRatio/pr/pycurl 2024-10-19 11:57:39 +02:00
Erik Sundell
e581232920 hub env: avoid installing pycurl using wheel with an issue 2024-10-18 23:10:01 +02:00
Erik Sundell
7514616e23 Merge pull request #1007 from consideRatio/pr/pin-jh
hub env: pin to jupyterhub 5.1.0
2024-10-18 23:07:47 +02:00
Erik Sundell
06d4670512 hub env: pin to jupyterhub 5.1.0 2024-10-18 22:51:31 +02:00
Erik Sundell
f4538ab06b Merge pull request #1004 from consideRatio/pr/lower-bound-user-env
hub env: bump to ldapauthenticator 2.0.0 and other lower bounds
2024-10-18 22:38:45 +02:00
Erik Sundell
bb17a1b980 hub env: bump to ldapauthenticator 2.0.0 and other lower bounds 2024-10-18 22:37:23 +02:00
Erik Sundell
8e68745e38 Bump to 2.0.0b1 2024-09-30 15:27:34 +02:00
Erik Sundell
a49f0a6889 Merge pull request #1000 from consideRatio/pr/changelog-2.0.0b1
Add changelog for 2.0.0b1
2024-09-30 15:25:48 +02:00
Min RK
bcfb426b5c Merge pull request #1003 from manics/upgrade-1 2024-09-29 08:26:31 +02:00
Simon Li
59fb7fb8a2 Test upgrade from 1.* 2024-09-28 15:38:32 +01:00
Erik Sundell
95b54414ca Add changelog for 2.0.0b1 2024-09-28 11:14:55 +02:00
Erik Sundell
eb5c0e4758 Merge pull request #1001 from consideRatio/pr/traefik-bump
Update traefik from 2.10.1 to 3.1.4
2024-09-28 10:59:38 +02:00
Erik Sundell
92e317d41f Merge pull request #1002 from consideRatio/pr/lower-bound-user-env
Bump the requirements-user-env-extras.txt lower version bounds
2024-09-28 10:59:00 +02:00
Erik Sundell
812be54635 Bump the requirements-user-env-extras.txt lower version bounds
By declaring these lower bounds, it becomes a bit easier to help others
using tljh, because we can know that fresh installations of tljh should
have at least these versions of software etc.
2024-09-28 10:49:03 +02:00
Erik Sundell
3ddc1e8d59 refactor: exctract calling traefik setup from ensure_jupyterhub_package func 2024-09-26 22:32:26 +02:00
Erik Sundell
a059d6ffbb Update traefik from 2.10.1 to 3.1.4 2024-09-26 16:29:51 +02:00
Erik Sundell
856c647e88 Merge pull request #999 from consideRatio/pr/bump-miniforge
Update to install miniforge 24.7.1-2 from 24.7.1-0
2024-09-26 13:42:04 +02:00
Erik Sundell
a89021c49e Update to install miniforge 24.7.1-2 from 24.7.1-0 2024-09-26 13:32:07 +02:00
Erik Sundell
a98299c629 Merge pull request #998 from consideRatio/pr/bump-drop
Drop ubuntu 20.04, require py39, traefik-proxy v2, and ldapauthenticator v2
2024-09-26 13:25:45 +02:00
Erik Sundell
e8602fc4a1 Update lower bounds on dependencies for tljh 2 beta release 2024-09-26 13:16:17 +02:00
Erik Sundell
0de2db365a pre-commit: run hooks 2024-09-20 22:25:46 +02:00
Erik Sundell
436c81f26d tljh package: require python 3.9+ 2024-09-20 22:25:46 +02:00
Erik Sundell
363dc45b52 tljh package: bump to traefik-proxy v2 2024-09-20 22:25:46 +02:00
Erik Sundell
1a9f3d65a4 tljh package: bump to ruamel.yaml==0.18.* 2024-09-20 22:25:46 +02:00
Erik Sundell
3f55ac2912 Drop support for ubuntu 20.04 and Python 3.8 2024-09-20 22:25:46 +02:00
Erik Sundell
92465ade36 Bump to 2.0.0.dev 2024-09-20 22:25:46 +02:00
Erik Sundell
2282e61894 Merge pull request #997 from consideRatio/main
ci: cache pip only when no container is used
2024-09-20 22:14:40 +02:00
Erik Sundell
94a16d6ddd ci: cache pip only when no container is used 2024-09-20 21:57:55 +02:00
Erik Sundell
7be7eb4968 Merge pull request #994 from minrk/consolidate_lock
consolidate lock file handling
2024-09-17 00:55:46 +02:00
Min RK
0c322774e2 filelock is a dependency of tljh 2024-09-05 12:03:26 +02:00
Min RK
13c8946d8c consolidate lock file handling
- adds config_file_lock context manager to re-use
- moves filelock import to module level
- fixes exit codes, stderr messages
2024-09-05 11:58:51 +02:00
Erik Sundell
f7118edf48 Merge pull request #993 from consideRatio/pr/unit-test-24.04
ci: run unit tests in ubuntu-24.04 github actions environment as well
2024-09-05 11:16:36 +02:00
Min RK
b034fc6713 fix calls to assert_called_with
it's not `assert ...called_with`
2024-09-05 11:07:22 +02:00
Erik Sundell
3321a50f31 ci: run unit tests in ubuntu-24.04 github actions environment as well 2024-09-04 16:16:31 +02:00
Erik Sundell
73f8833f0a Merge pull request #992 from minrk/oauth17
update oauthenticator to 17
2024-09-04 16:16:17 +02:00
Erik Sundell
5834f14b83 Merge pull request #942 from yuvipanda/conda-channels
Add the ability to define conda channels in plugins via `tljh_extra_user_conda_channels`
2024-09-04 16:14:10 +02:00
Erik Sundell
9111b73cee tests: reduce a test to only one package per conda channel 2024-09-04 16:04:29 +02:00
Min RK
3bd739e8dc update oauthenticator to 17
azuread no longer has its own dependencies
2024-09-04 13:25:10 +02:00
Erik Sundell
7a491e403c Merge branch 'main' into conda-channels 2024-09-04 13:16:58 +02:00
Erik Sundell
50c1b5f894 Merge pull request #990 from minrk/miniforge
Update base user environment to miniforge 24.7.1-0 (Python 3.12)
2024-09-04 13:08:17 +02:00
Min RK
5c8cb5bb26 Merge pull request #976 from jrdnbradford/add-conf-lockfile
Add TLJH config lockfile
2024-09-04 03:56:12 -07:00
Erik Sundell
8490ef2949 Update lower version bound on filelock, and add comment 2024-09-04 12:21:18 +02:00
Erik Sundell
5172ceb4f9 Update base user environment to miniforge 24.7.1-0 (Python 3.12) 2024-09-04 12:10:29 +02:00
Min RK
634956c33e Update base user environment to miniforge 24.5.0-0 (Python 3.12)
mambaforge is deprecated, mamba has been in miniforge for some time now
2024-08-27 10:54:07 +02:00
Simon Li
5278351eb1 Merge pull request #989 from minrk/hub5
jupyterhub 5
2024-08-25 15:09:36 +01:00
Simon Li
22e08a458b Merge pull request #988 from minrk/fix-launch
fix `-m` invocation of jupyterhub
2024-08-25 14:59:47 +01:00
Min RK
dcbb37688e doc adding users with github, since they won't be allowed by default 2024-08-23 11:40:07 +02:00
Min RK
c492c176bc allow all by default with default FirstUseAuthenticator
doesn't take effect if there's any auth config
2024-08-23 11:40:07 +02:00
Min RK
65c5d78ea5 jupyterhub 5
require 5.1.0 for security fixes
2024-08-23 10:02:58 +02:00
Min RK
5abf657bdf fix -m invocation of jupyterhub
-m jupyterhub.app results in multiple JupyterHub classes being defined
and jupyterhub.app.JupyterHub never being instantiated
2024-08-23 08:32:24 +02:00
Min RK
c49fada1c8 Merge pull request #985 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2024-08-06 08:59:46 +02:00
pre-commit-ci[bot]
708bbec2a4 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.16.0 → v3.17.0](https://github.com/asottile/pyupgrade/compare/v3.16.0...v3.17.0)
- [github.com/psf/black: 24.4.2 → 24.8.0](https://github.com/psf/black/compare/24.4.2...24.8.0)
- [github.com/pycqa/flake8: 7.1.0 → 7.1.1](https://github.com/pycqa/flake8/compare/7.1.0...7.1.1)
2024-08-05 23:07:01 +00:00
Min RK
729a3ceb28 Merge pull request #984 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2024-07-02 09:09:38 +02:00
pre-commit-ci[bot]
9c7427923d [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.15.2 → v3.16.0](https://github.com/asottile/pyupgrade/compare/v3.15.2...v3.16.0)
- [github.com/pycqa/flake8: 7.0.0 → 7.1.0](https://github.com/pycqa/flake8/compare/7.0.0...7.1.0)
2024-07-02 00:12:39 +00:00
Yuvi Panda
bcc64e0d8b Merge pull request #983 from josedaudi/patch-1
Added missing details on how to add custom domain from manual HTTPS  configuration
2024-06-10 19:13:05 -07:00
Joseph Daudi
a5f966927f Added missing details on how to add custom domain form manual HTTPS configuration 2024-05-23 21:49:15 +03:00
Erik Sundell
d0fb92eda5 Merge pull request #981 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2024-05-07 07:39:17 +02:00
pre-commit-ci[bot]
52478abb65 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 24.3.0 → 24.4.2](https://github.com/psf/black/compare/24.3.0...24.4.2)
- [github.com/pre-commit/pre-commit-hooks: v4.5.0 → v4.6.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.5.0...v4.6.0)
2024-05-06 22:03:37 +00:00
Jordan Bradford
96ac0d3538 Add filelock to dev-requirements 2024-04-06 11:03:24 -04:00
Jordan Bradford
13ed32b499 Add lockfile to integration tests 2024-04-06 10:51:51 -04:00
Jordan Bradford
bdbb3adbbc Add config lockfile 2024-04-06 10:49:07 -04:00
Erik Sundell
2b29bd9f0a Merge pull request #975 from consideRatio/pr/fix-tests
tests: fix to catch test failure earlier when they really happen
2024-04-04 22:53:32 +02:00
Erik Sundell
8fd41cc77a tests: strengthen tests to fail earlier on issues 2024-04-04 22:39:33 +02:00
Erik Sundell
7e39e993da Merge pull request #962 from jrdnbradford/validate-config-yaml
Validate tljh specific config
2024-04-04 07:45:42 +02:00
Jordan Bradford
5469e21e74 Fix removal of https.enabled 2024-04-03 16:19:45 -04:00
Jordan Bradford
38a01e8406 Use default true for validate 2024-04-03 16:09:18 -04:00
Jordan
9bcfa70326 Update tljh/config.py
Co-authored-by: Erik Sundell <erik.i.sundell@gmail.com>
2024-04-03 16:05:16 -04:00
Jordan Bradford
7474b876f1 Remove unneeded validate code 2024-04-03 16:04:29 -04:00
Jordan
5ae31ce169 Update tljh/config.py
Co-authored-by: Erik Sundell <erik.i.sundell@gmail.com>
2024-04-03 16:03:14 -04:00
Jordan
b94a281ff8 Update tljh/config.py
Co-authored-by: Erik Sundell <erik.i.sundell@gmail.com>
2024-04-03 16:03:05 -04:00
Jordan
67dd3c8abe Update tljh/config.py
Co-authored-by: Erik Sundell <erik.i.sundell@gmail.com>
2024-04-03 16:02:55 -04:00
Jordan Bradford
c578a7bec0 Update step name 2024-04-03 14:10:16 -04:00
Jordan Bradford
51f8470535 Fix unit tests with pip 2024-04-03 14:05:32 -04:00
Jordan Bradford
196208ae58 Remove argparse.BooleanOptionalAction for Python 3.8 compatibility 2024-04-03 13:30:32 -04:00
Erik Sundell
242dca4376 Merge pull request #973 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2024-04-02 09:54:01 +02:00
pre-commit-ci[bot]
5169301a0a [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.15.0 → v3.15.2](https://github.com/asottile/pyupgrade/compare/v3.15.0...v3.15.2)
- [github.com/PyCQA/autoflake: v2.2.1 → v2.3.1](https://github.com/PyCQA/autoflake/compare/v2.2.1...v2.3.1)
- [github.com/psf/black: 24.1.1 → 24.3.0](https://github.com/psf/black/compare/24.1.1...24.3.0)
2024-04-01 22:10:42 +00:00
Jordan Bradford
4ddd798928 Add docstring from config_schema.py 2024-03-27 12:08:28 -04:00
Jordan Bradford
f921acc183 Bump ubuntu image to 22.04 2024-03-20 15:09:07 -04:00
Jordan Bradford
46e4045568 Update test_proxy tests 2024-03-20 15:08:21 -04:00
Jordan Bradford
743f729902 Update set_config_value tests 2024-03-20 14:45:36 -04:00
Jordan Bradford
48fe440372 Add --[no-]validation flag for tljh-config 2024-03-20 14:36:49 -04:00
Min RK
8348d4ad96 Merge pull request #968 from consideRatio/pr/fix-tests
Re-install conda/mamba for every tljh upgrade (doesn't imply upgrade)
2024-03-18 09:26:46 +01:00
Erik Sundell
579b7eb5ba Merge pull request #969 from davidalber/fix-install-typo
Fix typo and replace word
2024-03-09 19:38:05 +01:00
Erik Sundell
0248785aed Merge pull request #970 from davidalber/reword-sg-sentence
Reword documentation sentence
2024-03-09 19:37:18 +01:00
David Alber
beed70060c Reword sentence 2024-03-01 12:09:17 -08:00
David Alber
d9a0a5fc7a Fix typo and replace word: "disitnguishing" --> "distinctive"
The typo is of "distinguishing", but "distinctive" makes more sense
to me in the context of the sentence it is in.
2024-03-01 11:50:47 -08:00
Erik Sundell
4e397bc687 Re-install conda/mamba for every tljh upgrade (doesn't imply upgrade) 2024-02-26 16:44:12 +01:00
Erik Sundell
7d8a84860f tests: show mamba list for the user environment before/after upgrade
This can help us check if a package has been installed from PyPI via
pip, or from conda-forge or other channel via conda/mamba.
2024-02-26 16:44:12 +01:00
Erik Sundell
2fe9912333 tests: test pip install plugin with no-dependency package
This is a simplification to help ensure we don't run into issues like
below because requests gets installed via pip.

```
RemoveError: 'requests' is a dependency of conda and cannot be removed from conda's operating environment.
```
2024-02-26 16:44:12 +01:00
Erik Sundell
02c3d7539b Merge pull request #967 from consideRatio/pr/ci-add-tests
ci: add tests for debian 12 and ubuntu 24.04
2024-02-26 16:43:57 +01:00
Erik Sundell
10ba571bde ci: add test for ubuntu 24.04 2024-02-26 16:24:29 +01:00
Erik Sundell
7fa4e2bcec ci: add test for debian 12 2024-02-24 21:47:36 +01:00
Erik Sundell
2faf0d3a5f Merge pull request #963 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2024-02-06 08:26:09 +01:00
pre-commit-ci[bot]
b35851f2b7 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2024-02-05 20:29:33 +00:00
pre-commit-ci[bot]
9755938d7d [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 23.12.1 → 24.1.1](https://github.com/psf/black/compare/23.12.1...24.1.1)
- [github.com/pycqa/flake8: 6.1.0 → 7.0.0](https://github.com/pycqa/flake8/compare/6.1.0...7.0.0)
2024-02-05 20:27:06 +00:00
Jordan Bradford
1f7d6d1c55 Add doc string for validate_config 2024-02-05 14:52:31 -05:00
Jordan Bradford
9060267458 Add LetsEncrypt.staging; run pre-commit 2024-02-03 13:39:17 -05:00
Jordan Bradford
4912cffe65 Fix parse_value 2024-02-03 13:27:58 -05:00
Jordan Bradford
d0c9aa263a Remove TLS required properties 2024-02-03 13:18:39 -05:00
Jordan Bradford
fa363658df Update schema based on values in configurer.py 2024-02-03 13:08:27 -05:00
Jordan Bradford
166eba6735 Switch from JSON to py 2024-02-03 12:48:31 -05:00
Jordan Bradford
5a0de137d2 Do not allow additionalProperties for Users 2024-02-02 23:22:57 -05:00
Jordan Bradford
929536de7b Run pre-commit hooks 2024-02-02 23:07:38 -05:00
Jordan Bradford
ef5c6c56b7 print human readable error message 2024-02-02 23:06:31 -05:00
Jordan Bradford
fb01dea5e4 Working schema path 2024-02-02 23:01:36 -05:00
Jordan Bradford
78d4b7fbc4 Test config setup 2024-02-02 22:52:16 -05:00
Jordan Bradford
d292457803 Initial config setup 2024-02-02 21:51:23 -05:00
Erik Sundell
6dd2ee812a Merge pull request #961 from jupyterhub/dependabot/github_actions/actions/cache-4
build(deps): bump actions/cache from 3 to 4
2024-02-01 10:57:26 +01:00
Erik Sundell
641a02ed07 Merge pull request #960 from jupyterhub/dependabot/github_actions/codecov/codecov-action-4
build(deps): bump codecov/codecov-action from 3 to 4
2024-02-01 10:25:36 +01:00
dependabot[bot]
1c9301e4d7 build(deps): bump actions/cache from 3 to 4
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 05:26:48 +00:00
dependabot[bot]
723c4e756d build(deps): bump codecov/codecov-action from 3 to 4
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 05:26:45 +00:00
Erik Sundell
eeae5f06be Merge pull request #959 from consideRatio/pr/add-azure-ad-dependency
Add missing oauthenticator dependency for AzureADOAuthenticator
2024-01-25 07:05:32 +01:00
Erik Sundell
4abf3f003f Add optional oauthenticator dependency for AzureAD 2024-01-04 02:28:28 +01:00
Erik Sundell
3da9743640 Merge pull request #956 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2024-01-04 01:06:36 +01:00
Erik Sundell
aec331b114 Merge pull request #958 from jupyterhub/dependabot/github_actions/actions/setup-python-5
build(deps): bump actions/setup-python from 4 to 5
2024-01-04 00:51:38 +01:00
pre-commit-ci[bot]
0f5a0ccbe0 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pycqa/isort: 5.12.0 → 5.13.2](https://github.com/pycqa/isort/compare/5.12.0...5.13.2)
- [github.com/psf/black: 23.10.1 → 23.12.1](https://github.com/psf/black/compare/23.10.1...23.12.1)
- [github.com/pre-commit/mirrors-prettier: v3.0.3 → v4.0.0-alpha.8](https://github.com/pre-commit/mirrors-prettier/compare/v3.0.3...v4.0.0-alpha.8)
2024-01-01 20:22:48 +00:00
dependabot[bot]
f1c7e2d90f build(deps): bump actions/setup-python from 4 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 05:51:55 +00:00
Min RK
5cb6b69020 Merge pull request #949 from pdebuyl/patch-1
Fix URL syntax in nativeauth.md
2023-11-22 14:25:22 +01:00
Min RK
7faf997c7b Merge pull request #953 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2023-11-07 10:03:44 +01:00
pre-commit-ci[bot]
79134e3a2f [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.14.0 → v3.15.0](https://github.com/asottile/pyupgrade/compare/v3.14.0...v3.15.0)
- [github.com/psf/black: 23.9.1 → 23.10.1](https://github.com/psf/black/compare/23.9.1...23.10.1)
- [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0)
2023-11-06 20:28:01 +00:00
Pierre de Buyl
e869633871 Fix URL syntax in nativeauth.md 2023-10-27 11:56:22 +02:00
Erik Sundell
793f6237b4 Merge pull request #945 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2023-10-03 12:42:12 +02:00
pre-commit-ci[bot]
caab46e08a [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.10.1 → v3.14.0](https://github.com/asottile/pyupgrade/compare/v3.10.1...v3.14.0)
- [github.com/psf/black: 23.7.0 → 23.9.1](https://github.com/psf/black/compare/23.7.0...23.9.1)
2023-10-03 10:35:43 +00:00
Erik Sundell
dcb91d4e6a Merge pull request #943 from jupyterhub/dependabot/github_actions/actions/checkout-4
build(deps): bump actions/checkout from 3 to 4
2023-10-01 10:12:17 +02:00
dependabot[bot]
ed6ff645c2 build(deps): bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 05:45:52 +00:00
YuviPanda
291c096a17 Fix argument name of channels 2023-09-29 14:47:53 -07:00
pre-commit-ci[bot]
eafc10e82a [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-09-29 21:39:30 +00:00
YuviPanda
58a679f584 Fix how channels are added to -c command 2023-09-29 14:39:12 -07:00
pre-commit-ci[bot]
9bde7e4680 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-09-29 21:35:50 +00:00
YuviPanda
6359bf498c Merge remote-tracking branch 'upstream/main' into conda-channels 2023-09-29 14:27:25 -07:00
Yuvi Panda
44bdaf2fa4 Merge pull request #939 from jupyterhub/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2023-09-29 14:19:34 -07:00
pre-commit-ci[bot]
1d1aefd518 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/autoflake: v2.2.0 → v2.2.1](https://github.com/PyCQA/autoflake/compare/v2.2.0...v2.2.1)
- [github.com/pre-commit/mirrors-prettier: v3.0.0 → v3.0.3](https://github.com/pre-commit/mirrors-prettier/compare/v3.0.0...v3.0.3)
2023-09-05 08:11:29 +00:00
Min RK
542cf4de6b Merge pull request #935 from schwebke/main
adapt install documentation for new /lab default interface
2023-08-14 11:32:15 +02:00
Kai G. Schwebke
46b49c819c adapt install documentation for new /lab default interface 2023-08-12 08:47:23 +02:00
Erik Sundell
c7507fd799 Bump to 1.0.1.dev 2023-08-11 14:46:52 +02:00
Will Dampier
ff1f612d10 adding content to docs 2022-09-02 14:47:41 -04:00
Will Dampier
58181c9671 adjusted integration test to call new hook 2022-09-02 14:47:25 -04:00
Will Dampier
8d1033393c adding tljh_extra_user_conda_channels hook to the hooks and installer 2022-09-02 14:46:55 -04:00
Will Dampier
fc8f70463c Adding the ability to define conda channels 2022-09-02 14:10:43 -04:00
64 changed files with 792 additions and 406 deletions

View File

@@ -10,7 +10,7 @@ GIT_REPO_PATH = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
TEST_IMAGE_NAME = "test-systemd" TEST_IMAGE_NAME = "test-systemd"
@functools.lru_cache() @functools.lru_cache
def _get_container_runtime_cli(): def _get_container_runtime_cli():
runtimes = ["docker", "podman"] runtimes = ["docker", "podman"]
for runtime in runtimes: for runtime in runtimes:
@@ -167,15 +167,23 @@ def run_test(
command = f"python3 /srv/src/bootstrap/bootstrap.py --version={upgrade_from}" command = f"python3 /srv/src/bootstrap/bootstrap.py --version={upgrade_from}"
run_command(container_name, command) run_command(container_name, command)
# show user environment
command = "/opt/tljh/user/bin/mamba list"
run_command(container_name, command)
command = f"python3 /srv/src/bootstrap/bootstrap.py {' '.join(installer_args)}" command = f"python3 /srv/src/bootstrap/bootstrap.py {' '.join(installer_args)}"
run_command(container_name, command) run_command(container_name, command)
# show user environment (again if upgrade)
command = "/opt/tljh/user/bin/mamba list"
run_command(container_name, command)
# Install pkgs from requirements in hub's pip, where # Install pkgs from requirements in hub's pip, where
# the bootstrap script installed the others # the bootstrap script installed the others
command = "/opt/tljh/hub/bin/python3 -m pip install -r /srv/src/integration-tests/requirements.txt" command = "/opt/tljh/hub/bin/python3 -m pip install -r /srv/src/integration-tests/requirements.txt"
run_command(container_name, command) run_command(container_name, command)
# show environment # show hub environment
command = "/opt/tljh/hub/bin/python3 -m pip freeze" command = "/opt/tljh/hub/bin/python3 -m pip freeze"
run_command(container_name, command) run_command(container_name, command)
@@ -218,12 +226,35 @@ def main():
copy_parser.add_argument("src") copy_parser.add_argument("src")
copy_parser.add_argument("dest") copy_parser.add_argument("dest")
run_test_parser = subparsers.add_parser("run-test") run_test_parser = subparsers.add_parser(
run_test_parser.add_argument("--installer-args", action="append") "run-test",
run_test_parser.add_argument("--upgrade-from", default="") help="Runs the bootstrap script in a container, then executes specified integration tests.",
run_test_parser.add_argument("--bootstrap-pip-spec", default="/srv/src") )
run_test_parser.add_argument("container_name") run_test_parser.add_argument(
run_test_parser.add_argument("test_files", nargs="+") "--installer-args",
action="append",
default=[],
help="Additional arguments to pass to bootstrap.py during the main installation. Can be used multiple times.",
)
run_test_parser.add_argument(
"--upgrade-from",
default="",
help="A version/tag (e.g., 'main', 'v0.1.0') to install first, simulating an upgrade to the current source code.",
)
run_test_parser.add_argument(
"--bootstrap-pip-spec",
default="/srv/src",
help="The pip specification used by the bootstrap script to install TLJH (for example: '--bootstrap-pip-spec=git+https://github.com/your-username/the-littlest-jupyterhub.git@branch-name'). Defaults to the local source code path.",
)
run_test_parser.add_argument(
"container_name",
help="An identifier for the container/test run (for example: 'basic-tests').",
)
run_test_parser.add_argument(
"test_files",
nargs="+",
help="A list of one or more test files under 'integration-tests/' to be executed.",
)
show_logs_parser = subparsers.add_parser("show-logs") show_logs_parser = subparsers.add_parser("show-logs")
show_logs_parser.add_argument("container_name") show_logs_parser.add_argument("container_name")

View File

@@ -36,25 +36,28 @@ jobs:
- name: "Debian 11, Py 3.9" - name: "Debian 11, Py 3.9"
distro_image: "debian:11" distro_image: "debian:11"
extra_flags: "" extra_flags: ""
- name: "Ubuntu 20.04, Py 3.8" - name: "Debian 12, Py 3.11"
distro_image: "ubuntu:20.04" distro_image: "debian:12"
extra_flags: "" extra_flags: ""
- name: "Ubuntu 22.04 Py 3.10" - name: "Ubuntu 22.04 Py 3.10"
distro_image: "ubuntu:22.04" distro_image: "ubuntu:22.04"
extra_flags: "" extra_flags: ""
- name: "Ubuntu 24.04 Py 3.12"
distro_image: "ubuntu:24.04"
extra_flags: ""
- name: "Ubuntu 22.04, Py 3.10, from main" - name: "Ubuntu 22.04, Py 3.10, from main"
distro_image: "ubuntu:22.04" distro_image: "ubuntu:22.04"
extra_flags: --upgrade-from=main extra_flags: --upgrade-from=main
- name: "Ubuntu 22.04, Py 3.10, from latest" - name: "Ubuntu 22.04, Py 3.10, from latest"
distro_image: "ubuntu:22.04" distro_image: "ubuntu:22.04"
extra_flags: --upgrade-from=latest extra_flags: --upgrade-from=latest
- name: "Ubuntu 22.04, Py 3.10, from 0.2.0" - name: "Ubuntu 22.04, Py 3.10, from 1.*"
distro_image: "ubuntu:22.04" distro_image: "ubuntu:22.04"
extra_flags: --upgrade-from=0.2.0 extra_flags: --upgrade-from=1
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v5
- uses: actions/setup-python@v4 - uses: actions/setup-python@v6
with: with:
python-version: "3.10" python-version: "3.10"
@@ -116,10 +119,13 @@ jobs:
distro_image: "ubuntu:22.04" distro_image: "ubuntu:22.04"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v5
- uses: actions/setup-python@v4 - uses: actions/setup-python@v6
with: with:
python-version: "3.10" python-version: "3.10"
cache: pip
cache-dependency-path: |
integration-tests/requirements.txt
# FIXME: The test_bootstrap.py script has duplicated logic to run build # FIXME: The test_bootstrap.py script has duplicated logic to run build
# and start images and run things in them. This makes tests slower, # and start images and run things in them. This makes tests slower,

View File

@@ -40,46 +40,33 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- name: "Ubuntu 20.04, Py 3.9"
ubuntu_version: "20.04"
python_version: "3.9"
- name: "Ubuntu 22.04, Py 3.10" - name: "Ubuntu 22.04, Py 3.10"
ubuntu_version: "22.04" ubuntu_version: "22.04"
python_version: "3.10" python_version: "3.10"
- name: "Ubuntu 24.04, Py 3.12"
ubuntu_version: "24.04"
python_version: "3.12"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v5
- uses: actions/setup-python@v4 - uses: actions/setup-python@v6
with: with:
python-version: "${{ matrix.python_version }}" python-version: "${{ matrix.python_version }}"
- name: Install venv, git and setup venv - name: Install system dependencies and setup venv
run: | run: |
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
apt-get update apt-get update
apt-get install --yes \ apt-get install --yes \
python3-venv \ python3-venv \
python3-pip \
bzip2 \ bzip2 \
git git \
curl
python3 -m venv /srv/venv python3 -m venv /srv/venv
echo '/srv/venv/bin' >> $GITHUB_PATH echo '/srv/venv/bin' >> $GITHUB_PATH
# WARNING: This action loads a cache of pip dependencies based on the
# declared key, and it will save a cache for that key on job
# completion. Make sure to update the key to bust the cache
# properly if you make a change that should influence it.
- name: Load cached Python dependencies
uses: actions/cache@v3
with:
path: /srv/venv/
key: >-
pip-
${{ matrix.runs_on }}-
${{ matrix.ubuntu_version }}-
${{ matrix.python_version }}-
${{ hashFiles('setup.py', 'dev-requirements.txt', '.github/workflows/unit-test.yaml') }}
- name: Install Python dependencies - name: Install Python dependencies
run: | run: |
pip install -r dev-requirements.txt pip install -r dev-requirements.txt
@@ -93,4 +80,4 @@ jobs:
run: pytest tests run: pytest tests
timeout-minutes: 15 timeout-minutes: 15
- uses: codecov/codecov-action@v3 - uses: codecov/codecov-action@v5

View File

@@ -11,18 +11,18 @@
repos: repos:
# Autoformat: Python code, syntax patterns are modernized # Autoformat: Python code, syntax patterns are modernized
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v3.10.1 rev: v3.21.2
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: args:
- --py36-plus - --py39-plus
# We need the bootstrap.py script to be parsable with Python 3.5, so we # We need the bootstrap.py script to be parsable with Python 3.8, so we
# exclude it from the pyupgrade hook that will apply f-strings etc. # exclude it from the pyupgrade hook that will apply f-strings etc.
exclude: bootstrap/bootstrap.py exclude: bootstrap/bootstrap.py
# Autoformat: Python code # Autoformat: Python code
- repo: https://github.com/PyCQA/autoflake - repo: https://github.com/PyCQA/autoflake
rev: v2.2.0 rev: v2.3.1
hooks: hooks:
- id: autoflake - id: autoflake
# args ref: https://github.com/PyCQA/autoflake#advanced-usage # args ref: https://github.com/PyCQA/autoflake#advanced-usage
@@ -31,25 +31,25 @@ repos:
# Autoformat: Python code # Autoformat: Python code
- repo: https://github.com/pycqa/isort - repo: https://github.com/pycqa/isort
rev: 5.12.0 rev: 7.0.0
hooks: hooks:
- id: isort - id: isort
# Autoformat: Python code # Autoformat: Python code
- repo: https://github.com/psf/black - repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.7.0 rev: 25.11.0
hooks: hooks:
- id: black - id: black
# Autoformat: markdown, yaml # Autoformat: markdown, yaml
- repo: https://github.com/pre-commit/mirrors-prettier - repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.0 rev: v4.0.0-alpha.8
hooks: hooks:
- id: prettier - id: prettier
# Misc... # Misc...
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 rev: v6.0.0
# ref: https://github.com/pre-commit/pre-commit-hooks#hooks-available # ref: https://github.com/pre-commit/pre-commit-hooks#hooks-available
hooks: hooks:
# Autoformat: Makes sure files end in a newline and only a newline. # Autoformat: Makes sure files end in a newline and only a newline.
@@ -64,7 +64,7 @@ repos:
# Lint: Python code # Lint: Python code
- repo: https://github.com/pycqa/flake8 - repo: https://github.com/pycqa/flake8
rev: "6.1.0" rev: "7.3.0"
hooks: hooks:
- id: flake8 - id: flake8

View File

@@ -27,22 +27,15 @@ for information on the different ways of contributing to The Littlest JupyterHub
See [this blog post](http://words.yuvi.in/post/the-littlest-jupyterhub/) for See [this blog post](http://words.yuvi.in/post/the-littlest-jupyterhub/) for
more information. more information.
## Development Status
This project is currently in **beta** state. Folks have been using installations
of TLJH for more than a year now to great success. While we try hard not to, we
might still make breaking changes that have no clear upgrade pathway.
## Installation ## Installation
The Littlest JupyterHub (TLJH) can run on any server that is running at least The Littlest JupyterHub (TLJH) can run on any server that is running at least
**Ubuntu 20.04**. Earlier versions of Ubuntu are not supported. **Ubuntu 22.04**. Earlier versions of Ubuntu are not supported.
We have several tutorials to get you started. We have several tutorials to get you started.
- Tutorials to create a new server from scratch on a cloud provider & run TLJH - Tutorials to create a new server from scratch on a cloud provider & run TLJH
on it. These are **recommended** if you do not have much experience setting up on it. These are **recommended** if you do not have much experience setting up
servers. servers.
- [Digital Ocean](https://the-littlest-jupyterhub.readthedocs.io/en/latest/install/digitalocean.html) - [Digital Ocean](https://the-littlest-jupyterhub.readthedocs.io/en/latest/install/digitalocean.html)
- [OVH](https://the-littlest-jupyterhub.readthedocs.io/en/latest/install/ovh.html) - [OVH](https://the-littlest-jupyterhub.readthedocs.io/en/latest/install/ovh.html)
- [Google Cloud](https://the-littlest-jupyterhub.readthedocs.io/en/latest/install/google.html) - [Google Cloud](https://the-littlest-jupyterhub.readthedocs.io/en/latest/install/google.html)

View File

@@ -9,10 +9,10 @@ This script is run as:
Constraints: Constraints:
- The entire script should be compatible with Python 3.8, which is the default on - The entire script should be compatible with Python 3.9, which is the default on
Ubuntu 20.04. Debian 11.
- The script should parse in Python 3.6 as we print error messages for using - The script should parse in Python 3.8 as we print error messages for using
Ubuntu 18.04 which comes with Python 3.6 by default. Ubuntu 20.04 which comes with Python 3.8 by default.
- The script must depend only on stdlib modules, as no previous installation - The script must depend only on stdlib modules, as no previous installation
of dependencies can be assumed. of dependencies can be assumed.
@@ -42,6 +42,7 @@ Command line flags, from "bootstrap.py --help":
can also pass a branch name such as 'main' or a can also pass a branch name such as 'main' or a
commit hash. commit hash.
""" """
import logging import logging
import multiprocessing import multiprocessing
import os import os
@@ -209,22 +210,22 @@ def ensure_host_system_can_install_tljh():
Check if TLJH is installable in current host system and exit with a clear Check if TLJH is installable in current host system and exit with a clear
error message otherwise. error message otherwise.
""" """
# Require Ubuntu 20.04+ or Debian 11+ # Require Ubuntu 22.04+ or Debian 11+
distro = get_os_release_variable("ID") distro = get_os_release_variable("ID")
version = get_os_release_variable("VERSION_ID") version = get_os_release_variable("VERSION_ID")
if distro not in ["ubuntu", "debian"]: if distro not in ["ubuntu", "debian"]:
print("The Littlest JupyterHub currently supports Ubuntu or Debian Linux only") print("The Littlest JupyterHub currently supports Ubuntu or Debian Linux only")
sys.exit(1) sys.exit(1)
elif distro == "ubuntu" and _parse_version(version) < (20, 4): elif distro == "ubuntu" and _parse_version(version) < (22, 4):
print("The Littlest JupyterHub requires Ubuntu 20.04 or higher") print("The Littlest JupyterHub requires Ubuntu 22.04 or higher")
sys.exit(1) sys.exit(1)
elif distro == "debian" and _parse_version(version) < (11,): elif distro == "debian" and _parse_version(version) < (11,):
print("The Littlest JupyterHub requires Debian 11 or higher") print("The Littlest JupyterHub requires Debian 11 or higher")
sys.exit(1) sys.exit(1)
# Require Python 3.8+ # Require Python 3.9+
if sys.version_info < (3, 8): if sys.version_info < (3, 9):
print(f"bootstrap.py must be run with at least Python 3.8, found {sys.version}") print(f"bootstrap.py must be run with at least Python 3.9, found {sys.version}")
sys.exit(1) sys.exit(1)
# Require systemd (systemctl is a part of systemd) # Require systemd (systemctl is a part of systemd)

View File

@@ -138,3 +138,14 @@ rediraffe_redirects = {
"howto/env/notebook-interfaces": "howto/user-env/notebook-interfaces", "howto/env/notebook-interfaces": "howto/user-env/notebook-interfaces",
"howto/env/server-resources": "howto/user-env/server-resources", "howto/env/server-resources": "howto/user-env/server-resources",
} }
def setup(app):
# Enable Plausible.io stats
app.add_js_file(
"https://plausible.io/js/pa-B75UO5--FNXYQSG7GBWkf.js", loading_method="async"
)
app.add_js_file(
filename=None,
body="window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};plausible.init({hashBasedRouting:true})",
)

View File

@@ -24,6 +24,9 @@ The easiest & safest way to develop & test TLJH is with [Docker](https://www.doc
--detach \ --detach \
--name=tljh-dev \ --name=tljh-dev \
--publish 12000:80 \ --publish 12000:80 \
--env TLJH_BOOTSTRAP_DEV=yes \
--env TLJH_BOOTSTRAP_PIP_SPEC=/srv/src \
--env PATH=/opt/tljh/hub/bin:${PATH} \
--mount type=bind,source="$(pwd)",target=/srv/src \ --mount type=bind,source="$(pwd)",target=/srv/src \
tljh-systemd tljh-systemd
``` ```
@@ -58,7 +61,6 @@ The easiest & safest way to develop & test TLJH is with [Docker](https://www.doc
8. Make some changes to the repository. You can test easily depending on what 8. Make some changes to the repository. You can test easily depending on what
you changed. you changed.
- If you changed the `bootstrap/bootstrap.py` script or any of its dependencies, - If you changed the `bootstrap/bootstrap.py` script or any of its dependencies,
you can test it by running `python3 /srv/src/bootstrap/bootstrap.py`. you can test it by running `python3 /srv/src/bootstrap/bootstrap.py`.
- If you changed the `tljh/installer.py` code (or any of its dependencies), - If you changed the `tljh/installer.py` code (or any of its dependencies),

View File

@@ -28,35 +28,43 @@ against the same installation of TLJH.
### Running integration tests locally ### Running integration tests locally
You need `docker` installed and callable by the user running You need `docker` or `podman` installed and callable by the user
the integration tests without needing sudo. running the integration tests without needing sudo.
You can then run the tests with: First build the container with a Ubuntu-based image:
```bash ```bash
.github/integration-test.py run-test <name-of-run> <test-file-names> .github/integration-test.py build-image \
--build-arg "BASE_IMAGE=ubuntu:22.04"
``` ```
- `<name-of-run>` is an identifier for the tests - you can choose anything you want Then you can then run the tests with the `run-test` function. For usage run:
- `<test-file-names>>` is list of test files (under `integration-tests`) that should be run in one go.
```bash
.github/integration-test.py run-test --help
```
For example, to run all the basic tests, you would write: For example, to run all the basic tests, you would write:
```bash ```bash
.github/integration-test.py run-test basic-tests \ .github/integration-test.py run-test basic-tests \
test_hub.py \ test_hub.py \
test_proxy.py \ test_proxy.py \
test_install.py \ test_install.py \
test_extensions.py test_extensions.py
``` ```
This will run the tests in the three files against the same installation This will run the tests in the four files against the same installation
of TLJH and report errors. of TLJH and report errors.
If you would like to run the tests with a custom pip spec for the bootstrap script, you can use the `--bootstrap-pip-spec` If you would like to run the tests with a custom `pip` spec for the bootstrap script, you can use the `--bootstrap-pip-spec`
parameter: parameter:
```bash ```bash
.github/integration-test.py run-test <name-of-run> <test-file-names> \ .github/integration-test.py run-test custom-pip-spec \
--bootstrap-pip-spec="git+https://github.com/your-username/the-littlest-jupyterhub.git@branch-name" test_hub.py \
test_proxy.py \
test_install.py \
test_extensions.py \
--bootstrap-pip-spec="git+https://github.com/your-username/the-littlest-jupyterhub.git@branch-name"
``` ```

View File

@@ -82,7 +82,7 @@ renew them for you before they expire.
## Manual HTTPS with existing key and certificate ## Manual HTTPS with existing key and certificate
You may already have an SSL key and certificate. You may already have an SSL key and certificate for your domain.
If so, you can tell your deployment to use these files: If so, you can tell your deployment to use these files:
``` ```
@@ -111,7 +111,7 @@ Finally, you can reload the proxy to load the new configuration:
sudo tljh-config reload proxy sudo tljh-config reload proxy
``` ```
and now access your Hub securely at <https://yourhub.yourdomain.edu>. and now access your Hub securely at the domain associated with your certificate.
## Troubleshooting ## Troubleshooting

View File

@@ -23,7 +23,7 @@ PrivateDevices=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelModules=yes ProtectKernelModules=yes
Environment=TLJH_INSTALL_PREFIX=/opt/tljh Environment=TLJH_INSTALL_PREFIX=/opt/tljh
ExecStart=/opt/tljh/hub/bin/python3 -m jupyterhub.app -f jupyterhub_config.py --upgrade-db ExecStart=/opt/tljh/hub/bin/python3 -m jupyterhub -f jupyterhub_config.py --upgrade-db
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@@ -38,6 +38,8 @@ these namespacing settings might be a bit too strict and prevent users from acce
To override the `jupyterhub` settings, it is possible to provide a custom `/etc/systemd/system/jupyterhub.service.d/override.conf` file. To override the `jupyterhub` settings, it is possible to provide a custom `/etc/systemd/system/jupyterhub.service.d/override.conf` file.
You can create this file with `sudo systemctl edit jupyterhub.service`
Here is an example for the content of the file: Here is an example for the content of the file:
```bash ```bash
@@ -72,7 +74,7 @@ The output should look like the following:
``` ```
To override the `traefik` settings, create a new file under `/etc/systemd/system/traefik.service.d/override.conf` To override the `traefik` settings, create a new file under `/etc/systemd/system/traefik.service.d/override.conf`
and follow the same steps. (or use `sudo systemctl edit traefik.service`) and follow the same steps.
## References ## References

View File

@@ -24,7 +24,6 @@ application to your `tljh` configuration.
1. Create a user pool [Getting Started with User Pool](https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-with-cognito-user-pools.html). 1. Create a user pool [Getting Started with User Pool](https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-with-cognito-user-pools.html).
When you have completed creating a user pool, app, and domain you should have the following settings available to you: When you have completed creating a user pool, app, and domain you should have the following settings available to you:
- **App client id**: From the App client page - **App client id**: From the App client page
- **App client secret** From the App client page - **App client secret** From the App client page
@@ -149,9 +148,10 @@ If it is not provided as array, there is an easy fix. Just add these lines to
your `awscognito.py`: your `awscognito.py`:
```python ```python
def claim_groups_key_func(user_data_resp_json): def groups_key_func(auth_state):
return [user_data_resp_json['custom:department']] return [auth_state['oauth_user']['custom:department']]
c.GenericOAuthenticator.claim_groups_key = claim_groups_key_func c.GenericOAuthenticator.manage_groups = True
c.GenericOAuthenticator.auth_state_groups_key = groups_key_func
c.GenericOAuthenticator.allowed_groups = ["AA BB CC", "AA BB DD"] c.GenericOAuthenticator.allowed_groups = ["AA BB CC", "AA BB DD"]
``` ```

View File

@@ -26,7 +26,6 @@ You'll need a GitHub account in order to complete these steps.
## Step 1: Create a GitHub application ## Step 1: Create a GitHub application
1. Go to the [GitHub OAuth app creation page](https://github.com/settings/applications/new). 1. Go to the [GitHub OAuth app creation page](https://github.com/settings/applications/new).
- **Application name**: Choose a descriptive application name (e.g. `tljh`) - **Application name**: Choose a descriptive application name (e.g. `tljh`)
- **Homepage URL**: Use the IP address or URL of your JupyterHub. e.g. `` http(s)://<my-tljh-url>` ``. - **Homepage URL**: Use the IP address or URL of your JupyterHub. e.g. `` http(s)://<my-tljh-url>` ``.
@@ -91,10 +90,16 @@ For more information on `tljh-config`, see [](/topic/tljh-config).
4. Tell your JupyterHub to _use_ the GitHub OAuthenticator for authentication: 4. Tell your JupyterHub to _use_ the GitHub OAuthenticator for authentication:
``` ```
sudo tljh-config set auth.type oauthenticator.github.GitHubOAuthenticator sudo tljh-config set auth.type github
``` ```
5. Restart your JupyterHub so that new users see these changes: 5. Tell JupyterHub which users to allow, if you haven't already:
```
sudo tljh-config add-item users.allowed good-user_1
```
6. Restart your JupyterHub so that new users see these changes:
``` ```
sudo tljh-config reload sudo tljh-config reload

View File

@@ -51,7 +51,6 @@ and create a new project:
``` ```
- You will have to fill a form with: - You will have to fill a form with:
- **Application type**: Choose _Web application_ - **Application type**: Choose _Web application_
- **Name**: A descriptive name for your OAuth client ID (e.g. `tljh-client`) - **Name**: A descriptive name for your OAuth client ID (e.g. `tljh-client`)

View File

@@ -42,4 +42,4 @@ tljh-config reload
## Optional features ## Optional features
More optional features are available on the `authenticator documentation <https://native-authenticator.readthedocs.io/en/latest/>` More optional features are available on the [authenticator documentation](https://native-authenticator.readthedocs.io/en/latest/)

View File

@@ -7,7 +7,8 @@ be changed with TLJH config `user_environment.default_app` or with the
JupyterHub config JupyterHub config
{external:py:attr}`jupyterhub.spawner.Spawner.default_url` directly. {external:py:attr}`jupyterhub.spawner.Spawner.default_url` directly.
The TLJH config supports the options `jupyterlab` and `classic`, which The TLJH config supports the options [`jupyterlab`](https://github.com/jupyterlab/jupyterlab/)
and [`classic`](https://github.com/jupyter/notebook), which
translates to a `Spawner.default_url` config of `/lab` and `/tree`. translates to a `Spawner.default_url` config of `/lab` and `/tree`.
Both these interfaces are also shipped with TLJH by default. You can try them Both these interfaces are also shipped with TLJH by default. You can try them

View File

@@ -180,7 +180,6 @@ To upgrade the Python version of the user environment, one can:
environment, but you may do so manually. environment, but you may do so manually.
**Steps:** **Steps:**
1. Activate the user environment, if using ssh. If the terminal was 1. Activate the user environment, if using ssh. If the terminal was
started with JupyterHub, this step can be skipped: started with JupyterHub, this step can be skipped:

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -4,12 +4,6 @@ A simple [JupyterHub](https://github.com/jupyterhub/jupyterhub) distribution for
a small (0-100) number of users on a single server. We recommend reading a small (0-100) number of users on a single server. We recommend reading
[](/topic/whentouse) to determine if this is the right tool for you. [](/topic/whentouse) to determine if this is the right tool for you.
## Development Status
This project is currently in **beta** state. Folks have been using installations
of TLJH for more than a year now to great success. While we try hard not to, we
might still make breaking changes that have no clear upgrade pathway.
## Installation ## Installation
The Littlest JupyterHub (TLJH) can run on any server that is running **Debian 11** or **Ubuntu 20.04** or **22.04** on an amd64 or arm64 CPU architecture. The Littlest JupyterHub (TLJH) can run on any server that is running **Debian 11** or **Ubuntu 20.04** or **22.04** on an amd64 or arm64 CPU architecture.

View File

@@ -1,11 +1,10 @@
Most administration & configuration of the JupyterHub can be done from the Most administration & configuration of the JupyterHub can be done from the
web UI directly. Let's add a few users who can log in! web UI directly. Let's add a few users who can log in!
1. Open the **Control Panel** by clicking the control panel button on the top 1. In the File menu select the entry for the **Hub Control Panel**.
right of your JupyterHub.
```{image} ../images/control-panel-button.png ```{image} ../images/control-panel-menu.png
:alt: Control panel button in notebook, top right :alt: Hub Control panel entry in lab File menu
``` ```
2. In the control panel, open the **Admin** link in the top left. 2. In the control panel, open the **Admin** link in the top left.

View File

@@ -139,10 +139,10 @@ Let's create the server on which we can run JupyterHub.
SSH to connect (port 22). SSH to connect (port 22).
If you have never used your Amazon account before, you'll have to select If you have never used your Amazon account before, you'll have to select
**Create a new security group**. You should give it a disitnguishing name **Create a new security group**. You should give it a distinctive name
under **Security group name** under **Security group name**
such as `ssh_web` for future reference. If you have, one from before you can such as `ssh_web` for future reference. If you already have a security group,
select it and adjust it to have the rules you need, if you prefer. you can select it and adjust it to have the rules you need, if you prefer.
The rules will default to include `SSH`. Leave that there, and then click on The rules will default to include `SSH`. Leave that there, and then click on
the **Add Rule** button. Under **Type** for the new rule, change the field the **Add Rule** button. Under **Type** for the new rule, change the field

View File

@@ -51,7 +51,6 @@ We start by creating the Virtual Machine in which we can run TLJH (The Littlest
``` ```
5. **Choose an Ubuntu server for your VM**: 5. **Choose an Ubuntu server for your VM**:
- Click `Ubuntu Server 22.04 LTS.` - Click `Ubuntu Server 22.04 LTS.`
- Make sure `Resource Manager` is selected in the next screen and click **Create** - Make sure `Resource Manager` is selected in the next screen and click **Create**
@@ -61,7 +60,6 @@ We start by creating the Virtual Machine in which we can run TLJH (The Littlest
``` ```
6. Customise the Virtual Machine basics: 6. Customise the Virtual Machine basics:
- **Subscription**. Choose the "Free Trial" if this is what you're using. Otherwise, choose a different plan. This is the billing account that will be charged. - **Subscription**. Choose the "Free Trial" if this is what you're using. Otherwise, choose a different plan. This is the billing account that will be charged.
- **Resource group**. Resource groups let you keep your Azure tools/resources together in an availability region (e.g. WestEurope). If you already have one you'd like to use it select that resource. - **Resource group**. Resource groups let you keep your Azure tools/resources together in an availability region (e.g. WestEurope). If you already have one you'd like to use it select that resource.
@@ -89,7 +87,6 @@ We start by creating the Virtual Machine in which we can run TLJH (The Littlest
- **Inbound port rules**. Leave the defaults for now, and we will update these later on in the Network configuration step. - **Inbound port rules**. Leave the defaults for now, and we will update these later on in the Network configuration step.
7. Before clicking on "Next" we need to select the RAM size for the image. 7. Before clicking on "Next" we need to select the RAM size for the image.
- For this we need to make sure we have enough RAM to accommodate your users. For example, if each user needs 2GB of RAM, and you have 10 total users, you need at least 20GB of RAM on the machine. It's also good to have a few GB of "buffer" RAM beyond what you think you'll need. - For this we need to make sure we have enough RAM to accommodate your users. For example, if each user needs 2GB of RAM, and you have 10 total users, you need at least 20GB of RAM on the machine. It's also good to have a few GB of "buffer" RAM beyond what you think you'll need.
- Click on **Change size** (see image below) - Click on **Change size** (see image below)
@@ -105,7 +102,6 @@ We start by creating the Virtual Machine in which we can run TLJH (The Littlest
- Select a suitable image (to check available images and prices in your region [click on this link](https://azuremarketplace.microsoft.com/en-gb/marketplace/apps/Canonical.UbuntuServer?tab=PlansAndPrice/?wt.mc_id=TLJH-github-taallard)). - Select a suitable image (to check available images and prices in your region [click on this link](https://azuremarketplace.microsoft.com/en-gb/marketplace/apps/Canonical.UbuntuServer?tab=PlansAndPrice/?wt.mc_id=TLJH-github-taallard)).
8. Disks (Storage): 8. Disks (Storage):
- **Disk options**: select the OS disk type there are options for SDD and HDD. **SSD persistent disk** gives you a faster but more expensive disk than HDD. - **Disk options**: select the OS disk type there are options for SDD and HDD. **SSD persistent disk** gives you a faster but more expensive disk than HDD.
- **Data disk**. Click on create and attach a new disk. Select an appropriate type and size and click ok. - **Data disk**. Click on create and attach a new disk. Select an appropriate type and size and click ok.
@@ -120,7 +116,6 @@ We start by creating the Virtual Machine in which we can run TLJH (The Littlest
``` ```
9. Networking 9. Networking
- **Virtual network**. Leave the default values selected. - **Virtual network**. Leave the default values selected.
- **Subnet**. Leave the default values selected. - **Subnet**. Leave the default values selected.
- **Public IP address**.Leave the default values selected. This will make your server accessible from a browser. - **Public IP address**.Leave the default values selected. This will make your server accessible from a browser.
@@ -132,9 +127,7 @@ We start by creating the Virtual Machine in which we can run TLJH (The Littlest
``` ```
10. Management 10. Management
- Monitoring - Monitoring
- **Boot diagnostics**. Choose "On". - **Boot diagnostics**. Choose "On".
- **OS guest diagnostics**. Choose "Off". - **OS guest diagnostics**. Choose "Off".
- **Diagnostics storage account**. Leave as the default. - **Diagnostics storage account**. Leave as the default.
@@ -150,7 +143,6 @@ We start by creating the Virtual Machine in which we can run TLJH (The Littlest
``` ```
11. Advanced settings 11. Advanced settings
- **Extensions**. Make sure there are no extensions listed - **Extensions**. Make sure there are no extensions listed
- **Cloud init**. We are going to use this section to install TLJH directly into our Virtual Machine. - **Cloud init**. We are going to use this section to install TLJH directly into our Virtual Machine.
@@ -177,7 +169,6 @@ We start by creating the Virtual Machine in which we can run TLJH (The Littlest
12. Check the summary and confirm the creation of your Virtual Machine. 12. Check the summary and confirm the creation of your Virtual Machine.
13. Check that the creation of your Virtual Machine worked. 13. Check that the creation of your Virtual Machine worked.
- Wait for the virtual machine to be created. This might take about 5-10 minutes. - Wait for the virtual machine to be created. This might take about 5-10 minutes.
- After completion, you should see a similar screen to the one below: - After completion, you should see a similar screen to the one below:

View File

@@ -1,152 +1,112 @@
(install-jetstream)= (install-jetstream)=
# Installing on Jetstream # Installing on Jetstream2
## Goal ## Goal
By the end of this tutorial, you should have a JupyterHub with some admin By the end of this tutorial, you should have a JupyterHub with some admin
users and a user environment with packages you want installed running on users and a user environment with packages you want installed running on
[Jetstream](https://jetstream-cloud.org/). [Jetstream2](https://jetstream-cloud.org/).
## Prerequisites ## Prerequisites
1. A Jetstream account with an XSEDE allocation; for more information, 1. An ACCESS ID, and membership in an allocation with access to Jetstream2 resources; for more information,
see the [Jetstream Allocations help page](http://wiki.jetstream-cloud.org/Jetstream+Allocations). see the [Jetstream2 Allocations Overview page](https://docs.jetstream-cloud.org/alloc/overview/) and the [Get started with Jetstream2 guide](https://jetstream-cloud.org/get-started/).
## Step 1: Installing The Littlest JupyterHub ## Step 1: Launch a Jetstream2 instance
Let's create the server on which we can run JupyterHub. We'll create a new Jetstream2 instance:
1. Log in to [the Jetstream portal](https://use.jetstream-cloud.org/). You need an allocation 1. Log in to the [Jetstream2 portal](https://use.jetstream-cloud.org/). You must have (and select) an allocation in order to launch instances. Click the allocation you want to charge.
to launch instances. 2. Click **Create****Instance**.
3. From the list of images, select **Ubuntu 24.04** (Jammy or newer is required for current TLJH releases).
4. In the **Create Instance** dialog:
1. Set a descriptive **Instance Name** (this is used in the default hostname and helps users recognize it).
2. Choose an **Instance Size**. We suggest `m3.small` (2 vCPUs / 6 GiB RAM) or larger for more than a couple of users. The absolute minimum TLJH can start with is about **1GiB** RAM, but you'll quickly run out with real workloads.
- See the resource estimation guide: [Choosing resources](/howto/admin/resource-estimation) for help picking CPU, RAM, and disk.
3. (Optional) Increase the **Volume Size** if you expect many users or large datasets. You can not easily shrink later.
5. Launch the instance (click **Create** button at the bottom of the form).
2. Select the **Launch New Instance** option to get going. ## Step 2: Install The Littlest JupyterHub
```{image} ../images/providers/jetstream/launch-instance-first-button.png 1. Wait a few minutes for the instance to show the status "Ready"
:alt: Launch new instance button with description. 2. Copy the **Hostname** under **Credentials**, it will be of the form: `yourinstancename.xxx0000000.projects.jetstream-cloud.org`, where `xxx000000` is the allocation ID. Keep it handy, we will use it multiple times in the next steps.
```
This takes you to a page with a list of base images you can choose for your 3. SSH into the instance with the `exouser` user:
server.
3. Under **Image Search**, search for **Ubuntu 22.04**, and select the ```bash
**Ubuntu 22.04 Devel and Docker** image. ssh exouser@yourinstancename.xxx0000000.projects.jetstream-cloud.org
```
```{image} ../images/providers/jetstream/select-image.png Need the passphrase? In Exosphere, open **Instances**, select your
:alt: Select Ubuntu 22.04 x64 image from image list JupyterHub instance, and expand **Credentials**. Click **Show Passphrase**
``` next to the `exouser` entry to reveal or copy it before running the
`ssh` command.
4. Once selected, you will see more information about this image. Click the 4. Run the TLJH bootstrap script, replace <admin-user-name> with the name of the first admin user for this JupyterHub. Choose any name you like (dont forget to remove the brackets!). This admin user can log in after the JupyterHub is set up, and can configure it to their needs.
**Launch** button on the top right.
```{image} ../images/providers/jetstream/launch-instance-second-button.png ```bash
:alt: Launch selected image with Launch button on top right curl -L https://tljh.jupyter.org/bootstrap.py | sudo -E python3 - --admin <admin-user-name>
``` ```
5. A dialog titled **Launch an Instance / Basic Options** pops up, with various 5. Open the Hostname in a web browser (http on port 80). You should see the JupyterHub login page. Your browser will warn about the site not being secure (no HTTPS)—we'll enable HTTPS in the next step. Do not login yet, first setup HTTPS, so we avoid transmitting the password in clear text.
options for configuring your instance.
```{image} ../images/providers/jetstream/launch-instance-dialog.png ## Step 2: Enable HTTPS
:alt: Launch an Instance / Basic Options dialog box
```
1. Give your server a descriptive **Instance Name**. Encrypted (HTTPS) access is strongly recommended before inviting users.
2. Select an appropriate **Instance Size**. We suggest m1.medium or larger. See the full guide: [Enable HTTPS](/howto/admin/https). Below is a quick recipe for using the default Jetstream-provided hostname.
Make sure your instance has at least **1GB** of RAM.
Check out our guide on How To [](/howto/admin/resource-estimation) to help pick 1. In the terminal inside the instance, configure Let's Encrypt (replace with a real email you control, and the correct hostname):
how much Memory, CPU & disk space your server needs. ```bash
sudo tljh-config set https.enabled true
sudo tljh-config set https.letsencrypt.email you@example.com
sudo tljh-config add-item https.letsencrypt.domains yourinstancename.xxx0000000.projects.jetstream-cloud.org
sudo tljh-config reload proxy
```
2. Wait ~3060 seconds, then reload the site using https://. If certificate issuance fails, check the logs:
```bash
sudo journalctl -u traefik --since "10 minutes ago" | grep -i acme
```
3. If you have multiple allocations, make sure you are 'charging' this server Tips:
to the correct allocation.
6. Click the **Advanced Options** link in the bottom left of the popup. This - Make sure ports 80 and 443 are open in your Jetstream security group (they are open by default for new projects; adjust only if you customized network policies).
lets us configure what the server should do when it starts up. We will use - If you later attach a custom domain, add it with another `add-item` command and reload the proxy again.
this to install The Littlest JupyterHub.
A dialog titled **Launch an Instance / Advanced Options** should pop up. ## Step 3: Log in as the administrative user and set a password
```{image} ../images/providers/jetstream/add-deployment-script-dialog.png 1. Now log in with the `<admin-user-name>` at https://yourinstancename.xxx000000.projects.jetstream-cloud.org. Since this is the first login, you'll be prompted to set a password. Choose a strong password and store it safely. This password is now the credential for that admin user.
:alt: Dialog box allowing you to add a new script. 2. Congratulations, you have a running working JupyterHub!
```
7. Click the **Create New Script** button. This will open up another dialog ## Step 4: Adding more users
box!
```{image} ../images/providers/jetstream/create-script-dialog.png
:alt: Launch an Instance / Advanced Options dialog box
```
8. Under **Input Type**, select **Raw Text**. This should make a text box titled
**Raw Text** visible on the right side of the dialog box.
Copy the text below, and paste it into the **Raw Text** text box. Replace
`<admin-user-name>` with the name of the first **admin user** for this
JupyterHub. This admin user can log in after the JupyterHub is set up, and
can configure it to their needs. **Remember to add your username**!
```bash
#!/bin/bash
curl -L https://tljh.jupyter.org/bootstrap.py \
| sudo python3 - \
--admin <admin-user-name>
```
:::{note}
See [](/topic/installer-actions) if you want to understand exactly what the installer is doing.
[](/topic/customizing-installer) documents other options that can be passed to the installer.
:::
9. Under **Execution Strategy Type**, select **Run script on first boot**.
10. Under **Deployment Type**, select **Wait for script to complete**.
11. Click the **Save and Add Script** button on the bottom right. This should hide
the dialog box.
12. Click the **Continue to Launch** button on the bottom right. This should put you
back in the **Launch an Instance / Basic Options** dialog box again.
13. Click the **Launch Instance** button on the bottom right. This should turn it
into a spinner, and your server is getting created!
```{image} ../images/providers/jetstream/launching-spinner.png
:alt: Launch button turns into a spinner
```
14. You'll now be shown a dashboard with all your servers and their states. The
server you just launched will progress through various stages of set up,
and you can see the progress here.
```{image} ../images/providers/jetstream/deployment-in-progress.png
:alt: Instances dashboard showing deployment in progress.
```
15. It will take about ten minutes for your server to come up. The status will
say **Active** and the progress bar will be a solid green. At this point,
your JupyterHub is ready for use!
16. Copy the **IP Address** of your server, and try accessing it from a web
browser. It should give you a JupyterHub login page.
```{image} ../images/first-login.png
:alt: JupyterHub log-in page
```
17. Login using the **admin user name** you used in step 8, and a password. Use a
strong password & note it down somewhere, since this will be the password for
the admin user account from now on.
18. Congratulations, you have a running working JupyterHub!
## Step 2: Adding more users
```{include} add-users.md ```{include} add-users.md
```
Next common tasks:
## Step 3: Install conda / pip packages for all users
- [](howto-admin-admin-users)
```{include} add-packages.md - [](howto-user-env-user-environment-apt)
- [](howto-admin-enable-extensions)
- []topic-installer-upgrade-actions)
Browse the full [How-To index](/howto/index) for more.
## Ask for help
Need a hand?
- For Jetstream2 specific questions (allocations, quotas, instance lifecycle, networking, etc.), use the [Jetstream support resources](https://docs.jetstream-cloud.org/overview/support/).
- For The Littlest JupyterHub usage, configuration, or upgrade questions, search or post in the [Jupyter forum TLJH category](https://discourse.jupyter.org/c/jupyterhub/tljh).
- If you believe you have found a TLJH bug or have a clear documentation improvement, open an issue (or pull request if you have a proposed fix) in the [TLJH GitHub repository](https://github.com/jupyterhub/the-littlest-jupyterhub).
When asking for help about TLJH, it is often useful to provide:
- A short description of what you were trying to do and what happened instead
- Relevant log excerpts (see [](/troubleshooting/logs))
- Your TLJH version (`sudo tljh-config show | grep version` if present in config) and the output of `lsb_release -a` for the OS
- Any custom installer flags or `tljh-config` changes you have applied
This information helps others debug and answer more quickly.
``` ```

View File

@@ -2,6 +2,135 @@
# Changelog # Changelog
## 2.0
### 2.0.0 - 2024-10-21
This release bundles with the latest available software from the JupyterHub
ecosystem.
For instructions on how to make an upgrade, see [](howto-admin-upgrade-tljh).
#### Breaking changes
- JupyterHub 4.\* has been upgraded to >=5.2.0,<6
- Refer to the [JupyterHub changelog] for details and pay attention to the
changelog entry for JupyterHub version 5.0.0.
- OAuthenticator 16.0.4 has been upgraded to >=17.1.0,<18
- If you are using an OAuthenticator based authenticator class
(GitHubOAuthenticator, GoogleOAuthenticator, ...), refer to the
[OAuthenticator changelog] for details and pay attention to the changelog
entry for OAuthenticator version 17.0.0.
- LDAPAuthenticator 1.3.2 has been upgraded to >=2.0.0,<3
- If you are using this authenticator class, refer to the [LDAPAuthenticator
changelog] for details and pay attention to the changelog entry for
LDAPAuthenticator version 2.0.0.
- The configured JupyterHub Proxy class `traefik-proxy` and the `traefik` server
controlled by JupyterHub via the proxy class has been upgraded to a new major
version, but no breaking change are expected to be noticed for users.
[oauthenticator changelog]: https://oauthenticator.readthedocs.io/en/latest/reference/changelog.html
[ldapauthenticator changelog]: https://github.com/jupyterhub/ldapauthenticator/blob/HEAD/CHANGELOG.md
#### Notable dependencies updated
A TLJH installation provides a Python environment where the software for
JupyterHub itself runs - _the hub environment_, and a Python environment where
the software of users runs - _the user environment_.
If you are installing TLJH for the first time, the user environment will be
setup initially with Python 3.12 and some other packages described in
[tljh/requirements-user-env-extras.txt].
If you are upgrading to this version of TLJH, the bare minimum is changed in the
user environment. The hub environment's dependencies are on the other hand
always upgraded to the latest version within the specified version range defined
in [tljh/requirements-hub-env.txt] and seen below.
[tljh/requirements-user-env-extras.txt]: https://github.com/jupyterhub/the-littlest-jupyterhub/blob/2.0.0/tljh/requirements-user-env-extras.txt
[tljh/requirements-hub-env.txt]: https://github.com/jupyterhub/the-littlest-jupyterhub/blob/2.0.0/tljh/requirements-hub-env.txt
The changes in the respective environments between TLJH version 1.0.0 and 2.0.0
are summarized below.
| Dependency changes in the _hub environment_ | Version in 1.0.0 | Version in 2.0.0 | Changelog link | Note |
| ------------------------------------------------------------------------------ | ---------------- | ---------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| [jupyterhub](https://github.com/jupyterhub/jupyterhub) | >=4.0.2,<5 | >=5.2.0,<6 | [Changelog](https://jupyterhub.readthedocs.io/en/stable/reference/changelog.html) | Running in the `jupyterhub` systemd service |
| [traefik](https://github.com/traefik/traefik) | 2.10.1 | 3.1.4 | [Changelog](https://github.com/traefik/traefik/blob/master/CHANGELOG.md) | Running in the `traefik` systemd service |
| [traefik-proxy](https://github.com/jupyterhub/traefik-proxy) | >=1.1.0,<2 | 2.\* | [Changelog](https://jupyterhub-traefik-proxy.readthedocs.io/en/latest/changelog.html) | Run by jupyterhub, controls `traefik` |
| [systemdspawner](https://github.com/jupyterhub/systemdspawner) | >=1.0.1,<2 | >=1.0.2,<2 | [Changelog](https://github.com/jupyterhub/systemdspawner/blob/master/CHANGELOG.md) | Run by jupyterhub, controls user servers via systemd |
| [jupyterhub-idle-culler](https://github.com/jupyterhub/jupyterhub-idle-culler) | >=1.2.1,<2 | >=1.4.0,<2 | [Changelog](https://github.com/jupyterhub/jupyterhub-idle-culler/blob/main/CHANGELOG.md) | Run by jupyterhub, stops inactivate servers etc. |
| [firstuseauthenticator](https://github.com/jupyterhub/firstuseauthenticator) | >=1.0.0,<2 | 1.1.0,<2 | [Changelog](https://oauthenticator.readthedocs.io/en/latest/reference/changelog.html) | An optional way to authenticate users |
| [tmpauthenticator](https://github.com/jupyterhub/tmpauthenticator) | >=1.0.0,<2 | 1.0.0,<2 | [Changelog](https://github.com/jupyterhub/tmpauthenticator/blob/HEAD/CHANGELOG.md) | An optional way to authenticate users |
| [nativeauthenticator](https://github.com/jupyterhub/nativeauthenticator) | >=1.2.0,<2 | >=1.3.0,<2 | [Changelog](https://github.com/jupyterhub/nativeauthenticator/blob/HEAD/CHANGELOG.md) | An optional way to authenticate users |
| [oauthenticator](https://github.com/jupyterhub/oauthenticator) | >=16.0.4,<17 | >=17.1.0,<18 | [Changelog](https://oauthenticator.readthedocs.io/en/latest/reference/changelog.html) | An optional way to authenticate users |
| [ldapauthenticator](https://github.com/jupyterhub/ldapauthenticator) | >=1.3.2,<2 | ==2.0.0 | [Changelog](https://github.com/jupyterhub/ldapauthenticator/blob/HEAD/CHANGELOG.md) | An optional way to authenticate users |
| [pip](https://github.com/pypa/pip) | >=23.1.2 | >=23.1.2 | [Changelog](https://pip.pypa.io/en/stable/news/) | - |
| Dependency changes in the _user environment_ | Version in 1.0.0 | Version in upgrade to 2.0.0 | Version in fresh install of 2.0.0 | Changelog link | Note |
| -------------------------------------------------------- | ---------------- | --------------------------- | --------------------------------- | --------------------------------------------------------------------------------- | ------------------------ |
| [jupyterhub](https://github.com/jupyterhub/jupyterhub) | >=4.0.2,<5 | >=5.2.0,<6 | >=5.2.0,<6 | [Changelog](https://jupyterhub.readthedocs.io/en/stable/reference/changelog.html) | Always upgraded. |
| [pip](https://github.com/pypa/pip) | >=23.1.2 | >=23.1.2 | >=24.2 | [Changelog](https://pip.pypa.io/en/stable/news/) | Only upgraded if needed. |
| [conda](https://docs.conda.io/projects/conda/en/stable/) | >=4.10.0 | >=4.10.0 | ==24.7.1 | [Changelog](https://docs.conda.io/projects/conda/en/stable/release-notes.html) | Only upgraded if needed. |
| [mamba](https://mamba.readthedocs.io/en/latest/) | >=0.16.0 | >=0.16.0 | ==1.5.9 | [Changelog](https://github.com/mamba-org/mamba/blob/main/CHANGELOG.md) | Only upgraded if needed. |
#### New features added
- jupyterhub 5 [#989](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/989) ([@minrk](https://github.com/minrk), [@manics](https://github.com/manics))
- Validate tljh specific config [#962](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/962) ([@jrdnbradford](https://github.com/jrdnbradford), [@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk))
- Add the ability to define conda channels in plugins via `tljh_extra_user_conda_channels` [#942](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/942) ([@yuvipanda](https://github.com/yuvipanda), [@consideRatio](https://github.com/consideRatio))
#### Bugs fixed
- hub env: avoid installing pycurl using wheel with an issue [#1006](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/1006) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk))
- fix `-m` invocation of jupyterhub [#988](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/988) ([@minrk](https://github.com/minrk), [@manics](https://github.com/manics))
- Re-install conda/mamba for every tljh upgrade (doesn't imply upgrade) [#968](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/968) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk))
- Add missing oauthenticator dependency for AzureADOAuthenticator [#959](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/959) ([@consideRatio](https://github.com/consideRatio))
#### Maintenance and upkeep improvements
- Update jupyterhub pinning to >=5.2.0,<6 from ==5.1.0 [#1008](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/1008) ([@consideRatio](https://github.com/consideRatio))
- hub env: pin to jupyterhub 5.1.0 [#1007](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/1007) ([@consideRatio](https://github.com/consideRatio))
- hub env: bump to ldapauthenticator 2.0.0 and other lower bounds [#1004](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/1004) ([@consideRatio](https://github.com/consideRatio))
- Bump the requirements-user-env-extras.txt lower version bounds [#1002](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/1002) ([@consideRatio](https://github.com/consideRatio))
- Update traefik from 2.10.1 to 3.1.4 [#1001](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/1001) ([@consideRatio](https://github.com/consideRatio))
- Update to install miniforge 24.7.1-2 from 24.7.1-0 [#999](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/999) ([@consideRatio](https://github.com/consideRatio))
- Drop ubuntu 20.04, require py39, traefik-proxy v2, and ldapauthenticator v2 [#998](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/998) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk))
- consolidate lock file handling [#994](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/994) ([@minrk](https://github.com/minrk), [@consideRatio](https://github.com/consideRatio), [@jrdnbradford](https://github.com/jrdnbradford))
- update oauthenticator to 17 [#992](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/992) ([@minrk](https://github.com/minrk), [@consideRatio](https://github.com/consideRatio))
- Update base user environment to miniforge 24.7.1-0 (Python 3.12) [#990](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/990) ([@minrk](https://github.com/minrk), [@consideRatio](https://github.com/consideRatio))
- Add TLJH config lockfile [#976](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/976) ([@jrdnbradford](https://github.com/jrdnbradford), [@minrk](https://github.com/minrk), [@consideRatio](https://github.com/consideRatio))
- tests: fix to catch test failure earlier when they really happen [#975](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/975) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk))
#### Documentation improvements
- Remove mention about beta state [#1009](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/1009) ([@consideRatio](https://github.com/consideRatio))
- Added missing details on how to add custom domain from manual HTTPS configuration [#983](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/983) ([@josedaudi](https://github.com/josedaudi), [@yuvipanda](https://github.com/yuvipanda))
- Reword documentation sentence [#970](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/970) ([@davidalber](https://github.com/davidalber), [@consideRatio](https://github.com/consideRatio))
- Fix typo and replace word [#969](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/969) ([@davidalber](https://github.com/davidalber), [@consideRatio](https://github.com/consideRatio))
- Fix URL syntax in nativeauth.md [#949](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/949) ([@pdebuyl](https://github.com/pdebuyl), [@minrk](https://github.com/minrk))
- adapt install documentation for new /lab default interface [#935](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/935) ([@schwebke](https://github.com/schwebke), [@minrk](https://github.com/minrk))
#### Continuous integration improvements
- Test upgrade from 1.\* [#1003](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/1003) ([@manics](https://github.com/manics), [@minrk](https://github.com/minrk), [@consideRatio](https://github.com/consideRatio))
- ci: cache pip only when no container is used [#997](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/997) ([@consideRatio](https://github.com/consideRatio))
- ci: run unit tests in ubuntu-24.04 github actions environment as well [#993](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/993) ([@consideRatio](https://github.com/consideRatio))
- ci: add tests for debian 12 and ubuntu 24.04 [#967](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/967) ([@consideRatio](https://github.com/consideRatio))
- build(deps): bump actions/cache from 3 to 4 [#961](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/961) ([@consideRatio](https://github.com/consideRatio))
- build(deps): bump codecov/codecov-action from 3 to 4 [#960](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/960) ([@consideRatio](https://github.com/consideRatio))
- build(deps): bump actions/setup-python from 4 to 5 [#958](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/958) ([@consideRatio](https://github.com/consideRatio))
- build(deps): bump actions/checkout from 3 to 4 [#943](https://github.com/jupyterhub/the-littlest-jupyterhub/pull/943) ([@consideRatio](https://github.com/consideRatio))
## Contributors to this release
The following people contributed discussions, new ideas, code and documentation contributions, and review.
See [our definition of contributors](https://github-activity.readthedocs.io/en/latest/#how-does-this-tool-define-contributions-in-the-reports).
([GitHub contributors page for this release](https://github.com/jupyterhub/the-littlest-jupyterhub/graphs/contributors?from=2023-08-11&to=2024-10-21&type=c))
@consideRatio ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3AconsideRatio+updated%3A2023-08-11..2024-10-21&type=Issues)) | @davidalber ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Adavidalber+updated%3A2023-08-11..2024-10-21&type=Issues)) | @josedaudi ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Ajosedaudi+updated%3A2023-08-11..2024-10-21&type=Issues)) | @jrdnbradford ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Ajrdnbradford+updated%3A2023-08-11..2024-10-21&type=Issues)) | @kiliansinger ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Akiliansinger+updated%3A2023-08-11..2024-10-21&type=Issues)) | @manics ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Amanics+updated%3A2023-08-11..2024-10-21&type=Issues)) | @minrk ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Aminrk+updated%3A2023-08-11..2024-10-21&type=Issues)) | @MridulS ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3AMridulS+updated%3A2023-08-11..2024-10-21&type=Issues)) | @pdebuyl ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Apdebuyl+updated%3A2023-08-11..2024-10-21&type=Issues)) | @schwebke ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Aschwebke+updated%3A2023-08-11..2024-10-21&type=Issues)) | @yuvipanda ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fthe-littlest-jupyterhub+involves%3Ayuvipanda+updated%3A2023-08-11..2024-10-21&type=Issues))
## 1.0 ## 1.0
### 1.0.0 - 2023-08-11 ### 1.0.0 - 2023-08-11

View File

@@ -18,12 +18,12 @@ the idle culler configuration can be extended beyond tljh-config options, using
## Default settings ## Default settings
By default, JupyterHub will ping the user notebook servers every 60s to check their By default, JupyterHub will ping the user notebook servers every 10 min to check their
status. Every server found to be idle for more than 10 minutes will be culled. status. Every server found to be idle for more than 1 hour will be culled.
```python ```python
services.cull.every = 60 services.cull.every = 600
services.cull.timeout = 600 services.cull.timeout = 3600
``` ```
Because the servers don't have a maximum age set, an active server will not be shut down Because the servers don't have a maximum age set, an active server will not be shut down

View File

@@ -26,7 +26,7 @@ sudo rm -rf /opt/tljh/hub
## User environment ## User environment
By default, a `mambaforge` conda environment is installed in `/opt/tljh/user`. This contains By default, a `miniforge` conda environment is installed in `/opt/tljh/user`. This contains
the notebook interface used to launch all users, and the various packages available to all the notebook interface used to launch all users, and the various packages available to all
users. The environment is owned by the `root` user. JupyterHub admins may use users. The environment is owned by the `root` user. JupyterHub admins may use
to `sudo -E conda install` or `sudo -E pip install` packages into this environment. to `sudo -E conda install` or `sudo -E pip install` packages into this environment.

View File

@@ -227,7 +227,7 @@ it after an argument like `remove-item` gives information about this specific co
```bash ```bash
sudo tljh-config --help sudo tljh-config --help
usage: tljh-config [-h] [--config-path CONFIG_PATH] {show,unset,set,add-item,remove-item,reload} ... usage: tljh-config [-h] [--config-path CONFIG_PATH] [--validate] [--no-validate] {show,unset,set,add-item,remove-item,reload} ...
positional arguments: positional arguments:
{show,unset,set,add-item,remove-item,reload} {show,unset,set,add-item,remove-item,reload}
@@ -238,10 +238,12 @@ positional arguments:
remove-item Remove a value from a list for a configuration property remove-item Remove a value from a list for a configuration property
reload Reload a component to apply configuration change reload Reload a component to apply configuration change
optional arguments: options:
-h, --help show this help message and exit -h, --help show this help message and exit
--config-path CONFIG_PATH --config-path CONFIG_PATH
Path to TLJH config.yaml file Path to TLJH config.yaml file
--validate Validate the TLJH config
--no-validate Do not validate the TLJH config
``` ```
```bash ```bash

View File

@@ -22,11 +22,9 @@ container technology in administering user sessions.
The choice between TLJH and Z2JH ultimately comes down to only a few questions: The choice between TLJH and Z2JH ultimately comes down to only a few questions:
1. Do you want your hub and all users to live on a **single, larger machine** vs. spreading users on a **cluster of smaller machines** that are scaled up or down? 1. Do you want your hub and all users to live on a **single, larger machine** vs. spreading users on a **cluster of smaller machines** that are scaled up or down?
- If you can use a single machine, we recommend **The Littlest JupyterHub**. - If you can use a single machine, we recommend **The Littlest JupyterHub**.
- If you wish to use multiple machines, we recommend **Zero to JupyterHub for Kubernetes**. - If you wish to use multiple machines, we recommend **Zero to JupyterHub for Kubernetes**.
2. Do you **need to use container technology**? 2. Do you **need to use container technology**?
- If no, we recommend **The Littlest JupyterHub**. - If no, we recommend **The Littlest JupyterHub**.
- If yes, we recommend **Zero to JupyterHub for Kubernetes**. - If yes, we recommend **Zero to JupyterHub for Kubernetes**.

View File

@@ -81,7 +81,6 @@ easier. Here are some very basic tips on effective `journalctl` usage.
[less](<https://en.wikipedia.org/wiki/Less_(Unix)>). This allows you to [less](<https://en.wikipedia.org/wiki/Less_(Unix)>). This allows you to
scroll up / down, search for specific words, etc. Some common keyboard shortcuts scroll up / down, search for specific words, etc. Some common keyboard shortcuts
are: are:
- Arrow keys to move up / down / left / right - Arrow keys to move up / down / left / right
- `G` to navigate to the end of the logs - `G` to navigate to the end of the logs
- `g` to navigate to the start of the logs - `g` to navigate to the start of the logs

View File

@@ -1,5 +1,5 @@
# Systemd inside a Docker container, for CI only # Systemd inside a Docker container, for CI and local development
ARG BASE_IMAGE=ubuntu:20.04 ARG BASE_IMAGE=ubuntu:22.04
FROM $BASE_IMAGE FROM $BASE_IMAGE
# DEBIAN_FRONTEND is set to avoid being asked for input and hang during build: # DEBIAN_FRONTEND is set to avoid being asked for input and hang during build:
@@ -28,9 +28,4 @@ RUN systemctl set-default multi-user.target
STOPSIGNAL SIGRTMIN+3 STOPSIGNAL SIGRTMIN+3
# Uncomment these lines for a development install
#ENV TLJH_BOOTSTRAP_DEV=yes
#ENV TLJH_BOOTSTRAP_PIP_SPEC=/srv/src
#ENV PATH=/opt/tljh/hub/bin:${PATH}
CMD ["/bin/bash", "-c", "exec /lib/systemd/systemd --log-target=journal 3>&1"] CMD ["/bin/bash", "-c", "exec /lib/systemd/systemd --log-target=journal 3>&1"]

View File

@@ -1,17 +1,25 @@
""" """
Simplest plugin that exercises all the hooks defined in tljh/hooks.py. Simplest plugin that exercises all the hooks defined in tljh/hooks.py.
""" """
from tljh.hooks import hookimpl from tljh.hooks import hookimpl
@hookimpl @hookimpl
def tljh_extra_user_conda_packages(): def tljh_extra_user_conda_packages():
return ["tqdm"] # tqdm installs from the conda-forge channel (https://conda-forge.org/packages/)
# csvtk installs from the bioconda channel (https://bioconda.github.io/conda-package_index.html)
return ["tqdm", "csvtk"]
@hookimpl
def tljh_extra_user_conda_channels():
return ["conda-forge", "bioconda"]
@hookimpl @hookimpl
def tljh_extra_user_pip_packages(): def tljh_extra_user_pip_packages():
return ["django"] return ["simplejson"]
@hookimpl @hookimpl

View File

@@ -9,6 +9,7 @@ FIXME: The last test stands out and could be part of the other tests, and the
first two could be more like unit tests. Ideally, this file is first two could be more like unit tests. Ideally, this file is
significantly reduced. significantly reduced.
""" """
import concurrent.futures import concurrent.futures
import os import os
import subprocess import subprocess
@@ -84,9 +85,9 @@ def test_ubuntu_too_old():
""" """
Error with a useful message when running in older Ubuntu Error with a useful message when running in older Ubuntu
""" """
output = _run_bootstrap_in_container("ubuntu:18.04", False) output = _run_bootstrap_in_container("ubuntu:20.04", False)
_stop_container() _stop_container()
assert output.stdout == "The Littlest JupyterHub requires Ubuntu 20.04 or higher\n" assert output.stdout == "The Littlest JupyterHub requires Ubuntu 22.04 or higher\n"
assert output.returncode == 1 assert output.returncode == 1

View File

@@ -9,9 +9,12 @@ def test_serverextensions():
# jupyter-serverextension writes to stdout and stderr weirdly # jupyter-serverextension writes to stdout and stderr weirdly
proc = subprocess.run( proc = subprocess.run(
["/opt/tljh/user/bin/jupyter-server", "extension", "list", "--sys-prefix"], ["/opt/tljh/user/bin/jupyter-server", "extension", "list", "--sys-prefix"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
) )
output = proc.stdout.decode()
extensions = [ extensions = [
"jupyterlab", "jupyterlab",
"nbgitpuller", "nbgitpuller",
@@ -19,7 +22,7 @@ def test_serverextensions():
] ]
for e in extensions: for e in extensions:
assert e in proc.stderr.decode() assert e in output, f"'{e}' not found in server extensions: {output}"
def test_labextensions(): def test_labextensions():
@@ -29,8 +32,7 @@ def test_labextensions():
# jupyter-labextension writes to stdout and stderr weirdly # jupyter-labextension writes to stdout and stderr weirdly
proc = subprocess.run( proc = subprocess.run(
["/opt/tljh/user/bin/jupyter-labextension", "list"], ["/opt/tljh/user/bin/jupyter-labextension", "list"],
stderr=subprocess.PIPE, capture_output=True,
stdout=subprocess.PIPE,
) )
extensions = [ extensions = [

View File

@@ -33,7 +33,7 @@ def test_hub_version():
r = requests.get(HUB_URL + "/hub/api") r = requests.get(HUB_URL + "/hub/api")
r.raise_for_status() r.raise_for_status()
info = r.json() info = r.json()
assert V("4") <= V(info["version"]) <= V("5") assert V("5.1") <= V(info["version"]) <= V("6")
async def test_user_code_execute(): async def test_user_code_execute():
@@ -59,9 +59,9 @@ async def test_user_code_execute():
async with User(username, HUB_URL, partial(login_dummy, password="")) as u: async with User(username, HUB_URL, partial(login_dummy, password="")) as u:
assert await u.login() assert await u.login()
await u.ensure_server_simulate(timeout=60, spawn_refresh_time=5) assert await u.ensure_server_simulate(timeout=60, spawn_refresh_time=5)
await u.start_kernel() assert await u.start_kernel()
await u.assert_code_output("5 * 4", "20", 5, 5) assert await u.assert_code_output("5 * 4", "20", 5, 5)
async def test_user_server_started_with_custom_base_url(): async def test_user_server_started_with_custom_base_url():

View File

@@ -1,4 +1,5 @@
"""tests for the proxy""" """tests for the proxy"""
import os import os
import shutil import shutil
import ssl import ssl

View File

@@ -2,6 +2,7 @@
Test the plugin in integration-tests/plugins/simplest that makes use of all tljh Test the plugin in integration-tests/plugins/simplest that makes use of all tljh
recognized plugin hooks that are defined in tljh/hooks.py. recognized plugin hooks that are defined in tljh/hooks.py.
""" """
import os import os
import subprocess import subprocess
@@ -19,13 +20,24 @@ def test_tljh_extra_user_conda_packages():
def test_tljh_extra_user_pip_packages(): def test_tljh_extra_user_pip_packages():
subprocess.check_call([f"{USER_ENV_PREFIX}/bin/python3", "-c", "import django"]) subprocess.check_call([f"{USER_ENV_PREFIX}/bin/python3", "-c", "import simplejson"])
def test_tljh_extra_hub_pip_packages(): def test_tljh_extra_hub_pip_packages():
subprocess.check_call([f"{HUB_ENV_PREFIX}/bin/python3", "-c", "import there"]) subprocess.check_call([f"{HUB_ENV_PREFIX}/bin/python3", "-c", "import there"])
def test_conda_packages():
"""
Test extra user conda packages are installed from multiple channels.
- tqdm installs from the conda-forge channel (https://conda-forge.org/packages/)
- csvtk installs from the bioconda channel (https://bioconda.github.io/conda-package_index.html)
"""
subprocess.check_call([f"{USER_ENV_PREFIX}/bin/python3", "-c", "import tqdm"])
subprocess.check_call([f"{USER_ENV_PREFIX}/bin/csvtk", "cat", "--help"])
def test_tljh_extra_apt_packages(): def test_tljh_extra_apt_packages():
assert os.path.exists("/usr/games/sl") assert os.path.exists("/usr/games/sl")

View File

@@ -25,12 +25,10 @@ profile = "black"
# target-version should be all supported versions, see # target-version should be all supported versions, see
# https://github.com/psf/black/issues/751#issuecomment-473066811 # https://github.com/psf/black/issues/751#issuecomment-473066811
target_version = [ target_version = [
"py36",
"py37",
"py38",
"py39", "py39",
"py310", "py310",
"py311", "py311",
"py312",
] ]
@@ -67,7 +65,7 @@ omit = [
github_url = "https://github.com/jupyterhub/the-littlest-jupyterhub" github_url = "https://github.com/jupyterhub/the-littlest-jupyterhub"
[tool.tbump.version] [tool.tbump.version]
current = "1.0.0" current = "2.0.1.dev"
regex = ''' regex = '''
(?P<major>\d+) (?P<major>\d+)
\. \.

View File

@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
setup( setup(
name="the-littlest-jupyterhub", name="the-littlest-jupyterhub",
version="1.0.0", version="2.0.1.dev",
description="A small JupyterHub distribution", description="A small JupyterHub distribution",
url="https://github.com/jupyterhub/the-littlest-jupyterhub", url="https://github.com/jupyterhub/the-littlest-jupyterhub",
author="Jupyter Development Team", author="Jupyter Development Team",
@@ -10,14 +10,16 @@ setup(
license="3 Clause BSD", license="3 Clause BSD",
packages=find_packages(), packages=find_packages(),
include_package_data=True, include_package_data=True,
python_requires=">=3.9",
install_requires=[ install_requires=[
"ruamel.yaml==0.17.*", "ruamel.yaml==0.18.*",
"jinja2", "jinja2",
"pluggy==1.*", "pluggy==1.*",
"backoff", "backoff",
"filelock",
"requests", "requests",
"bcrypt", "bcrypt",
"jupyterhub-traefik-proxy==1.*", "jupyterhub-traefik-proxy==2.*",
], ],
entry_points={ entry_points={
"console_scripts": [ "console_scripts": [

View File

@@ -1,4 +1,5 @@
"""pytest fixtures""" """pytest fixtures"""
import os import os
import types import types
from importlib import reload from importlib import reload

View File

@@ -1,6 +1,7 @@
""" """
Test conda commandline wrappers Test conda commandline wrappers
""" """
import os import os
import subprocess import subprocess
import tempfile import tempfile
@@ -13,9 +14,9 @@ from tljh import conda, installer
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def prefix(): def prefix():
""" """
Provide a temporary directory with a mambaforge conda environment Provide a temporary directory with a conda environment
""" """
installer_url, checksum = installer._mambaforge_url() installer_url, checksum = installer._miniforge_url()
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
with conda.download_miniconda_installer( with conda.download_miniconda_installer(
installer_url, checksum installer_url, checksum
@@ -33,6 +34,15 @@ def test_ensure_packages(prefix):
subprocess.check_call([os.path.join(prefix, "bin", "python"), "-c", "import numpy"]) subprocess.check_call([os.path.join(prefix, "bin", "python"), "-c", "import numpy"])
def test_ensure_channel_packages(prefix):
"""
Test installing packages in conda environment
"""
conda.ensure_conda_packages(prefix, ["csvtk"], channels=("conda-forge", "bioconda"))
# Throws an error if this fails
subprocess.check_call([os.path.join(prefix, "bin", "csvtk"), "cat", "--help"])
def test_ensure_pip_packages(prefix): def test_ensure_pip_packages(prefix):
""" """
Test installing pip packages in conda environment Test installing pip packages in conda environment

View File

@@ -143,21 +143,24 @@ def test_remove_from_config_error():
def test_reload_hub(): def test_reload_hub():
with mock.patch("tljh.systemd.restart_service") as restart_service, mock.patch( with (
"tljh.systemd.check_service_active" mock.patch("tljh.systemd.restart_service") as restart_service,
) as check_active, mock.patch("tljh.config.check_hub_ready") as check_ready: mock.patch("tljh.systemd.check_service_active") as check_active,
mock.patch("tljh.config.check_hub_ready") as check_ready,
):
config.reload_component("hub") config.reload_component("hub")
assert restart_service.called_with("jupyterhub") restart_service.assert_called_with("jupyterhub")
assert check_active.called_with("jupyterhub") check_active.assert_called_with("jupyterhub")
def test_reload_proxy(tljh_dir): def test_reload_proxy(tljh_dir):
with mock.patch("tljh.systemd.restart_service") as restart_service, mock.patch( with (
"tljh.systemd.check_service_active" mock.patch("tljh.systemd.restart_service") as restart_service,
) as check_active: mock.patch("tljh.systemd.check_service_active") as check_active,
):
config.reload_component("proxy") config.reload_component("proxy")
assert restart_service.called_with("traefik") restart_service.assert_called_with("traefik")
assert check_active.called_with("traefik") check_active.assert_called_with("traefik")
assert os.path.exists(os.path.join(config.STATE_DIR, "traefik.toml")) assert os.path.exists(os.path.join(config.STATE_DIR, "traefik.toml"))
@@ -217,7 +220,8 @@ def test_cli_remove_int(tljh_dir):
("x", "x"), ("x", "x"),
("1x", "1x"), ("1x", "1x"),
("1.2x", "1.2x"), ("1.2x", "1.2x"),
(None, None), ("None", None),
("none", None),
("", ""), ("", ""),
], ],
) )

View File

@@ -0,0 +1,13 @@
"""
Unit test functions to test JSON Schema validation
"""
import jsonschema
from tljh.config_schema import config_schema
def test_valid_config_json_schema():
"""Validate that the JSON schema fits its $schema specification"""
validator_class = jsonschema.validators.validator_for(config_schema)
validator_class.check_schema(config_schema)

View File

@@ -1,6 +1,7 @@
""" """
Unit test functions in installer.py Unit test functions in installer.py
""" """
import json import json
import os import os
from subprocess import PIPE, run from subprocess import PIPE, run
@@ -45,12 +46,12 @@ def test_ensure_admins(tljh_dir, admins, expected_config):
def setup_conda(distro, version, prefix): def setup_conda(distro, version, prefix):
"""Install mambaforge or miniconda in a prefix""" """Install miniforge or miniconda in a prefix"""
if distro == "mambaforge": if distro == "mambaforge":
installer_url, _ = installer._mambaforge_url(version) installer_url, _ = installer._miniforge_url(version)
installer_url = installer_url.replace("Miniforge3", "Mambaforge")
elif distro == "miniforge": elif distro == "miniforge":
installer_url, _ = installer._mambaforge_url(version) installer_url, _ = installer._miniforge_url(version)
installer_url = installer_url.replace("Mambaforge", "Miniforge3")
elif distro == "miniconda": elif distro == "miniconda":
arch = os.uname().machine arch = os.uname().machine
installer_url = ( installer_url = (
@@ -123,9 +124,9 @@ def _specifier(version):
None, None,
None, None,
{ {
"python": "3.10.*", "python": "3.12.*",
"conda": "23.1.0", "conda": "24.7.1",
"mamba": "1.4.1", "mamba": "1.5.9",
}, },
), ),
# previous install, 1.0 # previous install, 1.0
@@ -160,12 +161,6 @@ def _specifier(version):
"mamba": ">=1.1.0", "mamba": ">=1.1.0",
}, },
), ),
# too-old Python (3.7), abort
(
"miniconda",
"4.7.10",
ValueError,
),
], ],
) )
def test_ensure_user_environment( def test_ensure_user_environment(

View File

@@ -1,6 +1,7 @@
""" """
Unit test functions in installer.py Unit test functions in installer.py
""" """
import os import os
from datetime import date from datetime import date

View File

@@ -1,6 +1,7 @@
""" """
Test functions for normalizing various kinds of values Test functions for normalizing various kinds of values
""" """
from tljh.normalize import generate_system_username from tljh.normalize import generate_system_username

View File

@@ -1,4 +1,5 @@
"""Test traefik configuration""" """Test traefik configuration"""
import os import os
import pytest import pytest

View File

@@ -1,6 +1,7 @@
""" """
Test wrappers in tljw.user module Test wrappers in tljw.user module
""" """
import grp import grp
import os import os
import os.path import os.path

View File

@@ -1,6 +1,7 @@
""" """
Utilities for working with the apt package manager Utilities for working with the apt package manager
""" """
import os import os
import subprocess import subprocess

View File

@@ -1,6 +1,7 @@
""" """
Wrap conda commandline program Wrap conda commandline program
""" """
import contextlib import contextlib
import hashlib import hashlib
import json import json
@@ -98,9 +99,11 @@ def install_miniconda(installer_path, prefix):
fix_permissions(prefix) fix_permissions(prefix)
def ensure_conda_packages(prefix, packages, force_reinstall=False): def ensure_conda_packages(
prefix, packages, channels=("conda-forge",), force_reinstall=False
):
""" """
Ensure packages (from conda-forge) are installed in the conda prefix. Ensure packages (from channels) are installed in the conda prefix.
Note that conda seem to update dependencies by default, so there is probably Note that conda seem to update dependencies by default, so there is probably
no need to have a update parameter exposed for this function. no need to have a update parameter exposed for this function.
@@ -117,13 +120,14 @@ def ensure_conda_packages(prefix, packages, force_reinstall=False):
# avoids problems with RemoveError upgrading conda from old versions # avoids problems with RemoveError upgrading conda from old versions
cmd += ["--force-reinstall"] cmd += ["--force-reinstall"]
for channel in channels:
cmd += ["-c", channel]
abspath = os.path.abspath(prefix) abspath = os.path.abspath(prefix)
utils.run_subprocess( utils.run_subprocess(
cmd cmd
+ [ + [
"-c",
"conda-forge", # Make customizable if we ever need to
"--prefix", "--prefix",
abspath, abspath,
] ]

View File

@@ -18,9 +18,11 @@ import re
import sys import sys
import time import time
from collections.abc import Mapping, Sequence from collections.abc import Mapping, Sequence
from contextlib import contextmanager
from copy import deepcopy from copy import deepcopy
import requests import requests
from filelock import FileLock, Timeout
from .yaml import yaml from .yaml import yaml
@@ -32,6 +34,22 @@ CONFIG_DIR = os.path.join(INSTALL_PREFIX, "config")
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.yaml") CONFIG_FILE = os.path.join(CONFIG_DIR, "config.yaml")
@contextmanager
def config_file_lock(config_path, timeout=1):
"""Context manager to acquire the config file lock"""
lock_file = f"{config_path}.lock"
try:
with FileLock(lock_file).acquire(timeout=timeout):
yield
except Timeout:
print(
f"Another instance of tljh-config holds the lock {lock_file}.",
file=sys.stderr,
)
sys.exit(1)
def set_item_in_config(config, property_path, value): def set_item_in_config(config, property_path, value):
""" """
Set key at property_path to value in config & return new config. Set key at property_path to value in config & return new config.
@@ -154,92 +172,102 @@ def remove_item_from_config(config, property_path, value):
return config_copy return config_copy
def validate_config(config, validate):
"""
Validate changes to the config with tljh-config against the schema
"""
import jsonschema
from .config_schema import config_schema
try:
jsonschema.validate(instance=config, schema=config_schema)
except jsonschema.exceptions.ValidationError as e:
if validate:
print(
f"Config validation error: {e.message}.\n"
"You can still apply this change without validation by re-running your command with the --no-validate flag.\n"
"If you think this validation error is incorrect, please report it to https://github.com/jupyterhub/the-littlest-jupyterhub/issues.",
file=sys.stderr,
)
sys.exit(1)
def show_config(config_path): def show_config(config_path):
""" """
Pretty print config from given config_path Pretty print config from given config_path
""" """
try: config = get_current_config(config_path)
with open(config_path) as f:
config = yaml.load(f)
except FileNotFoundError:
config = {}
yaml.dump(config, sys.stdout) yaml.dump(config, sys.stdout)
def set_config_value(config_path, key_path, value): def set_config_value(config_path, key_path, value, validate=True):
""" """
Set key at key_path in config_path to value Set key at key_path in config_path to value
""" """
# FIXME: Have a file lock here with config_file_lock(config_path):
# FIXME: Validate schema here config = get_current_config(config_path)
try: config = set_item_in_config(config, key_path, value)
with open(config_path) as f: validate_config(config, validate)
config = yaml.load(f)
except FileNotFoundError:
config = {}
config = set_item_in_config(config, key_path, value) with open(config_path, "w") as f:
yaml.dump(config, f)
with open(config_path, "w") as f:
yaml.dump(config, f)
def unset_config_value(config_path, key_path): def unset_config_value(config_path, key_path, validate=True):
""" """
Unset key at key_path in config_path Unset key at key_path in config_path
""" """
# FIXME: Have a file lock here with config_file_lock(config_path):
# FIXME: Validate schema here config = get_current_config(config_path)
try: config = unset_item_from_config(config, key_path)
with open(config_path) as f: validate_config(config, validate)
config = yaml.load(f)
except FileNotFoundError:
config = {}
config = unset_item_from_config(config, key_path) with open(config_path, "w") as f:
yaml.dump(config, f)
with open(config_path, "w") as f:
yaml.dump(config, f)
def add_config_value(config_path, key_path, value): def add_config_value(config_path, key_path, value, validate=True):
""" """
Add value to list at key_path Add value to list at key_path
""" """
# FIXME: Have a file lock here with config_file_lock(config_path):
# FIXME: Validate schema here config = get_current_config(config_path)
try: config = add_item_to_config(config, key_path, value)
with open(config_path) as f: validate_config(config, validate)
config = yaml.load(f)
except FileNotFoundError:
config = {}
config = add_item_to_config(config, key_path, value) with open(config_path, "w") as f:
yaml.dump(config, f)
with open(config_path, "w") as f:
yaml.dump(config, f)
def remove_config_value(config_path, key_path, value): def remove_config_value(config_path, key_path, value, validate=True):
""" """
Remove value from list at key_path Remove value from list at key_path
""" """
# FIXME: Have a file lock here with config_file_lock(config_path):
# FIXME: Validate schema here config = get_current_config(config_path)
config = remove_item_from_config(config, key_path, value)
validate_config(config, validate)
with open(config_path, "w") as f:
yaml.dump(config, f)
def get_current_config(config_path):
"""
Retrieve the current config at config_path
"""
try: try:
with open(config_path) as f: with open(config_path) as f:
config = yaml.load(f) return yaml.load(f)
except FileNotFoundError: except FileNotFoundError:
config = {} return {}
config = remove_item_from_config(config, key_path, value)
with open(config_path, "w") as f:
yaml.dump(config, f)
def check_hub_ready(): def check_hub_ready():
"""
Checks that hub is running.
"""
from .configurer import load_config from .configurer import load_config
base_url = load_config()["base_url"] base_url = load_config()["base_url"]
@@ -289,8 +317,8 @@ def reload_component(component):
def parse_value(value_str): def parse_value(value_str):
"""Parse a value string""" """Parse a value string"""
if value_str is None: if value_str.lower() == "none":
return value_str return None
if re.match(r"^\d+$", value_str): if re.match(r"^\d+$", value_str):
return int(value_str) return int(value_str)
elif re.match(r"^\d+\.\d*$", value_str): elif re.match(r"^\d+\.\d*$", value_str):
@@ -336,6 +364,18 @@ def main(argv=None):
argparser.add_argument( argparser.add_argument(
"--config-path", default=CONFIG_FILE, help="Path to TLJH config.yaml file" "--config-path", default=CONFIG_FILE, help="Path to TLJH config.yaml file"
) )
argparser.add_argument(
"--validate", action="store_true", help="Validate the TLJH config"
)
argparser.add_argument(
"--no-validate",
dest="validate",
action="store_false",
help="Do not validate the TLJH config",
)
argparser.set_defaults(validate=True)
subparsers = argparser.add_subparsers(dest="action") subparsers = argparser.add_subparsers(dest="action")
show_parser = subparsers.add_parser("show", help="Show current configuration") show_parser = subparsers.add_parser("show", help="Show current configuration")
@@ -383,13 +423,19 @@ def main(argv=None):
if args.action == "show": if args.action == "show":
show_config(args.config_path) show_config(args.config_path)
elif args.action == "set": elif args.action == "set":
set_config_value(args.config_path, args.key_path, parse_value(args.value)) set_config_value(
args.config_path, args.key_path, parse_value(args.value), args.validate
)
elif args.action == "unset": elif args.action == "unset":
unset_config_value(args.config_path, args.key_path) unset_config_value(args.config_path, args.key_path, args.validate)
elif args.action == "add-item": elif args.action == "add-item":
add_config_value(args.config_path, args.key_path, parse_value(args.value)) add_config_value(
args.config_path, args.key_path, parse_value(args.value), args.validate
)
elif args.action == "remove-item": elif args.action == "remove-item":
remove_config_value(args.config_path, args.key_path, parse_value(args.value)) remove_config_value(
args.config_path, args.key_path, parse_value(args.value), args.validate
)
elif args.action == "reload": elif args.action == "reload":
reload_component(args.component) reload_component(args.component)
else: else:

130
tljh/config_schema.py Normal file
View File

@@ -0,0 +1,130 @@
"""
The schema against which the TLJH config file can be validated.
Validation occurs when changing values with tljh-config.
"""
config_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Littlest JupyterHub YAML config file",
"definitions": {
"BaseURL": {
"type": "string",
},
"Users": {
"type": "object",
"additionalProperties": False,
"properties": {
"extra_user_groups": {"type": "object", "items": {"type": "string"}},
"allowed": {"type": "array", "items": {"type": "string"}},
"banned": {"type": "array", "items": {"type": "string"}},
"admin": {"type": "array", "items": {"type": "string"}},
},
},
"Services": {
"type": "object",
"properties": {
"cull": {
"type": "object",
"additionalProperties": False,
"properties": {
"enabled": {"type": "boolean"},
"timeout": {"type": "integer"},
"every": {"type": "integer"},
"concurrency": {"type": "integer"},
"users": {"type": "boolean"},
"max_age": {"type": "integer"},
"remove_named_servers": {"type": "boolean"},
},
}
},
},
"HTTP": {
"type": "object",
"additionalProperties": False,
"properties": {
"address": {"type": "string", "format": "ipv4"},
"port": {"type": "integer"},
},
},
"HTTPS": {
"type": "object",
"additionalProperties": False,
"properties": {
"enabled": {"type": "boolean"},
"address": {"type": "string", "format": "ipv4"},
"port": {"type": "integer"},
"tls": {"$ref": "#/definitions/TLS"},
"letsencrypt": {"$ref": "#/definitions/LetsEncrypt"},
},
},
"LetsEncrypt": {
"type": "object",
"additionalProperties": False,
"properties": {
"email": {"type": "string", "format": "email"},
"domains": {
"type": "array",
"items": {"type": "string", "format": "hostname"},
},
"staging": {"type": "boolean"},
},
},
"TLS": {
"type": "object",
"additionalProperties": False,
"properties": {"key": {"type": "string"}, "cert": {"type": "string"}},
},
"Limits": {
"description": "User CPU and memory limits.",
"type": "object",
"additionalProperties": False,
"properties": {
"memory": {
"anyOf": [
{"type": "string"},
{"type": "null"},
]
},
"cpu": {
"anyOf": [
{"type": "number", "minimum": 0},
{"type": "null"},
]
},
},
},
"UserEnvironment": {
"type": "object",
"additionalProperties": False,
"properties": {
"default_app": {
"type": "string",
"enum": ["jupyterlab", "classic"],
"default": "jupyterlab",
}
},
},
"TraefikAPI": {
"type": "object",
"additionalProperties": False,
"properties": {
"ip": {"type": "string", "format": "ipv4"},
"port": {"type": "integer"},
"username": {"type": "string"},
"password": {"type": "string"},
},
},
},
"properties": {
"additionalProperties": False,
"base_url": {"$ref": "#/definitions/BaseURL"},
"user_environment": {"$ref": "#/definitions/UserEnvironment"},
"users": {"$ref": "#/definitions/Users"},
"limits": {"$ref": "#/definitions/Limits"},
"https": {"$ref": "#/definitions/HTTPS"},
"http": {"$ref": "#/definitions/HTTP"},
"traefik_api": {"$ref": "#/definitions/TraefikAPI"},
"services": {"$ref": "#/definitions/Services"},
},
}

View File

@@ -5,7 +5,6 @@ Config should never append or mutate, only set. Functions here could
be called many times per lifetime of a jupyterhub. be called many times per lifetime of a jupyterhub.
Traitlets that modify the startup of JupyterHub should not be here. Traitlets that modify the startup of JupyterHub should not be here.
FIXME: A strong feeling that JSON Schema should be involved somehow.
""" """
import os import os
@@ -199,6 +198,14 @@ def update_userlists(c, config):
""" """
users = config["users"] users = config["users"]
if (
not users["allowed"]
and config["auth"]["type"] == default["auth"]["type"]
and "allow_all" not in c.FirstUseAuthenticator
):
# _default_ authenticator, enable allow_all if no users specified
c.FirstUseAuthenticator.allow_all = True
c.Authenticator.allowed_users = set(users["allowed"]) c.Authenticator.allowed_users = set(users["allowed"])
c.Authenticator.blocked_users = set(users["banned"]) c.Authenticator.blocked_users = set(users["banned"])
c.Authenticator.admin_users = set(users["admin"]) c.Authenticator.admin_users = set(users["admin"])

View File

@@ -1,6 +1,7 @@
""" """
Hook specifications that pluggy plugins can override Hook specifications that pluggy plugins can override
""" """
import pluggy import pluggy
hookspec = pluggy.HookspecMarker("tljh") hookspec = pluggy.HookspecMarker("tljh")
@@ -14,6 +15,13 @@ def tljh_extra_user_conda_packages():
""" """
@hookspec
def tljh_extra_user_conda_channels():
"""
Return a list of conda channels to be used during user environment installation.
"""
@hookspec @hookspec
def tljh_extra_user_pip_packages(): def tljh_extra_user_pip_packages():
""" """

View File

@@ -115,7 +115,6 @@ def ensure_jupyterhub_package(prefix):
os.path.join(HERE, "requirements-hub-env.txt"), os.path.join(HERE, "requirements-hub-env.txt"),
upgrade=True, upgrade=True,
) )
traefik.ensure_traefik_binary(prefix)
def ensure_usergroups(): def ensure_usergroups():
@@ -136,13 +135,13 @@ def ensure_usergroups():
f.write("Defaults exempt_group = jupyterhub-admins\n") f.write("Defaults exempt_group = jupyterhub-admins\n")
# Install mambaforge using an installer from # Install miniforge using an installer from
# https://github.com/conda-forge/miniforge/releases # https://github.com/conda-forge/miniforge/releases
MAMBAFORGE_VERSION = "23.1.0-1" MINIFORGE_VERSION = "24.7.1-2"
# sha256 checksums # sha256 checksums
MAMBAFORGE_CHECKSUMS = { MINIFORGE_CHECKSUMS = {
"aarch64": "d9d89c9e349369702171008d9ee7c5ce80ed420e5af60bd150a3db4bf674443a", "aarch64": "7bf60bce50f57af7ea4500b45eeb401d9350011ab34c9c45f736647d8dba9021",
"x86_64": "cfb16c47dc2d115c8b114280aa605e322173f029fdb847a45348bf4bd23c62ab", "x86_64": "636f7faca2d51ee42b4640ce160c751a46d57621ef4bf14378704c87c5db4fe3",
} }
# minimum versions of packages # minimum versions of packages
@@ -156,22 +155,22 @@ MINIMUM_VERSIONS = {
} }
def _mambaforge_url(version=MAMBAFORGE_VERSION, arch=None): def _miniforge_url(version=MINIFORGE_VERSION, arch=None):
"""Return (URL, checksum) for mambaforge download for a given version and arch """Return (URL, checksum) for miniforge download for a given version and arch
Default values provided for both version and arch Default values provided for both version and arch
""" """
if arch is None: if arch is None:
arch = os.uname().machine arch = os.uname().machine
installer_url = "https://github.com/conda-forge/miniforge/releases/download/{v}/Mambaforge-{v}-Linux-{arch}.sh".format( installer_url = "https://github.com/conda-forge/miniforge/releases/download/{v}/Miniforge3-{v}-Linux-{arch}.sh".format(
v=version, v=version,
arch=arch, arch=arch,
) )
# Check system architecture, set appropriate installer checksum # Check system architecture, set appropriate installer checksum
checksum = MAMBAFORGE_CHECKSUMS.get(arch) checksum = MINIFORGE_CHECKSUMS.get(arch)
if not checksum: if not checksum:
raise ValueError( raise ValueError(
f"Unsupported architecture: {arch}. TLJH only supports {','.join(MAMBAFORGE_CHECKSUMS.keys())}" f"Unsupported architecture: {arch}. TLJH only supports {','.join(MINIFORGE_CHECKSUMS.keys())}"
) )
return installer_url, checksum return installer_url, checksum
@@ -198,7 +197,7 @@ def ensure_user_environment(user_requirements_txt_file):
raise OSError(msg) raise OSError(msg)
logger.info("Downloading & setting up user environment...") logger.info("Downloading & setting up user environment...")
installer_url, installer_sha256 = _mambaforge_url() installer_url, installer_sha256 = _miniforge_url()
with conda.download_miniconda_installer( with conda.download_miniconda_installer(
installer_url, installer_sha256 installer_url, installer_sha256
) as installer_path: ) as installer_path:
@@ -242,11 +241,10 @@ def ensure_user_environment(user_requirements_txt_file):
) )
to_upgrade.append(pkg) to_upgrade.append(pkg)
# force reinstall conda/mamba to ensure a basically consistent env # force reinstall conda/mamba to ensure conda doesn't raise error
# avoids issues with RemoveError: 'requests' is a dependency of conda # "RemoveError: 'requests' is a dependency of conda" later on when
# only do this for 'old' conda versions known to have a problem # conda/mamba is used to install/upgrade something
# we don't know how old, but we know 4.10 is affected and 23.1 is not if not is_fresh_install:
if not is_fresh_install and V(package_versions.get("conda", "0")) < V("23.1"):
# force-reinstall doesn't upgrade packages # force-reinstall doesn't upgrade packages
# it reinstalls them in-place # it reinstalls them in-place
# only reinstall packages already present # only reinstall packages already present
@@ -295,12 +293,16 @@ def ensure_user_environment(user_requirements_txt_file):
) )
if user_requirements_txt_file: if user_requirements_txt_file:
# FIXME: This currently fails hard, should fail soft and not abort installer try:
conda.ensure_pip_requirements( conda.ensure_pip_requirements(
USER_ENV_PREFIX, USER_ENV_PREFIX,
user_requirements_txt_file, user_requirements_txt_file,
upgrade=True, upgrade=True,
) )
except Exception as e:
logger.warning(
f"Failed to install requirements for user env from {user_requirements_txt_file}: {e}"
)
def ensure_admins(admin_password_list): def ensure_admins(admin_password_list):
@@ -450,13 +452,18 @@ def run_plugin_actions(plugin_manager):
# Install conda packages # Install conda packages
conda_packages = list(set(itertools.chain(*hook.tljh_extra_user_conda_packages()))) conda_packages = list(set(itertools.chain(*hook.tljh_extra_user_conda_packages())))
conda_channels = list(itertools.chain(*hook.tljh_extra_user_conda_channels()))
if len(conda_channels) == 0:
conda_channels = ("conda-forge",)
if conda_packages: if conda_packages:
logger.info( logger.info(
"Installing {} user conda packages collected from plugins: {}".format( "Installing {} user conda packages collected from plugins: {}".format(
len(conda_packages), " ".join(conda_packages) len(conda_packages), " ".join(conda_packages)
) )
) )
conda.ensure_conda_packages(USER_ENV_PREFIX, conda_packages) conda.ensure_conda_packages(
USER_ENV_PREFIX, conda_packages, channels=conda_channels
)
# Install pip packages # Install pip packages
user_pip_packages = list(set(itertools.chain(*hook.tljh_extra_user_pip_packages()))) user_pip_packages = list(set(itertools.chain(*hook.tljh_extra_user_pip_packages())))
@@ -527,11 +534,12 @@ def main():
ensure_admins(args.admin) ensure_admins(args.admin)
ensure_usergroups() ensure_usergroups()
if args.user_requirements_txt_url: if args.user_requirements_txt_url:
logger.info("installing packages from user_requirements_txt_url") logger.info("Installing packages from user_requirements_txt_url")
ensure_user_environment(args.user_requirements_txt_url) ensure_user_environment(args.user_requirements_txt_url)
logger.info("Setting up JupyterHub...") logger.info("Setting up JupyterHub...")
ensure_jupyterhub_package(HUB_ENV_PREFIX) ensure_jupyterhub_package(HUB_ENV_PREFIX)
traefik.ensure_traefik_binary(HUB_ENV_PREFIX)
# Stop the http server with the progress page before traefik starts # Stop the http server with the progress page before traefik starts
if args.progress_page_server_pid: if args.progress_page_server_pid:

View File

@@ -1,4 +1,5 @@
"""Setup tljh logging""" """Setup tljh logging"""
import logging import logging
import os import os

View File

@@ -1,6 +1,7 @@
""" """
Functions to normalize various inputs Functions to normalize various inputs
""" """
import hashlib import hashlib

View File

@@ -8,14 +8,14 @@
# If a dependency is bumped to a new major version, we should make a major # If a dependency is bumped to a new major version, we should make a major
# version release of tljh. # version release of tljh.
# #
jupyterhub>=4.0.2,<5 jupyterhub>=5.2.0,<6
jupyterhub-systemdspawner>=1.0.1,<2 jupyterhub-systemdspawner>=1.0.2,<2
jupyterhub-firstuseauthenticator>=1.0.0,<2 jupyterhub-firstuseauthenticator>=1.1.0,<2
jupyterhub-nativeauthenticator>=1.2.0,<2 jupyterhub-nativeauthenticator>=1.3.0,<2
jupyterhub-ldapauthenticator>=1.3.2,<2 jupyterhub-ldapauthenticator>=2.0.0,<3
jupyterhub-tmpauthenticator>=1.0.0,<2 jupyterhub-tmpauthenticator>=1.0.0,<2
oauthenticator>=16.0.4,<17 oauthenticator>=17.1.0,<18
jupyterhub-idle-culler>=1.2.1,<2 jupyterhub-idle-culler>=1.4.0,<2
# pycurl is installed to improve reliability and performance for when JupyterHub # pycurl is installed to improve reliability and performance for when JupyterHub
# makes web requests. JupyterHub will use tornado's CurlAsyncHTTPClient when # makes web requests. JupyterHub will use tornado's CurlAsyncHTTPClient when
@@ -25,4 +25,4 @@ jupyterhub-idle-culler>=1.2.1,<2
# ref: https://www.tornadoweb.org/en/stable/httpclient.html#module-tornado.simple_httpclient # ref: https://www.tornadoweb.org/en/stable/httpclient.html#module-tornado.simple_httpclient
# ref: https://github.com/jupyterhub/the-littlest-jupyterhub/issues/289 # ref: https://github.com/jupyterhub/the-littlest-jupyterhub/issues/289
# #
pycurl>=7.45.2,<8 pycurl>=7.45.7,<8

View File

@@ -8,11 +8,20 @@
# the requirements-txt-fixer pre-commit hook that sorted them and made # the requirements-txt-fixer pre-commit hook that sorted them and made
# our integration tests fail. # our integration tests fail.
# #
notebook==7.* # ref: https://github.com/jupyter/notebook
jupyterlab==4.* notebook>=7.2.2,<8
# ref: https://github.com/jupyterlab/jupyterlab
jupyterlab>=4.2.5,<5
# nbgitpuller for easily pulling in Git repositories # nbgitpuller for easily pulling in Git repositories
nbgitpuller==1.* # ref: https://github.com/jupyterhub/nbgitpuller
nbgitpuller>=1.2.1,<2
# jupyter-resource-usage to show people how much RAM they are using # jupyter-resource-usage to show people how much RAM they are using
jupyter-resource-usage==1.* # ref: https://github.com/jupyter-server/jupyter-resource-usage
jupyter-resource-usage>=1.1.0,<2
# Most people consider ipywidgets to be part of the core notebook experience # Most people consider ipywidgets to be part of the core notebook experience
ipywidgets==8.* # ref: https://github.com/jupyter-widgets/ipywidgets
ipywidgets>=8.1.5,<9

View File

@@ -18,7 +18,7 @@ Environment=TLJH_INSTALL_PREFIX={install_prefix}
Environment=PATH={install_prefix}/hub/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin Environment=PATH={install_prefix}/hub/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Run upgrade-db before starting, in case Hub version has changed # Run upgrade-db before starting, in case Hub version has changed
# This is a no-op when no db exists or no upgrades are needed # This is a no-op when no db exists or no upgrades are needed
ExecStart={python_interpreter_path} -m jupyterhub.app -f {jupyterhub_config_path} --upgrade-db ExecStart={python_interpreter_path} -m jupyterhub -f {jupyterhub_config_path} --upgrade-db
[Install] [Install]
# Start service when system boots # Start service when system boots

View File

@@ -3,6 +3,7 @@ Wraps systemctl to install, uninstall, start & stop systemd services.
If we use a debian package instead, we can get rid of all this code. If we use a debian package instead, we can get rid of all this code.
""" """
import os import os
import subprocess import subprocess

View File

@@ -1,4 +1,5 @@
"""Traefik installation and setup""" """Traefik installation and setup"""
import hashlib import hashlib
import io import io
import logging import logging
@@ -28,13 +29,13 @@ else:
plat = None plat = None
# Traefik releases: https://github.com/traefik/traefik/releases # Traefik releases: https://github.com/traefik/traefik/releases
traefik_version = "2.10.1" traefik_version = "3.1.4"
# record sha256 hashes for supported platforms here # record sha256 hashes for supported platforms here
# checksums are published in the checksums.txt of each release # checksums are published in the checksums.txt of each release
checksums = { checksums = {
"linux_amd64": "8d9bce0e6a5bf40b5399dbb1d5e3e5c57b9f9f04dd56a2dd57cb0713130bc824", "linux_amd64": "eb7227b1b235195355904839c514a9ed6a0aecdcf5dab02ad48db21b05c5e700",
"linux_arm64": "260a574105e44901f8c9c562055936d81fbd9c96a21daaa575502dc69bfe390a", "linux_arm64": "e5d970a7f11267b70a8e308cb80f859bba4f420f24789f7393fdf3f4cd031631",
} }
_tljh_path = Path(__file__).parent.resolve() _tljh_path = Path(__file__).parent.resolve()
@@ -90,7 +91,10 @@ def check_traefik_version(traefik_bin):
@backoff.on_exception(backoff.expo, Exception, max_tries=2, giveup=fatal_error) @backoff.on_exception(backoff.expo, Exception, max_tries=2, giveup=fatal_error)
def ensure_traefik_binary(prefix): def ensure_traefik_binary(prefix):
"""Download and install the traefik binary to a location identified by a prefix path such as '/opt/tljh/hub/'""" """
Ensure that a traefik binary of a hardcoded version is made available at a
prefix path such as '/opt/tljh/hub/'.
"""
if plat is None: if plat is None:
raise OSError( raise OSError(
f"Error. Platform: {os.uname().sysname} / {machine} Not supported." f"Error. Platform: {os.uname().sysname} / {machine} Not supported."

View File

@@ -3,6 +3,7 @@ User management for tljh.
Supports minimal user & group management Supports minimal user & group management
""" """
import grp import grp
import pwd import pwd
import subprocess import subprocess

View File

@@ -1,6 +1,7 @@
""" """
Miscellaneous functions useful in at least two places unrelated to each other Miscellaneous functions useful in at least two places unrelated to each other
""" """
import logging import logging
import re import re
import subprocess import subprocess

View File

@@ -3,6 +3,7 @@
ensures the same yaml settings for reading/writing ensures the same yaml settings for reading/writing
throughout tljh throughout tljh
""" """
from ruamel.yaml import YAML from ruamel.yaml import YAML
from ruamel.yaml.composer import Composer from ruamel.yaml.composer import Composer