From aa11440fe7ff017045f7c9f376c23765fbc7bc5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= Date: Fri, 17 Jan 2025 14:58:02 +0100 Subject: [PATCH] Add Kiosk containers from home:atgracey:wallboardos https://jira.suse.com/browse/EDGE-271 --- src/bci_build/package/__init__.py | 6 + src/bci_build/package/kiosk.py | 171 ++++++++++++++++++++ src/bci_build/package/package_versions.json | 6 + src/bci_build/package/pulseaudio/system.pa | 39 +++++ src/bci_build/package/x11/entrypoint.sh | 54 +++++++ src/bci_build/package/x11/xinitrc | 13 ++ src/bci_build/package/x11/xorg.conf | 43 +++++ 7 files changed, 332 insertions(+) create mode 100644 src/bci_build/package/kiosk.py create mode 100644 src/bci_build/package/pulseaudio/system.pa create mode 100644 src/bci_build/package/x11/entrypoint.sh create mode 100644 src/bci_build/package/x11/xinitrc create mode 100644 src/bci_build/package/x11/xorg.conf diff --git a/src/bci_build/package/__init__.py b/src/bci_build/package/__init__.py index 987b3cece..cc8d2aff1 100644 --- a/src/bci_build/package/__init__.py +++ b/src/bci_build/package/__init__.py @@ -1474,6 +1474,9 @@ def generate_disk_size_constraints(size_gb: int) -> str: from .golang import GOLANG_CONTAINERS # noqa: E402 from .helm import HELM_CONTAINERS # noqa: E402 from .kea import KEA_DHCP_CONTAINERS # noqa: E402 +from .kiosk import FIREFOX_CONTAINERS # noqa: E402 +from .kiosk import PULSEAUDIO_CONTAINERS # noqa: E402 +from .kiosk import X11_CONTAINERS # noqa: E402 from .kiwi import KIWI_CONTAINERS # noqa: E402 from .kubectl import KUBECTL_CONTAINERS # noqa: E402 from .mariadb import MARIADB_CLIENT_CONTAINERS # noqa: E402 @@ -1545,6 +1548,9 @@ def generate_disk_size_constraints(size_gb: int) -> str: *KEA_DHCP_CONTAINERS, *KUBECTL_CONTAINERS, *STUNNEL_CONTAINERS, + *X11_CONTAINERS, + *FIREFOX_CONTAINERS, + *PULSEAUDIO_CONTAINERS, ) } diff --git a/src/bci_build/package/kiosk.py b/src/bci_build/package/kiosk.py new file mode 100644 index 000000000..6d48253a2 --- /dev/null +++ b/src/bci_build/package/kiosk.py @@ -0,0 +1,171 @@ +"""Build descriptions for the containerized kiosk containers (X11+auxiliary +apps). + +""" + +from pathlib import Path + +from bci_build.os_version import ALL_NONBASE_OS_VERSIONS +from bci_build.os_version import CAN_BE_LATEST_OS_VERSION +from bci_build.package import ApplicationStackContainer +from bci_build.package import DevelopmentContainer +from bci_build.package import ParseVersion +from bci_build.package import Replacement +from bci_build.package.helpers import generate_package_version_check +from bci_build.package.versions import get_pkg_version + +_X11_FILES = { + "preferences": """ShowThemesMenu=0 +ShowLogoutMenu=0 +ShowFocusModeMenu=0 +QuickSwitch=0 +""", + "entrypoint.sh": ( + (_x11_dir := (_pkg_dir := Path(__file__).parent) / "x11") / "entrypoint.sh" + ).read_text(), + "xinitrc": (_x11_dir / "xinitrc").read_text(), + "xorg.conf": (_x11_dir / "xorg.conf").read_text(), +} + +X11_CONTAINERS = [ + DevelopmentContainer( + name="x11", + os_version=os_version, + additional_versions=["notaskbar"], + version_in_uid=False, + tag_version=(tag_ver := "21"), + is_latest=os_version in CAN_BE_LATEST_OS_VERSION, + version=(xorg_server_re := "%%xorg_server_ver%%"), + pretty_name="X11 Server", + package_list=[ + "hostname", + "which", + "xinit", + "xhost", + "xorg-x11", + "xorg-x11-server", + "xrandr", + "icewm-lite", + "xf86-input-evdev", + "xf86-input-libinput", + "xkeyboard-config", + "xinput", + # indirect dependencies + "xorg-x11-essentials", + "xdm", + ] + # FIXME: unavailable on SLES + + (["xsession"] if os_version.is_tumbleweed else []), + replacements_via_service=[ + Replacement( + xorg_server_re, + package_name="xorg-x11-server", + parse_version=ParseVersion.MINOR, + ) + ], + extra_files=_X11_FILES, + entrypoint=["/usr/local/bin/entrypoint.sh"], + custom_end=generate_package_version_check( + "xorg-x11-server", tag_ver, ParseVersion.MAJOR + ) + + """ +RUN useradd -m user -u 1000 +COPY preferences /etc/icewm/preferences +COPY xinitrc /etc/X11/xinit/xinitrc +COPY xorg.conf /etc/X11/xorg.conf.d/xorg.conf + +ENV XDG_SESSION_TYPE=x11 + +COPY entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh +""", + ) + for os_version in ALL_NONBASE_OS_VERSIONS +] + + +_PULSE_FILES = { + "client.conf": """autospawn = no +auto-connect-localhost = yes +""", + "daemon.conf": """daemonize = no +fail = no +; allow-module-loading = yes +allow-exit = no +use-pid-file = no +system-instance = yes +""", + "system.pa": (_pkg_dir / "pulseaudio" / "system.pa").read_text(), +} + +PULSEAUDIO_CONTAINERS = [ + ApplicationStackContainer( + name="pulseaudio", + os_version=os_version, + tag_version=(tag_ver := "17"), + version_in_uid=False, + is_latest=os_version in CAN_BE_LATEST_OS_VERSION, + version=(pulseaudio_ver_re := "%%pulseaudio_ver%%"), + pretty_name="Pulseaudio", + package_list=["pulseaudio", "pulseaudio-utils"], + replacements_via_service=[ + Replacement( + pulseaudio_ver_re, + package_name="pulseaudio", + parse_version=ParseVersion.MINOR, + ) + ], + extra_files=_PULSE_FILES, + custom_end=generate_package_version_check( + "pulseaudio", tag_ver, ParseVersion.MAJOR + ) + + """ +COPY daemon.conf /etc/pulse/ +COPY client.conf /etc/pulse/ +COPY system.pa /etc/pulse/ +""", + ) + for os_version in ALL_NONBASE_OS_VERSIONS +] + + +FIREFOX_CONTAINERS = [ + DevelopmentContainer( + name="firefox", + os_version=os_version, + tag_version=(ff_ver := get_pkg_version("MozillaFirefox", os_version)), + is_latest=os_version in CAN_BE_LATEST_OS_VERSION, + version=(ff_ver_re := "%%ff_ver%%"), + version_in_uid=False, + pretty_name="Mozilla Firefox", + package_list=( + ["MozillaFirefox"] + + ( + ["MozillaFirefox-branding-openSUSE"] + if os_version.is_tumbleweed + else [ + "MozillaFirefox-branding-SLE", + # required by Firefox via /usr/bin/gconftool-2 + # to be fixed via FileProvides + "gconf2", + ] + ) + ), + replacements_via_service=[ + Replacement( + ff_ver_re, + package_name="MozillaFirefox", + parse_version=ParseVersion.MINOR, + ) + ], + cmd=["/bin/bash", "-c", "firefox --kiosk $URL"], + custom_end=generate_package_version_check( + "MozillaFirefox", ff_ver, ParseVersion.MINOR + ) + + """ +RUN useradd -m user -u 1000 +ENV DISPLAY=":0" +""", + ) + for os_version in ALL_NONBASE_OS_VERSIONS +] diff --git a/src/bci_build/package/package_versions.json b/src/bci_build/package/package_versions.json index f098d2d62..105ac95b8 100644 --- a/src/bci_build/package/package_versions.json +++ b/src/bci_build/package/package_versions.json @@ -1,4 +1,10 @@ { + "MozillaFirefox": { + "6": "128.6", + "7": "128.6", + "Tumbleweed": "134.0", + "version_format": "minor" + }, "cosign": { "5": "2.4", "6": "2.4", diff --git a/src/bci_build/package/pulseaudio/system.pa b/src/bci_build/package/pulseaudio/system.pa new file mode 100644 index 000000000..5094cc2fb --- /dev/null +++ b/src/bci_build/package/pulseaudio/system.pa @@ -0,0 +1,39 @@ +#!/usr/bin/pulseaudio -nF +.fail + +### Automatically restore the volume of streams and devices +load-module module-device-restore +load-module module-stream-restore +load-module module-card-restore + +load-module module-udev-detect + +### Load several protocols +.ifexists module-esound-protocol-unix.so +load-module module-esound-protocol-unix +.endif +load-module module-native-protocol-unix auth-anonymous=1 + +load-module module-native-protocol-tcp auth-anonymous=1 auth-ip-acl=127.0.0.1 + +load-module module-default-device-restore + +### Make sure we always have a sink around, even if it is a null sink. +load-module module-always-sink + +### Automatically suspend sinks/sources that become idle for too long +load-module module-suspend-on-idle + +### Enable positioned event sounds +load-module module-position-event-sounds + +.nofail + +### Set the default sink +#set-default-sink alsa_output.pci-0000_00_1b.0.analog-stereo + +### Set default sink volume to 100% +set-sink-volume @DEFAULT_SINK@ 0x10000 + +### Unmute default sink +set-sink-mute @DEFAULT_SINK@ 0 diff --git a/src/bci_build/package/x11/entrypoint.sh b/src/bci_build/package/x11/entrypoint.sh new file mode 100644 index 000000000..b16b95808 --- /dev/null +++ b/src/bci_build/package/x11/entrypoint.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Function to log messages +log() { + echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')] $@" +} + +log "Starting X11 entrypoint script" + +# Trap signals for graceful shutdown +trap 'log "Received SIGTERM, initiating shutdown"; cleanup' SIGTERM +trap 'log "Received SIGINT, initiating shutdown"; cleanup' SIGINT + +# Cleanup function to stop all relevant processes +cleanup() { + log "Cleaning up and stopping processes" + + pkill -SIGTERM Xorg + pkill -SIGTERM icewm-session-lite + + sleep 3 + + log "Cleanup complete, exiting" + exit 0 +} + +# Set default DISPLAY if not set +if [ -z "$DISPLAY" ]; then + log "DISPLAY variable is not set, defaulting to :0" + DISPLAY=:0 +fi + +# Extract display number from DISPLAY variable +DISPLAY_NUM=$(echo $DISPLAY | sed 's/^://') + +# Clean up existing X server lock files and sockets +log "Cleaning up existing X server lock files for display $DISPLAY" +rm -f /tmp/.X${DISPLAY_NUM}-lock /tmp/.X11-unix/X${DISPLAY_NUM} + +if [ $# -gt 0 ]; then + log "Executing custom command: $@" + exec "$@" +else + # Start X server + log "Starting X server on display $DISPLAY" + startx -- "$DISPLAY" & + X_PID=$! + + # Wait for X server process (Xorg) to finish + log "X server (startx) running" + wait $X_PID + + log "X server has exited" +fi diff --git a/src/bci_build/package/x11/xinitrc b/src/bci_build/package/x11/xinitrc new file mode 100644 index 000000000..592485b94 --- /dev/null +++ b/src/bci_build/package/x11/xinitrc @@ -0,0 +1,13 @@ +#!/bin/bash +xset -dpms +xset s off +xset s noblank + +[ ! -d "/home/user/xauthority" ] && mkdir -p "/home/user/xauthority" +touch /home/user/xauthority/.xauth +xauth -i -f /home/user/xauthority/.xauth generate :0 . trusted +chown -R user:users /home/user/xauthority + +( [ -f ~/.Xmodmap ] ) && DISPLAY=:0 xmodmap ~/.Xmodmap + +exec icewm-session-lite diff --git a/src/bci_build/package/x11/xorg.conf b/src/bci_build/package/x11/xorg.conf new file mode 100644 index 000000000..f7baf6207 --- /dev/null +++ b/src/bci_build/package/x11/xorg.conf @@ -0,0 +1,43 @@ +Section "Device" + Identifier "modesetting" + Driver "modesetting" + Option "PreferCloneMode" "true" + Option "AccelMethod" "none" +EndSection + +Section "Screen" + Identifier "modesetting" + Device "modesetting" +EndSection + +Section "Device" + Identifier "fbdev" + Driver "fbdev" +EndSection + +Section "Screen" + Identifier "fbdev" + Device "fbdev" +EndSection + +Section "Device" + Identifier "vesa" + Driver "vesa" +EndSection + +Section "Screen" + Identifier "vesa" + Device "vesa" +EndSection + +Section "ServerLayout" + Identifier "Layout" + Screen "modesetting" + Screen "fbdev" + Screen "vesa" +EndSection + +Section "ServerFlags" + Option "DontVTSwitch" "true" + Option "DontZap" "true" +EndSection