Describe the bug
When the beets-flask process' user has its shell set to /sbin/nologin, as is done by Kubernetes when running with a user in securityContext.runAsUser that does not already exist in the container, beets-flask repeatedly crashes because the tmux server instantly exits.
Expected behavior
beets-flask runs and the integrated tmux works.
To Reproduce
This is what my Pod looks like from kubectl get --output=yaml pods [my-pod-name]:
apiVersion: v1
kind: Pod
metadata:
name: beets-flask
spec:
containers:
- command:
- /bin/sh
- -c
- umask 002 && . /repo/entrypoint.sh
image: ghcr.io/pspitzner/beets-flask:v2.0.0-rc2@sha256:3e2933e58f176898b23a634f129efb57a81c9ff17c03395810a9bf7272ab658a
name: beets-flask
ports:
- containerPort: 5001
protocol: TCP
securityContext:
runAsGroup: 995
runAsUser: 970
volumeMounts:
- mountPath: /config/beets-flask/config.yaml
name: beets-flask-config
readOnly: true
subPath: config.yaml
- mountPath: /config/beets/config.yaml
name: beets-config
readOnly: true
subPath: config.yaml
- mountPath: /srv/downloads
name: downloads
- mountPath: /srv/Music
name: music
- mountPath: /config/beets-flask
name: beets-flask-config-dir
- mountPath: /logs
name: logs
securityContext:
fsGroup: 995
volumes:
- configMap:
name: beets-flask-config
name: beets-flask-config
- configMap:
name: beets-config
name: beets-config
- hostPath:
path: /srv/downloads
type: Directory
name: downloads
- hostPath:
path: /srv/Music
type: Directory
name: music
- emptyDir: {}
name: logs
- emptyDir: {}
name: beets-flask-config-dir
If you possibly wanted to reproduce this you'd also need to upload ConfigMaps with the beets and beets-flask configuration files to the correct names with the correct keys, and adjust volume paths and groups accordingly. Yes I know Kubernetes is incredibly overkill for this. I happen to like using it.
The workaround in this case was to create another ConfigMap with a tmux configuration file setting default-shell to /bin/bash and mounting it at /. So, I would suggest that a fix for this would involve explicitly specifying /bin/bash as the user's shell. That looks something like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: tmux-conf
data:
tmux.conf: |-
set -g default-shell /bin/bash
setenv -g PATH /repo/backend/.venv/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Your deployment or pod:
containers:
- ...
volumeMounts:
- name: tmux-conf
subPath: tmux.conf
mountPath: /.tmux.conf
volumes:
- name: tmux-conf
configMap:
name: tmux-conf
Technical Details
Version v2.0.0-rc1.
The exception that crashes beets-flask:
[INFO] beets-flask: Setting up Web-Terminal
Process SpawnProcess-20:
Traceback (most recent call last):
File "/repo/backend/beets_flask/server/websocket/terminal.py", line 53, in register_tmux
session = server.new_session(
^^^^^^^^^^^^^^^^^^^
File "/repo/backend/.venv/lib/python3.12/site-packages/libtmux/server.py", line 591, in new_session
return Session.from_session_id(
^^^^^^^^^^^^^^^^^^^^^^^^
File "/repo/backend/.venv/lib/python3.12/site-packages/libtmux/session.py", line 145, in from_session_id
session = fetch_obj(
^^^^^^^^^^
File "/repo/backend/.venv/lib/python3.12/site-packages/libtmux/neo.py", line 230, in fetch_obj
obj_formatters_filtered = fetch_objs(
^^^^^^^^^^^
File "/repo/backend/.venv/lib/python3.12/site-packages/libtmux/neo.py", line 209, in fetch_objs
raise exc.LibTmuxException(proc.stderr)
libtmux.exc.LibTmuxException: ['no server running on /tmp/tmux-970/default']
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap
self.run()
File "/usr/local/lib/python3.12/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/repo/backend/.venv/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
target(sockets=sockets)
File "/repo/backend/.venv/lib/python3.12/site-packages/uvicorn/supervisors/multiprocess.py", line 63, in target
return self.real_target(sockets)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/repo/backend/.venv/lib/python3.12/site-packages/uvicorn/server.py", line 67, in run
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/runners.py", line 195, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/base_events.py", line 691, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "/repo/backend/.venv/lib/python3.12/site-packages/uvicorn/server.py", line 71, in serve
await self._serve(sockets)
File "/repo/backend/.venv/lib/python3.12/site-packages/uvicorn/server.py", line 78, in _serve
config.load()
File "/repo/backend/.venv/lib/python3.12/site-packages/uvicorn/config.py", line 445, in load
self.loaded_app = self.loaded_app()
^^^^^^^^^^^^^^^^^
File "/repo/backend/beets_flask/server/app.py", line 44, in create_app
register_socketio(app)
File "/repo/backend/beets_flask/server/websocket/__init__.py", line 55, in register_socketio
register_tmux()
File "/repo/backend/beets_flask/server/websocket/terminal.py", line 57, in register_tmux
session = server.sessions.get(session_name="beets-socket-term") # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/repo/backend/.venv/lib/python3.12/site-packages/libtmux/_internal/query_list.py", line 567, in get
raise ObjectDoesNotExist
libtmux._internal.query_list.ObjectDoesNotExist
Pod spec is mentioned above. It's like a slightly more complicated docker-compose.yaml.
/config/beets-flask/config.yaml:
gui:
terminal:
start_path: "/srv/downloads" # the directory where to start new terminal sessions
inbox:
folders:
slskd:
name: "/srv/downloads"
path: "/srv/downloads"
autotag: "off"
Describe the bug
When the beets-flask process' user has its shell set to /sbin/nologin, as is done by Kubernetes when running with a user in securityContext.runAsUser that does not already exist in the container, beets-flask repeatedly crashes because the tmux server instantly exits.
Expected behavior
beets-flask runs and the integrated tmux works.
To Reproduce
This is what my Pod looks like from
kubectl get --output=yaml pods [my-pod-name]:If you possibly wanted to reproduce this you'd also need to upload ConfigMaps with the beets and beets-flask configuration files to the correct names with the correct keys, and adjust volume paths and groups accordingly. Yes I know Kubernetes is incredibly overkill for this. I happen to like using it.
The workaround in this case was to create another ConfigMap with a tmux configuration file setting default-shell to /bin/bash and mounting it at /. So, I would suggest that a fix for this would involve explicitly specifying /bin/bash as the user's shell. That looks something like this:
Your deployment or pod:
Technical Details
Version v2.0.0-rc1.
The exception that crashes beets-flask:
Pod spec is mentioned above. It's like a slightly more complicated docker-compose.yaml.
/config/beets-flask/config.yaml: