Unable to use systemdspawner on CentOS 7

Hello!

I’m currently going through the process of trying to get systemdspawner running on a CentOS 7 instance.

# cat /etc/centos-release
CentOS Linux release 7.9.2009 (Core)

# systemctl --version
systemd 219

# uname -r
3.10.0-1160.15.2.el7.x86_64

# python --version
Python 3.8.6

# pip list
jupyterhub                1.3.0
jupyterhub-systemdspawner 0.15.0
jupyterlab                2.2.5

I understand that there’s limited functionality due to the version of systemd that’s most likely to remain on the OS till EoL, but I haven’t been able to successfully completely log in against local accounts or those authenticating against LDAP.

We’re coming from a working setup on CentOS 7, but instead using SudoSpawner. We’re looking to switch away from this to take advantage of the memory and CPU cgroup implementation here.

As a note, for testing purposes I’ve disabed SELinux till everything is up and running, then will fight that fight when the time comes. Apologies for what is likely to be a mess here.

Out of the box, I receive the below error after authenticating against LDAP credentials:

jupyterhub: [E 2021-02-11 18:22:20.455 JupyterHub user:638] Unhandled error starting ldap-user's server: [Errno 13] Permission denied: '/run/jupyter-ldap-user-singleuser/jupyter-ldap-user-singleuser.env'
jupyterhub: [W 2021-02-11 18:22:20.482 JupyterHub web:1787] 500 GET /hub/spawn/ldap-user (::ffff:192.168.56.1): Error in Authenticator.pre_spawn_start: PermissionError [Errno 13] Permission denied: '/run/jupyter-ldap-user-singleuser/jupyter-ldap-user-singleuser.env'

And this if I use a local account:

jupyterhub: [W 2021-02-11 18:28:41.744 JupyterHub auth:919] PAM Authentication failed (local-user@::ffff:192.168.56.1): [PAM Error 7] Authentication failure
jupyterhub: [W 2021-02-11 18:28:41.747 JupyterHub base:713] Failed login for local-user

To authenticate with the local account, I need to comment out the CapabilityBoundingSet line in the service file and at that stage, I then get the same Error in Authenticator.pre_spawn_start error above.

After adding /run to ReadWriteDirectories= in the service file, I’m able to authenticate with both accounts, but get stuck at spawning. On the UI Spawn failed: Timeout eventually appears.

jupyterhub: [I 2021-02-11 18:34:44.081 JupyterHub pages:347] local-user is pending spawn
jupyterhub: [I 2021-02-11 18:34:44.086 JupyterHub log:174] 200 GET /hub/spawn-pending/local-user (vagrant@::ffff:192.168.56.1) 10.46ms
jupyterhub: [W 2021-02-11 18:34:53.028 JupyterHub base:947] User local-user is slow to start (timeout=10)

I’ve added some parameters to the JupyterHub config to see if that’ll resolve.

With c.SystemdSpawner.readwrite_paths = ['/home/{USERNAME}'] configured, I see:

Feb 11 18:11:09 sysdspawner jupyterhub: Unknown assignment ReadWriteDirectories=/home/local-user.
Feb 11 18:11:09 sysdspawner jupyterhub: Failed to create bus message: No such device or address

c.SystemdSpawner.user_workingdir = '/home/{USERNAME}' is also specified with no change.

Also tried are

c.PAMAuthenticator.open_sessions = False
c.SystemdSpawner.dynamic_users = True

But all this results in is the below appearing in the logs. I’ve enabled debugging in various parameters, but nothing comes to light.

Feb 11 17:53:22 sysdspawner jupyterhub: Unknown assignment DynamicUser=yes.
Feb 11 17:53:22 sysdspawner jupyterhub: Failed to create bus message: No such device or address

Is there a step that I’m missing here at all? I’ve been able to get things working on Debian Buster fine using the same setup, but our infrastructure is built on CentOS for just now.

Thanks!

The README for c.SystemdSpawner.dynamic_users links to a post which says the feature was introduced in version 235, so that explains the error message.

Can you show us your logs with debug enabled for JupyterHub and the spawner?

If you can provide your full configuration with secrets redacted that might help someone else figure out the problem.

Thanks! I was getting desperate trying things out - thanks for checking me on that, but wasn’t expecting anything to work there. Understand we’ll be limited in what can be controlled due to the versions we’re running.

This is where I’m at just now. I’ve spent this afternoon disabling various components that are only supported in more recent versions of systemd. Below is the main error via journalctl that I’m getting that I can’t clear, which is supposedly resolved as per issue #9 - I can confirm that I see the applied change in the systemd.py file.

Feb 22 15:21:43 sysdspawner scl[3126]: Unknown assignment RuntimeDirectory=jupyter-test-singleuser.

jupyterhub.service

[Unit]
Description=Jupyterhub
RequiresMountsFor=/opt/rh
After=network.target

[Service]
User=root
Environment="PATH=/nix/var/nix/profiles/jupyterhub/bin:/sbin:/bin:/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/lib/npm/bin:/usr/local/texlive/2020/bin/x86_64-linux"
#ExecStart=/opt/rh/rh-python38/root/usr/local/bin/jupyterhub -f /etc/jupyterhub/jupyterhub-config.py
WorkingDirectory=/srv/jupyterhub/
ExecStart=/usr/bin/scl enable rh-python38 -- jupyterhub -f /etc/jupyterhub/jupyterhub-config.py


[Install]
WantedBy=multi-user.target
                  

jupyterhub-config.py

import sys
import os

c.JupyterHub.cookie_secret_file = 'jupyterhub_cookie_secret'
c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite'
c.ConfigurableHTTPProxy.pid_file = "jupyterhub-proxy.pid"

c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner'
c.JupyterHub.proxy_class = 'jupyterhub.proxy.ConfigurableHTTPProxy'

#c.Spawner.cmd = ['jupyterhub-singleuser']
c.Spawner.cmd = ['jupyter-labhub']
c.SystemdSpawner.default_url = '/lab'
#c.JupyterHub.default_url = '/lab?reset'


c.PAMAuthenticator.open_sessions = False
c.SystemdSpawner.mem_limit = '1G'
c.SystemdSpawner.cpu_limit = 1.0
#c.SystemdSpawner.default_shell = '/bin/bash'

# Requires more recent systemd
#c.SystemdSpawner.isolate_tmp = True
#c.SystemdSpawner.disable_user_sudo = True
#c.SystemdSpawner.dynamic_users = False
#c.SystemdSpawner.isolate_devices = True
#c.SystemdSpawner.readonly_paths = ['/']
#c.SystemdSpawner.readwrite_paths = ['/home/{USERNAME}', '/var/log/']
#c.SystemdSpawner.user_workingdir = '/home/{USERNAME}'
#c.SystemdSpawner.username_template = '{USERNAME}'

# Deprecated
c.JupyterHub.extra_log_file = "/var/log/jupyterhub.log"

c.JupyterHub.log_level = "DEBUG"
c.Spawner.debug = True
c.SystemdSpawner.debug = True
c.Spawner.start_timeout = 30
#c.JupyterHub.init_spawners_timeout = 30
c.ConfigurableHTTPProxy.debug = True

#os.environ['PATH'] = '/opt/rh/rh-python38/root/usr/local/bin:/opt/rh/rh-python38/root/usr/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/lib/npm/bin:/usr/local/texlive/2020/bin/x86_64-linux'
#c.Spawner.env_keep.extend(['PATH'])

The config has taken on multiple forms recently - it’s a bit of a Frankenstein’s Monster based on other working configurations I’ve been able to see online. I understand I’m probably missing something here as there are a few differences between systemdspawner and SudoSpawner.

In regards to logs.

/var/log/jupyterhub.log

[I 2021-02-22 15:34:21.166 JupyterHub app:2349] Running JupyterHub version 1.3.0
[I 2021-02-22 15:34:21.167 JupyterHub app:2379] Using Authenticator: jupyterhub.auth.PAMAuthenticator-1.3.0
[I 2021-02-22 15:34:21.167 JupyterHub app:2379] Using Spawner: systemdspawner.systemdspawner.SystemdSpawner
[I 2021-02-22 15:34:21.167 JupyterHub app:2379] Using Proxy: jupyterhub.proxy.ConfigurableHTTPProxy-1.3.0
[D 2021-02-22 15:34:21.168 JupyterHub app:2310] Could not load pycurl: No module named 'pycurl'
    pycurl is recommended if you have a large number of users.
[I 2021-02-22 15:34:21.168 JupyterHub app:1420] Loading cookie_secret from /srv/jupyterhub/jupyterhub_cookie_secret
[D 2021-02-22 15:34:21.168 JupyterHub app:1587] Connecting to db: sqlite:///jupyterhub.sqlite
[D 2021-02-22 15:34:21.181 JupyterHub orm:815] database schema version found: 4dc2d5a8c53c
[I 2021-02-22 15:34:21.184 JupyterHub proxy:460] Generating new CONFIGPROXY_AUTH_TOKEN
[W 2021-02-22 15:34:21.185 JupyterHub app:1695] No admin users, admin interface will be unavailable.
[W 2021-02-22 15:34:21.185 JupyterHub app:1696] Add any administrative users to `c.Authenticator.admin_users` in config.
[I 2021-02-22 15:34:21.185 JupyterHub app:1725] Not using allowed_users. Any authenticated user will be allowed.
[D 2021-02-22 15:34:21.204 JupyterHub app:1877] Purging expired APITokens
[D 2021-02-22 15:34:21.206 JupyterHub app:1877] Purging expired OAuthAccessTokens
[D 2021-02-22 15:34:21.209 JupyterHub app:1877] Purging expired OAuthCodes
[D 2021-02-22 15:34:21.215 JupyterHub app:2004] Initializing spawners
[D 2021-02-22 15:34:21.216 JupyterHub app:2137] Loaded users:
    
[I 2021-02-22 15:34:21.216 JupyterHub app:2416] Initialized 0 spawners in 0.001 seconds
[W 2021-02-22 15:34:21.218 JupyterHub proxy:662] Running JupyterHub without SSL.  I hope there is SSL termination happening somewhere else...
[I 2021-02-22 15:34:21.218 JupyterHub proxy:666] Starting proxy @ http://:8000
[D 2021-02-22 15:34:21.218 JupyterHub proxy:667] Proxy cmd: ['configurable-http-proxy', '--ip', '', '--port', '8000', '--api-ip', '127.0.0.1', '--api-port', '8001', '--error-target', 'h
ttp://127.0.0.1:8081/hub/error', '--log-level', 'debug']
[D 2021-02-22 15:34:21.224 JupyterHub proxy:574] Writing proxy pid file: jupyterhub-proxy.pid
[D 2021-02-22 15:34:21.522 JupyterHub proxy:702] Proxy started and appears to be up
[D 2021-02-22 15:34:21.526 JupyterHub proxy:795] Proxy: Fetching GET http://127.0.0.1:8001/api/routes
[I 2021-02-22 15:34:21.539 JupyterHub app:2664] Hub API listening on http://127.0.0.1:8081/hub/
[D 2021-02-22 15:34:21.539 JupyterHub proxy:314] Fetching routes to check
[D 2021-02-22 15:34:21.539 JupyterHub proxy:795] Proxy: Fetching GET http://127.0.0.1:8001/api/routes
[I 2021-02-22 15:34:21.542 JupyterHub proxy:319] Checking routes
[I 2021-02-22 15:34:21.542 JupyterHub proxy:399] Adding default route for Hub: / => http://127.0.0.1:8081
[D 2021-02-22 15:34:21.542 JupyterHub proxy:795] Proxy: Fetching POST http://127.0.0.1:8001/api/routes/
[I 2021-02-22 15:34:21.547 JupyterHub app:2739] JupyterHub is now running at http://:8000
[D 2021-02-22 15:34:21.548 JupyterHub app:2342] It took 0.398 seconds for the Hub to start
[D 2021-02-22 15:34:25.681 JupyterHub base:328] Refreshing auth for test
[I 2021-02-22 15:34:25.681 JupyterHub login:43] User logged out: test
[I 2021-02-22 15:34:25.685 JupyterHub log:181] 302 GET /hub/logout -> /hub/login (@::ffff:192.168.56.1) 14.43ms
[I 2021-02-22 15:34:25.729 JupyterHub log:181] 200 GET /hub/login (@::ffff:192.168.56.1) 25.28ms
[D 2021-02-22 15:34:29.461 JupyterHub base:521] Setting cookie jupyterhub-session-id: {'httponly': True}
[D 2021-02-22 15:34:29.461 JupyterHub base:525] Setting cookie for test: jupyterhub-hub-login
[D 2021-02-22 15:34:29.461 JupyterHub base:521] Setting cookie jupyterhub-hub-login: {'httponly': True, 'path': '/hub/'}
[I 2021-02-22 15:34:29.461 JupyterHub base:757] User logged in: test
[D 2021-02-22 15:34:29.461 JupyterHub user:288] Creating <class 'systemdspawner.systemdspawner.SystemdSpawner'> for test:
[D 2021-02-22 15:34:29.463 JupyterHub systemdspawner:155] user:test Initialized spawner with unit jupyter-test-singleuser
[I 2021-02-22 15:34:29.463 JupyterHub log:181] 302 POST /hub/login?next= -> /hub/spawn (test@::ffff:192.168.56.1) 369.89ms
[D 2021-02-22 15:34:29.487 JupyterHub pages:217] Triggering spawn with default options for test
[D 2021-02-22 15:34:29.487 JupyterHub base:875] Initiating spawn for test
[D 2021-02-22 15:34:29.487 JupyterHub base:879] 0/100 concurrent spawns
[D 2021-02-22 15:34:29.487 JupyterHub base:884] 0 active servers
[D 2021-02-22 15:34:29.511 JupyterHub user:602] Calling Spawner.start for test
[D 2021-02-22 15:34:29.512 JupyterHub systemdspawner:201] user:test Using port 56903 to start spawning user server
[I 2021-02-22 15:34:30.494 JupyterHub log:181] 302 GET /hub/spawn -> /hub/spawn-pending/test (test@::ffff:192.168.56.1) 1008.57ms
[I 2021-02-22 15:34:30.557 JupyterHub pages:402] test is pending spawn
[I 2021-02-22 15:34:30.561 JupyterHub log:181] 200 GET /hub/spawn-pending/test (test@::ffff:192.168.56.1) 8.44ms
[W 2021-02-22 15:34:39.490 JupyterHub base:1003] User test is slow to start (timeout=10)
[W 2021-02-22 15:34:59.515 JupyterHub user:681] test's server failed to start in 30 seconds, giving up
[D 2021-02-22 15:34:59.517 JupyterHub user:790] Stopping test
[D 2021-02-22 15:34:59.556 JupyterHub user:816] Deleting oauth client jupyterhub-user-test
[D 2021-02-22 15:34:59.563 JupyterHub user:819] Finished stopping test
[E 2021-02-22 15:34:59.569 JupyterHub gen:623] Exception in Future <Task finished name='Task-23' coro=<BaseHandler.spawn_single_user.<locals>.finish_user_spawn() done, defined at /opt/rh/rh-python38/root/usr/local/lib/python3.8/site-packages/jupyterhub/handlers/base.py:895> exception=TimeoutError('Timeout')> after timeout
    Traceback (most recent call last):
      File "/opt/rh/rh-python38/root/usr/local/lib64/python3.8/site-packages/tornado/gen.py", line 618, in error_callback
        future.result()
      File "/opt/rh/rh-python38/root/usr/local/lib/python3.8/site-packages/jupyterhub/handlers/base.py", line 902, in finish_user_spawn
        await spawn_future
      File "/opt/rh/rh-python38/root/usr/local/lib/python3.8/site-packages/jupyterhub/user.py", line 707, in spawn
        raise e
      File "/opt/rh/rh-python38/root/usr/local/lib/python3.8/site-packages/jupyterhub/user.py", line 606, in spawn
        url = await gen.with_timeout(timedelta(seconds=spawner.start_timeout), f)
    tornado.util.TimeoutError: Timeout
    
[I 2021-02-22 15:34:59.570 JupyterHub log:181] 200 GET /hub/api/users/test/server/progress (test@::ffff:192.168.56.1) 28891.96ms
(END)

journalctl

Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.461 JupyterHub base:525] Setting cookie for test: jupyterhub-hub-login
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.461 JupyterHub base:521] Setting cookie jupyterhub-hub-login: {'httponly': True, 'path': '/hub/'}
Feb 22 15:34:29 sysdspawner scl[3485]: [I 2021-02-22 15:34:29.461 JupyterHub base:757] User logged in: test
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.461 JupyterHub user:288] Creating <class 'systemdspawner.systemdspawner.SystemdSpawner'> for test:
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.463 JupyterHub systemdspawner:155] user:test Initialized spawner with unit jupyter-test-singleuser
Feb 22 15:34:29 sysdspawner scl[3485]: [I 2021-02-22 15:34:29.463 JupyterHub log:181] 302 POST /hub/login?next= -> /hub/spawn (test@::ffff:192.168.56.1) 369.89ms
Feb 22 15:34:29 sysdspawner scl[3485]: 15:34:29.483 [ConfigProxy] debug: PROXY WEB /hub/spawn to http://127.0.0.1:8081
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.487 JupyterHub pages:217] Triggering spawn with default options for test
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.487 JupyterHub base:875] Initiating spawn for test
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.487 JupyterHub base:879] 0/100 concurrent spawns
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.487 JupyterHub base:884] 0 active servers
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.511 JupyterHub user:602] Calling Spawner.start for test
Feb 22 15:34:29 sysdspawner scl[3485]: [D 2021-02-22 15:34:29.512 JupyterHub systemdspawner:201] user:test Using port 56903 to start spawning user server
Feb 22 15:34:29 sysdspawner scl[3485]: Unknown assignment RuntimeDirectory=jupyter-test-singleuser.
Feb 22 15:34:29 sysdspawner scl[3485]: Failed to create bus message: No such device or address
Feb 22 15:34:30 sysdspawner scl[3485]: [I 2021-02-22 15:34:30.494 JupyterHub log:181] 302 GET /hub/spawn -> /hub/spawn-pending/test (test@::ffff:192.168.56.1) 1008.57ms
Feb 22 15:34:30 sysdspawner scl[3485]: 15:34:30.544 [ConfigProxy] debug: PROXY WEB /hub/spawn-pending/test to http://127.0.0.1:8081
Feb 22 15:34:30 sysdspawner scl[3485]: [I 2021-02-22 15:34:30.557 JupyterHub pages:402] test is pending spawn
Feb 22 15:34:30 sysdspawner scl[3485]: [I 2021-02-22 15:34:30.561 JupyterHub log:181] 200 GET /hub/spawn-pending/test (test@::ffff:192.168.56.1) 8.44ms
Feb 22 15:34:30 sysdspawner scl[3485]: 15:34:30.677 [ConfigProxy] debug: PROXY WEB /hub/api/users/test/server/progress to http://127.0.0.1:8081
Feb 22 15:34:39 sysdspawner scl[3485]: [W 2021-02-22 15:34:39.490 JupyterHub base:1003] User test is slow to start (timeout=10)
Feb 22 15:34:59 sysdspawner scl[3485]: [W 2021-02-22 15:34:59.515 JupyterHub user:681] test's server failed to start in 30 seconds, giving up
Feb 22 15:34:59 sysdspawner scl[3485]: [D 2021-02-22 15:34:59.517 JupyterHub user:790] Stopping test
Feb 22 15:34:59 sysdspawner scl[3485]: [D 2021-02-22 15:34:59.556 JupyterHub user:816] Deleting oauth client jupyterhub-user-test
Feb 22 15:34:59 sysdspawner scl[3485]: [D 2021-02-22 15:34:59.563 JupyterHub user:819] Finished stopping test
Feb 22 15:34:59 sysdspawner scl[3485]: [E 2021-02-22 15:34:59.569 JupyterHub gen:623] Exception in Future <Task finished name='Task-23' coro=<BaseHandler.spawn_single_user.<locals>.fini
Feb 22 15:34:59 sysdspawner scl[3485]: Traceback (most recent call last):
Feb 22 15:34:59 sysdspawner scl[3485]: File "/opt/rh/rh-python38/root/usr/local/lib64/python3.8/site-packages/tornado/gen.py", line 618, in error_callback
Feb 22 15:34:59 sysdspawner scl[3485]: future.result()
Feb 22 15:34:59 sysdspawner scl[3485]: File "/opt/rh/rh-python38/root/usr/local/lib/python3.8/site-packages/jupyterhub/handlers/base.py", line 902, in finish_user_spawn
Feb 22 15:34:59 sysdspawner scl[3485]: await spawn_future
Feb 22 15:34:59 sysdspawner scl[3485]: File "/opt/rh/rh-python38/root/usr/local/lib/python3.8/site-packages/jupyterhub/user.py", line 707, in spawn
Feb 22 15:34:59 sysdspawner scl[3485]: raise e
Feb 22 15:34:59 sysdspawner scl[3485]: File "/opt/rh/rh-python38/root/usr/local/lib/python3.8/site-packages/jupyterhub/user.py", line 606, in spawn
Feb 22 15:34:59 sysdspawner scl[3485]: url = await gen.with_timeout(timedelta(seconds=spawner.start_timeout), f)
Feb 22 15:34:59 sysdspawner scl[3485]: tornado.util.TimeoutError: Timeout
Feb 22 15:34:59 sysdspawner scl[3485]: [I 2021-02-22 15:34:59.570 JupyterHub log:181] 200 GET /hub/api/users/test/server/progress (test@::ffff:192.168.56.1) 28891.96ms

Hmmm…

I’ve downgraded systemdspawner from 0.15.0 to 0.14.0, where 0.14.0 is the latest version under releases on the git repo, but 0.15.0 is latest available via pip. I’m able to spawn now. I’ll perform some tests to see if everything is working as expected then open an issue.

Cheers!

2 Likes