From b4f4fe2f07dbd012d4ae7962770f3fb0e2f00f4d Mon Sep 17 00:00:00 2001 From: Alexandre Pires Date: Mon, 1 Dec 2025 17:25:18 +0100 Subject: [PATCH] Refactor SteamOS session management and launcher scripts - Removed obsolete launch_desktop.sh and launch_session.sh scripts. - Introduced new steam-launcher script to handle Steam launching and session tracking. - Added steam-short-session-tracker for monitoring short Steam sessions and triggering repairs. - Created steamos and steamos-session scripts for managing the SteamOS session. - Implemented steamos-session-select for switching between Gamescope and Plasma sessions. - Updated SDDM configuration for autologin and session management. - Added new systemd services and targets for managing Gamescope and Steam sessions. - Created desktop entries and icons for ALVR and SteamOS shortcuts. - Enhanced logging and error handling across scripts. - Cleaned up unused systemd slice and service files. - Updated Ansible playbook to reflect new configurations and file structures. --- .../game_station/bin/system/gamescope-session | 149 +++++++++++++ .../game_station/bin/system/launch-gamescope | 38 ++++ .../bin/system/{launch_kde.sh => launch-kde} | 4 - .../game_station/bin/system/launch_desktop.sh | 24 --- .../game_station/bin/system/launch_session.sh | 100 --------- .../{launch_steam.sh => steam-launcher} | 2 +- .../bin/system/steam-short-session-tracker | 77 +++++++ ansible/files/game_station/bin/system/steamos | 14 ++ .../game_station/bin/system/steamos-session | 26 +++ .../bin/system/steamos-session-select | 29 ++- .../files/game_station/bin/system/steamos.sh | 4 - .../files/game_station/sddm.conf/steamos.conf | 7 + .../files/game_station/shortcuts/alvr.desktop | 8 + .../game_station/shortcuts/icons/alvr.png | Bin 0 -> 24042 bytes .../game_station/shortcuts/icons/steamos.png | Bin 0 -> 4742 bytes .../game_station/shortcuts/steamos.desktop | 8 + .../game_station/systemd/user/desktop.slice | 3 - .../systemd/user/gamescope-mangoapp.service | 11 + .../systemd/user/gamescope-session.service | 17 ++ .../systemd/user/gamescope-session.target | 13 ++ .../systemd/user/ibus-gamescope.service | 12 ++ .../game_station/systemd/user/session.service | 7 - .../game_station/systemd/user/session.slice | 15 ++ .../systemd/user/steam-launcher.service | 22 ++ .../game_station/systemd/user/steam.slice | 16 +- .../game_station/systemd/user/steamos.service | 10 +- .../game_station/systemd/user/steamos.target | 15 -- .../game_station/systemd/user/sunshine.slice | 16 +- .../wayland-sessions/steamos.desktop | 8 + ansible/host_vars/dev-01.lab.alexpires.me.yml | 1 + ansible/host_vars/gpu-01.lab.alexpires.me.yml | 3 + ansible/playbook_game_station.yml | 199 ++++-------------- terraform/apps/dev-01/config.tf | 5 +- 33 files changed, 518 insertions(+), 345 deletions(-) create mode 100644 ansible/files/game_station/bin/system/gamescope-session create mode 100644 ansible/files/game_station/bin/system/launch-gamescope rename ansible/files/game_station/bin/system/{launch_kde.sh => launch-kde} (90%) delete mode 100644 ansible/files/game_station/bin/system/launch_desktop.sh delete mode 100644 ansible/files/game_station/bin/system/launch_session.sh rename ansible/files/game_station/bin/system/{launch_steam.sh => steam-launcher} (99%) create mode 100644 ansible/files/game_station/bin/system/steam-short-session-tracker create mode 100644 ansible/files/game_station/bin/system/steamos create mode 100644 ansible/files/game_station/bin/system/steamos-session delete mode 100644 ansible/files/game_station/bin/system/steamos.sh create mode 100644 ansible/files/game_station/sddm.conf/steamos.conf create mode 100644 ansible/files/game_station/shortcuts/alvr.desktop create mode 100644 ansible/files/game_station/shortcuts/icons/alvr.png create mode 100644 ansible/files/game_station/shortcuts/icons/steamos.png create mode 100644 ansible/files/game_station/shortcuts/steamos.desktop delete mode 100644 ansible/files/game_station/systemd/user/desktop.slice create mode 100644 ansible/files/game_station/systemd/user/gamescope-mangoapp.service create mode 100644 ansible/files/game_station/systemd/user/gamescope-session.service create mode 100644 ansible/files/game_station/systemd/user/gamescope-session.target create mode 100644 ansible/files/game_station/systemd/user/ibus-gamescope.service delete mode 100644 ansible/files/game_station/systemd/user/session.service create mode 100644 ansible/files/game_station/systemd/user/session.slice create mode 100644 ansible/files/game_station/systemd/user/steam-launcher.service delete mode 100644 ansible/files/game_station/systemd/user/steamos.target create mode 100644 ansible/files/game_station/wayland-sessions/steamos.desktop diff --git a/ansible/files/game_station/bin/system/gamescope-session b/ansible/files/game_station/bin/system/gamescope-session new file mode 100644 index 0000000..3bd0cf3 --- /dev/null +++ b/ansible/files/game_station/bin/system/gamescope-session @@ -0,0 +1,149 @@ +#!/bin/bash +set -euo pipefail +LOG_FILE="$HOME/.local/logs/session.log" + +log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOG_FILE"; } + +CONF_FILE="$HOME/.config/gamescope/gamescope.conf" +[ -f "$CONF_FILE" ] && source "$CONF_FILE" + +FRAMERATE=${FRAMERATE:-60} +RESOLUTION=${RESOLUTION:-1920x1080} +WIDTH="${RESOLUTION%x*}" +HEIGHT="${RESOLUTION#*x}" + +export __GL_GSYNC_ALLOWED=1 +export __GL_VRR_ALLOWED=1 +export __GL_SHADER_DISK_CACHE=1 +export __GL_SYNC_TO_VBLANK=0 +export LIBVA_DRIVER_NAME=nvidia +export __GLX_VENDOR_LIBRARY_NAME=nvidia +export NVD_BACKEND=direct +# export __GL_THREADED_OPTIMIZATIONS=1 + +GAMESCOPE_BIN="$(command -v gamescope || true)" +if [ -z "$GAMESCOPE_BIN" ]; then + log "ERROR: gamescope not found in PATH" + exit 127 +fi + +HDR_FLAG="" +if [[ "$HDR_ENABLED" == "1" || "$HDR_ENABLED" == "true" || "$HDR_ENABLED" == "yes" ]]; then + HDR_FLAG="--hdr-enabled" + log "HDR flag added: --hdr-enabled" +else + log "HDR disabled, no HDR flag added" +fi + +# Create run directory file for startup and stats sockets +# shellcheck disable=SC2030 # (broken warning) +tmpdir="$([[ -n ${XDG_RUNTIME_DIR+x} ]] && mktemp -p "$XDG_RUNTIME_DIR" -d -t gamescope.XXXXXXX)" +socket="${tmpdir:+$tmpdir/startup.socket}" +stats="${tmpdir:+$tmpdir/stats.pipe}" +# Fail early if we don't have a proper runtime directory setup +# shellcheck disable=SC2031 # (broken warning) +if [[ -z $tmpdir || -z ${XDG_RUNTIME_DIR+x} ]]; then + echo >&2 "!! Failed to find run directory in which to create stats session sockets (is \$XDG_RUNTIME_DIR set?)" + exit 0 +fi + +# Chromium (and therefore Steam) ignore XCursor and use on the GTK config +kwriteconfig6 --file gtk-3.0/settings.ini --group Settings --key gtk-cursor-theme-name steam + +# Workaround for Steam login issue while Steam client change propagates out of Beta +touch ~/.steam/root/config/SteamAppData.vdf || true + +# Increase open file limit for gamescope session +ulimit -n 524288 + +# 1048576 = 1M - passing it like that omits the 'M' suffix - xargs removes whitespace +free_disk_space_megs=$(df ~/ --output=avail -B1048576 | sed -n '2 p' | xargs) +minimum_free_disk_space_needed_megs=500 + +if [[ "$free_disk_space_megs" -lt "$minimum_free_disk_space_needed_megs" ]]; then + echo >&2 "gamescope-session: not enough disk space to proceed, trying to find game to delete" + + find ~/.local/share/Steam/steamapps/common/ -mindepth 1 -maxdepth 1 -type d -printf "%T@ %p\0" | sort -n -z | while IFS= read -r -d $'\0' line; do + timestamp=${line%% *} + game_folder=${line#* } + + [[ -d $game_folder ]] || continue + + acf=$(grep -F -- "$(basename -- "$game_folder")" ~/.local/share/Steam/steamapps/*.acf | grep \"installdir\" | cut -d: -f1) + [[ -e "$acf" ]] || continue + + echo >&2 "gamescope-session: deleting $(basename "$game_folder")" + appid=$(basename "$acf" | cut -d_ -f2 | cut -d. -f1) + + # TODO leave a note for Steam to display UI to explain what happened, if this logic stays + # intentionally leave compatdata; could be unclouded save files there + rm -rf --one-file-system -- "$game_folder" "$acf" ~/.local/share/Steam/steamapps/shadercache/"$appid" + + free_disk_space_megs=$(df ~/ --output=avail -B1048576 | sed -n '2 p' | xargs) + [[ "$free_disk_space_megs" -lt "$minimum_free_disk_space_needed_megs" ]] || break + done +fi + +export GAMESCOPE_STATS="$stats" +mkfifo -- "$stats" +mkfifo -- "$socket" + +# Attempt to claim global session if we're the first one running (e.g. /run/1000/gamescope) +linkname="gamescope-stats" +# shellcheck disable=SC2031 # (broken warning) +sessionlink="${XDG_RUNTIME_DIR:+$XDG_RUNTIME_DIR/}${linkname}" # Account for XDG_RUNTIME_DIR="" (notfragileatall) +lockfile="$sessionlink".lck +exec 9>"$lockfile" # Keep as an fd such that the lock lasts as long as the session if it is taken +if flock -n 9 && rm -f "$sessionlink" && ln -sf "$tmpdir" "$sessionlink"; then + # Took the lock. Don't blow up if those commands fail, though. + echo >&2 "Claimed global gamescope stats session at \"$sessionlink\"" +else + echo >&2 "!! Failed to claim global gamescope stats session" +fi + +read_gamescope_env() { + log "Waiting for gamescope to provide DISPLAY and GAMESCOPE_WAYLAND_DISPLAY via socket..." + if read -r -t 3 response_x_display response_wl_display <> "$socket"; then + log "Received gamescope environment:" + log " DISPLAY=$response_x_display" + log " GAMESCOPE_WAYLAND_DISPLAY=$response_wl_display" + export DISPLAY="$response_x_display" + export GAMESCOPE_WAYLAND_DISPLAY="$response_wl_display" + + # Sync environment variables to systemd, then notify we are ready to launch subsequent services + log "Storing gamescope environment for systemd..." + env > $XDG_RUNTIME_DIR/gamescope-environment + systemd-notify --ready + fi +} + +# Spawned in parallel to read values from gamescope +(read_gamescope_env &) + +log "Starting Gamescope session..." + +# Build gamescope argument array for safe quoting and readability +GAMESCOPE_ARGS=( + --generate-drm-mode fixed + --fade-out-duration 200 + --cursor-scale-height 720 + -f + -W "$WIDTH" -H "$HEIGHT" + -w "$WIDTH" -h "$HEIGHT" + --rt --mangoapp -e -R "$socket" -T "$stats" +) + +# Append HDR flag if enabled +if [ -n "${HDR_FLAG:-}" ]; then + GAMESCOPE_ARGS+=("$HDR_FLAG") +fi + +export XDG_CURRENT_DESKTOP=gamescope +export XDG_SESSION_TYPE=wayland +export DESKTOP_SESSION=gamescope + +log "Launching Gamescope: $GAMESCOPE_BIN ${GAMESCOPE_ARGS[*]} -- $*" +sudo setcap 'CAP_SYS_NICE=eip' "$GAMESCOPE_BIN" + +exec "$GAMESCOPE_BIN" "${GAMESCOPE_ARGS[@]}" >>"$LOG_FILE" 2>&1 + diff --git a/ansible/files/game_station/bin/system/launch-gamescope b/ansible/files/game_station/bin/system/launch-gamescope new file mode 100644 index 0000000..a9a02d1 --- /dev/null +++ b/ansible/files/game_station/bin/system/launch-gamescope @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail +LOGFILE="$HOME/.local/logs/gamescope.log" +export PATH="$HOME/.local/bin:$PATH" + +log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; } + +# SDDM sets this to wayland but apps using Gamescope must use x11 +export XDG_SESSION_TYPE=x11 + +# Update the enviroment with DESKTOP_SESSION and all XDG variables +log "Updating systemd user environment with XDG variables" +dbus-update-activation-environment --systemd DESKTOP_SESSION `env | grep ^XDG_ | cut -d = -f 1` + +# This makes it so that xdg-desktop-portal doesn't find any portal implementations and doesn't start them and makes +# them crash/exit because the dbus env has no DISPLAY. In turn this causes dbus calls to the portal which don't rely +# on implementations to hang (such as SDL talking to the real time portal) +# Plasma resets this variable when it starts +systemctl --user set-environment XDG_DESKTOP_PORTAL_DIR="" + +# Remove these as they prevent gamescope-session from starting correctly +systemctl --user unset-environment DISPLAY XAUTHORITY + +# If this shell script is killed then stop gamescope-session +trap 'systemctl --user stop gamescope-session.target' HUP INT TERM + +# Start gamescope-session and wait +log "Starting Gamescope Session" +systemctl --user --wait start gamescope-session.target & +wait +log "Gamescope Session Ended - Performing Final Cleanup" + +# The 'wait' above blocks until gamescope-session.target stops +# We want to wait until *everything* has finished. We know systemd will have +# queued a stop job on graphical-session-pre aleady +# by also queuing up a job we can block until that completes +systemctl --user stop graphical-session-pre.target +log "Gamescope Session Ended - Cleanup Complete" diff --git a/ansible/files/game_station/bin/system/launch_kde.sh b/ansible/files/game_station/bin/system/launch-kde similarity index 90% rename from ansible/files/game_station/bin/system/launch_kde.sh rename to ansible/files/game_station/bin/system/launch-kde index 3191111..f4a2fe2 100644 --- a/ansible/files/game_station/bin/system/launch_kde.sh +++ b/ansible/files/game_station/bin/system/launch-kde @@ -12,11 +12,7 @@ if [ -z "$DESKTOP_BIN" ]; then fi export XDG_CURRENT_DESKTOP=plasma -export XDG_SESSION_TYPE=wayland -export XDG_DATA_DIRS=/usr/local/share/:/usr/share/ -export XDG_CONFIG_DIRS=/usr/local/etc/xdg:/etc/xdg export XDG_CURRENT_DESKTOP=KDE -export XDG_RUNTIME_DIR=/run/user/$(id -u) export QT_QPA_PLATFORM=wayland export GDK_BACKEND=wayland diff --git a/ansible/files/game_station/bin/system/launch_desktop.sh b/ansible/files/game_station/bin/system/launch_desktop.sh deleted file mode 100644 index 875f404..0000000 --- a/ansible/files/game_station/bin/system/launch_desktop.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -set -euo pipefail -LOGFILE="$HOME/.local/logs/desktop.log" - -log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; } - -log "Starting Desktop session..." - -DESKTOP_SESSION_BIN="$(command -v startplasma-wayland || true)" -if [ -z "$DESKTOP_SESSION_BIN" ]; then - log "ERROR: startplasma-wayland not found in PATH" - exit 127 -fi - -log "Launching Desktop: $DESKTOP_SESSION_BIN" -exec "$DESKTOP_SESSION_BIN" >>"$LOGFILE" 2>&1 & - -sleep 5 -systemd-run --user --slice=sunshine.slice --scope sunshine >>"$LOGFILE" 2>&1 || { - log "ERROR: Failed to start Sunshine" - exit 1 -} & - -tail -f /dev/null diff --git a/ansible/files/game_station/bin/system/launch_session.sh b/ansible/files/game_station/bin/system/launch_session.sh deleted file mode 100644 index 1131d12..0000000 --- a/ansible/files/game_station/bin/system/launch_session.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash -set -euo pipefail -LOG_FILE="$HOME/.local/logs/session.log" - -log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOG_FILE"; } - -start_gamescope() { - log "Starting Gamescope session..." - - CONF_FILE="$HOME/.config/gamescope/gamescope.conf" - [ -f "$CONF_FILE" ] && source "$CONF_FILE" - - FRAMERATE=${FRAMERATE:-60} - RESOLUTION=${RESOLUTION:-1920x1080} - WIDTH="${RESOLUTION%x*}" - HEIGHT="${RESOLUTION#*x}" - - export __GL_GSYNC_ALLOWED=1 - export __GL_VRR_ALLOWED=1 - export __GL_SHADER_DISK_CACHE=1 - export __GL_SYNC_TO_VBLANK=0 - export LIBVA_DRIVER_NAME=nvidia - export __GLX_VENDOR_LIBRARY_NAME=nvidia - export NVD_BACKEND=direct - # export __GL_THREADED_OPTIMIZATIONS=1 - - GAMESCOPE_BIN="$(command -v gamescope || true)" - if [ -z "$GAMESCOPE_BIN" ]; then - log "ERROR: gamescope not found in PATH" - exit 127 - fi - - HDR_FLAG="" - if [[ "$HDR_ENABLED" == "1" || "$HDR_ENABLED" == "true" || "$HDR_ENABLED" == "yes" ]]; then - HDR_FLAG="--hdr-enabled" - log "HDR flag added: --hdr-enabled" - else - log "HDR disabled, no HDR flag added" - fi - - # Build gamescope argument array for safe quoting and readability - GAMESCOPE_ARGS=( - --generate-drm-mode fixed - --fade-out-duration 200 - --cursor-scale-height 720 - -f - -W "$WIDTH" -H "$HEIGHT" - -w "$WIDTH" -h "$HEIGHT" - --rt --mangoapp -e - -r "$FRAMERATE" - ) - - # Append HDR flag if enabled - if [ -n "${HDR_FLAG:-}" ]; then - GAMESCOPE_ARGS+=("$HDR_FLAG") - fi - - export XDG_CURRENT_DESKTOP=gamescope - export XDG_SESSION_TYPE=wayland - export DESKTOP_SESSION=gamescope - - log "Launching Gamescope: $GAMESCOPE_BIN ${GAMESCOPE_ARGS[*]} -- $*" - sudo setcap 'CAP_SYS_NICE=eip' "$GAMESCOPE_BIN" - # Execute gamescope inside a DBus session, preserving proper argument quoting - exec dbus-run-session -- "$GAMESCOPE_BIN" "${GAMESCOPE_ARGS[@]}" -- "$@" >>"$LOG_FILE" 2>&1 -} - -start_kwin() { - log "Starting KWin session..." - KWIN_BIN="$(command -v kwin_wayland || true)" - if [ -z "$KWIN_BIN" ]; then - log "ERROR: kwin_wayland not found in PATH" - exit 127 - fi - - export XDG_CURRENT_DESKTOP=plasma - export XDG_SESSION_TYPE=wayland - export DESKTOP_SESSION=plasma-wayland - - # Ensure we don't run nested; width/height/fullscreen are for the windowed backend. - unset DISPLAY WAYLAND_DISPLAY - KWIN_ARGS="--drm --exit-with-session" - log "Launching KWin (DRM): $KWIN_BIN ${KWIN_ARGS} $*" - exec dbus-run-session -- "$KWIN_BIN" ${KWIN_ARGS} "$@" >>"$LOG_FILE" 2>&1 -} - -export XDG_SEAT=seat0 -export XDG_RUNTIME_DIR=/run/user/$(id -u) -export XDG_DATA_DIRS=/usr/local/share/:/usr/share/ -export XDG_CONFIG_DIRS=/usr/local/etc/xdg:/etc/xdg - -if [[ -f "$HOME/.desktop-session-plasma" ]]; then - log "Plasma session selected." - rm "$HOME/.desktop-session-plasma" - start_kwin /usr/local/bin/launch_kde.sh -else - log "Gamescope session selected." - start_gamescope /usr/local/bin/launch_steam.sh -fi - diff --git a/ansible/files/game_station/bin/system/launch_steam.sh b/ansible/files/game_station/bin/system/steam-launcher similarity index 99% rename from ansible/files/game_station/bin/system/launch_steam.sh rename to ansible/files/game_station/bin/system/steam-launcher index 16d83bf..36666b5 100644 --- a/ansible/files/game_station/bin/system/launch_steam.sh +++ b/ansible/files/game_station/bin/system/steam-launcher @@ -145,4 +145,4 @@ if systemctl --user is-active --quiet sunshine.scope; then fi log "Steam session ended." -exit "$status" \ No newline at end of file +exit "$status" diff --git a/ansible/files/game_station/bin/system/steam-short-session-tracker b/ansible/files/game_station/bin/system/steam-short-session-tracker new file mode 100644 index 0000000..410635d --- /dev/null +++ b/ansible/files/game_station/bin/system/steam-short-session-tracker @@ -0,0 +1,77 @@ +#!/bin/bash + +short_session_tracker_file="/tmp/steamos-short-session-tracker" +short_session_start_file="/tmp/steamos-short-session-start" +short_session_duration=60 +short_session_count_before_reset=3 + +do_repair() { + # This should really be part of the steam launcher as `steam --repair` or similar, but we presently only have + # `steam --reset` which is too heavy of a hammer. + + echo >&2 "steam-short-session-tracker: Re-bootstrapping steam from OS copy." + # at this point, might as well make sure we won't relaunch on a sideloaded build + rm -f -- "$HOME/devkit-game/devkit-steam" + mkdir -p ~/.local/share/Steam + # remove some caches and stateful things known to cause Steam to fail to start if corrupt + rm -rf --one-file-system ~/.local/share/Steam/config/widevine + # cleanup the steam config dir, i.e. ~/.steam. We should try to preserve registry.vdf if possible + steam_config_dir="$HOME/.steam" + steam_config_backup_dir="$HOME/dot-steam.bak.$(date +%s)" + registry_vdf="$steam_config_dir/registry.vdf" + registry_backup_vdf="$steam_config_backup_dir/.steam/registry.vdf" + mv "$steam_config_dir" "$steam_config_backup_dir" + mkdir -p "$steam_config_dir" + cp -f "$registry_backup_vdf" "$registry_vdf" || true + # restore clean copy of binaries from RO partition + tar xf /usr/lib/steam/bootstraplinux_ubuntu12_32.tar.xz -C ~/.local/share/Steam + # rearm + rm "$short_session_tracker_file" +} + +handle_started() { + short_session_count=$(< "$short_session_tracker_file" wc -l) + touch $short_session_start_file + + if [[ "$short_session_count" -ge "$short_session_count_before_reset" ]]; then + echo >&2 "steam-short-session-tracker: Steam failed to start $short_session_count_before_reset times within $short_session_duration seconds" + + if [ -f "$HOME/.config/inhibit-short-session-tracker" ]; then + echo >&2 "steam-short-session-tracker: Auto-repair disabled by config. Remove ~/.config/inhibit-short-session-tracker to re-enable" + return + fi + + do_repair + fi +} + +handle_stopped() { + seconds_since_started=$(($(date +%s) - $(date +%s -r "$short_session_start_file"))) + + if [[ "seconds_since_started" -lt "$short_session_duration" ]]; then + echo "frog" >> "$short_session_tracker_file" + else + rm "$short_session_tracker_file" + fi +} + +case "$1" in + --track-started) + echo "steam-short-session-tracker: Tracking Steam start (unimplemented)" + # handle_started + ;; + --track-stopped) + echo "steam-short-session-tracker: Tracking Steam stop (unimplemented)" + # handle_stopped + ;; + --repair-now) + echo "steam-short-session-tracker: Performing immediate repair (unimplemented)" + # do_repair + ;; + *) + echo "Usage: $0 --track-started | --track-stopped | --repair-now" + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/ansible/files/game_station/bin/system/steamos b/ansible/files/game_station/bin/system/steamos new file mode 100644 index 0000000..bf769da --- /dev/null +++ b/ansible/files/game_station/bin/system/steamos @@ -0,0 +1,14 @@ +#!/bin/bash +set -euo pipefail +LOG_FILE="$HOME/.local/logs/session.log" + +log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOG_FILE"; } + +if [[ -f "$HOME/.desktop-session-plasma" ]]; then + log "Plasma session selected." + rm "$HOME/.desktop-session-plasma" + exec /usr/bin/startplasma-wayland +else + log "Gamescope session selected." + exec /usr/local/bin/launch-gamescope +fi diff --git a/ansible/files/game_station/bin/system/steamos-session b/ansible/files/game_station/bin/system/steamos-session new file mode 100644 index 0000000..64d0fbc --- /dev/null +++ b/ansible/files/game_station/bin/system/steamos-session @@ -0,0 +1,26 @@ +# #!/bin/bash +set -euo pipefail +LOG_FILE="$HOME/.local/logs/session.log" + +log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOG_FILE"; } + +env > $XDG_RUNTIME_DIR/steamos-environment +log "Starting SteamOS Session" +while true; do + systemctl --user --wait start steamos.service + wait_status=$? + log "Graphical session service exited with status $wait_status" + if [ $wait_status -ne 0 ]; then + log "Graphical session service exited with error; ending loop." + break + fi + if [ -f "$HOME/.steamos-session-switch" ]; then + log "Graphical session service exited; switch file present -> restarting..." + rm "$HOME/.steamos-session-switch" + continue + fi + log "Graphical session service exited; switch file absent -> ending loop." + break +done +sleep 5 +log "SteamOS Session Ended" \ No newline at end of file diff --git a/ansible/files/game_station/bin/system/steamos-session-select b/ansible/files/game_station/bin/system/steamos-session-select index 845d297..552ef32 100644 --- a/ansible/files/game_station/bin/system/steamos-session-select +++ b/ansible/files/game_station/bin/system/steamos-session-select @@ -4,6 +4,11 @@ LOGFILE="$HOME/.local/logs/session.log" log() { echo "[$(date --iso-8601=seconds)] $*" | tee -a "$LOGFILE"; } +die() { echo >&2 "!! $*"; exit 1; } + +# File this script will modify +CONF_FILE="/etc/sddm.conf.d/zz-steamos-autologin.conf" + session="${1:-gamescope}" case "$session" in @@ -23,18 +28,12 @@ case "$session" in ;; esac -if systemctl --user is-active --quiet sunshine.scope; then - log "Stopping sunshine.scope" - systemctl --user stop sunshine.scope -fi -if systemctl --user is-active --quiet steam.scope; then - log "Stopping steam.scope" - systemctl --user stop steam.scope -fi -if systemctl --user is-active --quiet plasma.scope; then - log "Stopping plasma.scope" - systemctl --user stop plasma.scope -fi -sleep 5 -log "Restarting graphical session service..." -systemctl --user restart session.service \ No newline at end of file +log "Signaling session switch..." +touch "$HOME/.steamos-session-switch" + +# It is possible to get things remaining from the previous session if SDDM is sigkilled by root systemd +# and our units are still running in the user systemd +systemctl --user stop gamescope-session.target +systemctl --user stop plasma-workspace.target +systemctl --user reset-failed + diff --git a/ansible/files/game_station/bin/system/steamos.sh b/ansible/files/game_station/bin/system/steamos.sh deleted file mode 100644 index d74d51d..0000000 --- a/ansible/files/game_station/bin/system/steamos.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -euo pipefail - -systemctl --user start steamos.target \ No newline at end of file diff --git a/ansible/files/game_station/sddm.conf/steamos.conf b/ansible/files/game_station/sddm.conf/steamos.conf new file mode 100644 index 0000000..3823415 --- /dev/null +++ b/ansible/files/game_station/sddm.conf/steamos.conf @@ -0,0 +1,7 @@ +[General] +DisplayServer=wayland + +[Autologin] +Relogin=true +Session=steamos.desktop +User={{ user_name }} \ No newline at end of file diff --git a/ansible/files/game_station/shortcuts/alvr.desktop b/ansible/files/game_station/shortcuts/alvr.desktop new file mode 100644 index 0000000..552922c --- /dev/null +++ b/ansible/files/game_station/shortcuts/alvr.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=ALVR +Comment=Linux Virtual Reality +Exec=/opt/alvr/bin/alvr_dashboard +Icon=alvr.png +Terminal=false +Type=Application +Categories=Game; \ No newline at end of file diff --git a/ansible/files/game_station/shortcuts/icons/alvr.png b/ansible/files/game_station/shortcuts/icons/alvr.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa67da3cba00f01118f1db687be492220ef5f4c GIT binary patch literal 24042 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 literal 0 HcmV?d00001 diff --git a/ansible/files/game_station/shortcuts/icons/steamos.png b/ansible/files/game_station/shortcuts/icons/steamos.png new file mode 100644 index 0000000000000000000000000000000000000000..085d24cef95633840a14344041a1ea4cbd6c0c8a GIT binary patch literal 4742 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 IQo-ik|1=o&`Tzg` literal 0 HcmV?d00001 diff --git a/ansible/files/game_station/shortcuts/steamos.desktop b/ansible/files/game_station/shortcuts/steamos.desktop new file mode 100644 index 0000000..a5155f9 --- /dev/null +++ b/ansible/files/game_station/shortcuts/steamos.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=SteamOS +Comment=Switch to SteamOS +Exec=/usr/local/bin/steamos-session-select +Icon=steamos.png +Terminal=false +Type=Application +Categories=Game; \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/desktop.slice b/ansible/files/game_station/systemd/user/desktop.slice deleted file mode 100644 index 4618983..0000000 --- a/ansible/files/game_station/systemd/user/desktop.slice +++ /dev/null @@ -1,3 +0,0 @@ -[Slice] -CPUWeight=100 -AllowedCPUs={{ general_cores }} diff --git a/ansible/files/game_station/systemd/user/gamescope-mangoapp.service b/ansible/files/game_station/systemd/user/gamescope-mangoapp.service new file mode 100644 index 0000000..01d8667 --- /dev/null +++ b/ansible/files/game_station/systemd/user/gamescope-mangoapp.service @@ -0,0 +1,11 @@ +[Unit] +Description=mangoapp +After=graphical-session.target +PartOf=graphical-session.target + +[Service] +Type=exec +ExecStart=/usr/bin/mangoapp +Restart=always +EnvironmentFile=%t/gamescope-environment +TimeoutStopSec=5 \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/gamescope-session.service b/ansible/files/game_station/systemd/user/gamescope-session.service new file mode 100644 index 0000000..c7ee30a --- /dev/null +++ b/ansible/files/game_station/systemd/user/gamescope-session.service @@ -0,0 +1,17 @@ +[Unit] +Description=Gamescope Session +Before=graphical-session.target +PartOf=graphical-session.target +Wants=graphical-session-pre.target +After=graphical-session-pre.target +RefuseManualStart=yes + +[Service] +TimeoutStartSec=5 +TimeoutStopSec=10 +ExecStart=gamescope-session +Type=notify +NotifyAccess=all +# Make Steam's srt-logger write to the journal with it's own prefixes +Environment=SRT_LOG_TO_JOURNAL=1 +Slice=session.slice \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/gamescope-session.target b/ansible/files/game_station/systemd/user/gamescope-session.target new file mode 100644 index 0000000..197a0e6 --- /dev/null +++ b/ansible/files/game_station/systemd/user/gamescope-session.target @@ -0,0 +1,13 @@ +[Unit] +Description=Gamescope Session +Requires=graphical-session.target +BindsTo=graphical-session.target +After=graphical-session.target + +Requires=gamescope-session.service +BindsTo=gamescope-session.service + +Upholds=steam-launcher.service + +Wants=ibus-gamescope.service +Wants=gamescope-mangoapp.service \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/ibus-gamescope.service b/ansible/files/game_station/systemd/user/ibus-gamescope.service new file mode 100644 index 0000000..bb6384b --- /dev/null +++ b/ansible/files/game_station/systemd/user/ibus-gamescope.service @@ -0,0 +1,12 @@ +[Unit] +Description=Wrapper for Ibus +PartOf=graphical-session.target +After=graphical-session.target + +[Service] +Type=dbus +ExecStart=/usr/bin/ibus-daemon -r --panel=disable --emoji-extension=disable +BusName=org.freedesktop.IBus +EnvironmentFile=%t/gamescope-environment +Slice=session.slice +TimeoutStopSec=5 \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/session.service b/ansible/files/game_station/systemd/user/session.service deleted file mode 100644 index 35cdb6a..0000000 --- a/ansible/files/game_station/systemd/user/session.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=User graphical session service -After=steamos.target - -[Service] -ExecStart=/usr/bin/bash /usr/local/bin/launch_session.sh -Restart=on-failure diff --git a/ansible/files/game_station/systemd/user/session.slice b/ansible/files/game_station/systemd/user/session.slice new file mode 100644 index 0000000..6bb1f9b --- /dev/null +++ b/ansible/files/game_station/systemd/user/session.slice @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=User Core Session Slice +Documentation=man:systemd.special(7) + +[Slice] +CPUWeight=100 \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/steam-launcher.service b/ansible/files/game_station/systemd/user/steam-launcher.service new file mode 100644 index 0000000..974ce42 --- /dev/null +++ b/ansible/files/game_station/systemd/user/steam-launcher.service @@ -0,0 +1,22 @@ +[Unit] +Description=Steam Launcher +After=gamescope-session.target +PartOf=gamescope-session.target + +[Service] +ExecStart=steam-launcher + +# Track short sessions to trigger a repair after enough failures +ExecStartPre=steam-short-session-tracker --track-started +ExecStopPost=steam-short-session-tracker --track-stopped + +# To close properly we need to kill the child of the steam wrapper, as the wrapper itself does not forward signals +ExecStop=/bin/bash -c 'kill -TERM $(pgrep -P $MAINPID || echo $MAINPID)' +# Disable the term signal sent from systemd, as we we handle it manually above +# But still want systemd to kill the entire cgroup on timeout +KillSignal=SIGCONT +KillMode=mixed +TimeoutStopSec=60 + +Type=exec +EnvironmentFile=%t/gamescope-environment \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/steam.slice b/ansible/files/game_station/systemd/user/steam.slice index 4618983..6bb1f9b 100644 --- a/ansible/files/game_station/systemd/user/steam.slice +++ b/ansible/files/game_station/systemd/user/steam.slice @@ -1,3 +1,15 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=User Core Session Slice +Documentation=man:systemd.special(7) + [Slice] -CPUWeight=100 -AllowedCPUs={{ general_cores }} +CPUWeight=100 \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/steamos.service b/ansible/files/game_station/systemd/user/steamos.service index 53514db..e447a94 100644 --- a/ansible/files/game_station/systemd/user/steamos.service +++ b/ansible/files/game_station/systemd/user/steamos.service @@ -1,10 +1,8 @@ [Unit] -Description=SteamOS user graphical session service -After=graphical-session.target systemd-user-sessions.service +Description=User graphical session service +After=graphical-session.target [Service] -ExecStart=/usr/bin/bash /usr/local/bin/steamos.sh +ExecStart=/usr/local/bin/steamos +EnvironmentFile=%t/steamos-environment Restart=on-failure - -[Install] -WantedBy=default.target \ No newline at end of file diff --git a/ansible/files/game_station/systemd/user/steamos.target b/ansible/files/game_station/systemd/user/steamos.target deleted file mode 100644 index 4ded1f3..0000000 --- a/ansible/files/game_station/systemd/user/steamos.target +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=SteamOS Target -Requires=graphical-session.target -BindsTo=graphical-session.target -After=graphical-session.target -PropagatesStopTo=graphical-session.target - -Requires=session.service -BindsTo=session.service - -# Wants=ibus-gamescope.service -# Wants=steam-notif-daemon.service -# Wants=gamescope-xbindkeys.service -# Wants=galileo-mura-setup.service -# Wants=gamescope-mangoapp.service diff --git a/ansible/files/game_station/systemd/user/sunshine.slice b/ansible/files/game_station/systemd/user/sunshine.slice index 571d093..6bb1f9b 100644 --- a/ansible/files/game_station/systemd/user/sunshine.slice +++ b/ansible/files/game_station/systemd/user/sunshine.slice @@ -1,3 +1,15 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=User Core Session Slice +Documentation=man:systemd.special(7) + [Slice] -CPUWeight=100 -AllowedCPUs={{ sunshine_cores }} +CPUWeight=100 \ No newline at end of file diff --git a/ansible/files/game_station/wayland-sessions/steamos.desktop b/ansible/files/game_station/wayland-sessions/steamos.desktop new file mode 100644 index 0000000..d3f72a3 --- /dev/null +++ b/ansible/files/game_station/wayland-sessions/steamos.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=SteamOS +Comment=SteamOS graphical session +Exec=/usr/local/bin/steamos-session +Icon=steamicon.png +Type=Application +DesktopNames=gamescope \ No newline at end of file diff --git a/ansible/host_vars/dev-01.lab.alexpires.me.yml b/ansible/host_vars/dev-01.lab.alexpires.me.yml index 4eec4b9..e26758f 100644 --- a/ansible/host_vars/dev-01.lab.alexpires.me.yml +++ b/ansible/host_vars/dev-01.lab.alexpires.me.yml @@ -66,6 +66,7 @@ ufw_outgoing_traffic: - 9090 # Prometheus ufw_default_forward_policy: "ACCEPT" +fw_loopback_traffic_deny: false ipv4_sysctl_settings: net.ipv4.ip_forward: 1 diff --git a/ansible/host_vars/gpu-01.lab.alexpires.me.yml b/ansible/host_vars/gpu-01.lab.alexpires.me.yml index c771ee0..6049132 100644 --- a/ansible/host_vars/gpu-01.lab.alexpires.me.yml +++ b/ansible/host_vars/gpu-01.lab.alexpires.me.yml @@ -51,8 +51,11 @@ ufw_outgoing_traffic: - 123 # NTP - 443 # HTTPS - 853 # DNS over TLS + - 139 # Samba + - 445 # Samba ufw_default_forward_policy: "ACCEPT" +fw_loopback_traffic_deny: false ipv4_sysctl_settings: net.ipv4.ip_forward: 1 diff --git a/ansible/playbook_game_station.yml b/ansible/playbook_game_station.yml index 39a53b8..addcd6c 100644 --- a/ansible/playbook_game_station.yml +++ b/ansible/playbook_game_station.yml @@ -9,9 +9,6 @@ systemd_user_dir: "/home/{{ user_name }}/.config/systemd/user" systemd_system_dir: "/etc/systemd/system" grub_cfg: "/etc/default/grub" - system_cores: "0,8" - general_cores: "2-7,10-15" - sunshine_cores: "1,9" screen_resolution: "{{ lookup('env', 'GAME_RESOLUTION') | d('1920x1080', true) }}" screen_width: "{{ screen_resolution.split('x')[0] }}" screen_height: "{{ screen_resolution.split('x')[1] }}" @@ -27,8 +24,6 @@ - fbdev=1 - mitigations=off - threadirqs - - nohz_full=1-7,9-15 - - rcu_nocbs=1-7,9-15 - drm.edid_firmware=DP-1:edid/aoc28e850.bin - video=DP-1:e - acpi_enforce_resources=lax @@ -63,140 +58,6 @@ - lizardbyte/stable - atim/heroic-games-launcher - # --- CachyOS Kernel (conditional) --- - - name: Detect supported x86_64 ISA levels - ansible.builtin.shell: - cmd: | - set -euo pipefail; - /lib64/ld-linux-x86-64.so.2 --help | grep -F "(supported, searched)" - register: glibc_loader_help - changed_when: false - failed_when: false - - - name: Determine CPU support for CachyOS kernel - ansible.builtin.set_fact: - has_x86_64_v3: "{{ ('x86-64-v3' in glibc_loader_help.stdout) or ('x86_64_v3' in glibc_loader_help.stdout) }}" - has_x86_64_v2: "{{ ('x86-64-v2' in glibc_loader_help.stdout) or ('x86_64_v2' in glibc_loader_help.stdout) }}" - - - name: Debug CPU ISA detection - ansible.builtin.debug: - msg: "CPU supports x86_64_v3: {{ has_x86_64_v3 }}, x86_64_v2: {{ has_x86_64_v2 }}" - - - name: Enable CachyOS COPR repository (kernel) - become: true - community.general.copr: - name: bieszczaders/kernel-cachyos - state: enabled - when: has_x86_64_v3 | bool or has_x86_64_v2 | bool - - - name: Enable CachyOS COPR repository (addons) - become: true - community.general.copr: - name: bieszczaders/kernel-cachyos-addons - state: enabled - when: has_x86_64_v3 | bool or has_x86_64_v2 | bool - - - name: Install CachyOS kernel for x86_64_v3 CPUs - become: true - ansible.builtin.dnf: - name: - - pesign - - openssl - - kernel-devel - - mokutil - - keyutils - - kernel-cachyos - - kernel-cachyos-devel - state: present - when: has_x86_64_v3 | bool - - - name: Ensures user is on /etc/pesign/users - become: true - ansible.builtin.lineinfile: - path: /etc/pesign/users - line: "{{ ansible_user }}" - state: present - when: has_x86_64_v3 | bool - notify: Run pesign - - - name: Run /usr/libexec/pesign/pesign-authorize - become: true - ansible.builtin.command: /usr/libexec/pesign/pesign-authorize - when: has_x86_64_v3 | bool - changed_when: false - - # - name: Generate certificate for CachyOS kernel signing - # become: true - # ansible.builtin.shell: | - # openssl req -new -x509 -newkey rsa:2048 -keyout "key.pem" \ - # -outform DER -out "cert.der" -nodes -days 36500 \ - # -subj "/CN=CachyOS Secure Boot/" && \ - # openssl pkcs12 -export -out key.p12 -inkey key.pem -in cert.der - # when: has_x86_64_v3 | bool - # changed_when: false - # args: - # executable: /bin/bash - # creates: - # - key.pem - # - cert.der - # - key.p12 - - # - name: Inform user to enroll MOK key - # ansible.builtin.debug: - # msg: | - # Please enroll the MOK key for kernel module signing on next reboot. - # Run: - # sudo certutil -A -i cert.der -n "CachyOS Secure Boot" -d /etc/pki/pesign/ -t "Pu,Pu,Pu" && \ - # sudo pk12util -i key.p12 -d /etc/pki/pesign - # sudo mokutil --import cert.der' if not prompted automatically. - # when: has_x86_64_v3 | bool - - - name: Create /etc/kernel/postinst.d directory - become: true - ansible.builtin.file: - path: /etc/kernel/postinst.d - state: directory - owner: root - group: root - mode: "0755" - - - name: Enable Automatically signing kernel updates - become: true - ansible.builtin.copy: - dest: /etc/kernel/postinst.d/00-signing - owner: root - group: root - mode: "0755" - content: | - #!/bin/sh - set -e - KERNEL_IMAGE="$2" - MOK_KEY_NICKNAME="CachyOS Secure Boot" - if [ "$#" -ne "2" ] ; then - echo "Wrong count of command line arguments. This is not meant to be called directly." >&2 - exit 1 - fi - if [ ! -x "$(command -v pesign)" ] ; then - echo "pesign not executable. Bailing." >&2 - exit 1 - fi - if [ ! -w "$KERNEL_IMAGE" ] ; then - echo "Kernel image $KERNEL_IMAGE is not writable." >&2 - exit 1 - fi - echo "Signing $KERNEL_IMAGE..." - pesign --certificate "$MOK_KEY_NICKNAME" --in "$KERNEL_IMAGE" --sign --out "$KERNEL_IMAGE.signed" - mv "$KERNEL_IMAGE.signed" "$KERNEL_IMAGE" - - - name: Install CachyOS LTS kernel for x86_64_v2-only CPUs - become: true - ansible.builtin.dnf: - name: - - kernel-cachyos-lts - - kernel-cachyos-lts-devel-matched - state: present - when: (not has_x86_64_v3 | bool) and (has_x86_64_v2 | bool) - - name: Ensure core gaming and streaming packages are installed become: true ansible.builtin.dnf: @@ -351,16 +212,11 @@ state: stopped loop: - gdm.service - - sddm.service - - bluetooth.service - ModemManager.service - cups.service - - avahi-daemon.service - chronyd.service - NetworkManager-wait-online.service - - geoclue.service - smartd.service - - upower.service # System actions - name: Install Systemd system files @@ -398,26 +254,26 @@ mode: "0755" loop: - /root/.local/logs - - "{{ systemd_system_dir }}/getty@tty1.service.d" - - name: Create override for getty on tty1 + - name: Copy wayland session files for SDDM become: true ansible.builtin.copy: - dest: "{{ systemd_system_dir }}/getty@tty1.service.d/override.conf" + src: "{{ item }}" + dest: "/usr/share/wayland-sessions/{{ item | basename }}" owner: root group: root mode: "0644" - content: | - [Service] - ExecStart= - ExecStart=-/usr/bin/agetty --autologin {{ user_name }} --noclear %I $TERM - Type=idle + loop: "{{ query('fileglob', 'game_station/wayland-sessions/*') }}" - - name: Enable user lingering for game user + - name: Install SDDM configuration for auto-login become: true - ansible.builtin.command: loginctl enable-linger {{ user_name }} - changed_when: false - failed_when: false + ansible.builtin.template: + src: "{{ item }}" + dest: "/etc/sddm.conf.d/{{ item | basename }}" + owner: root + group: root + mode: "0644" + loop: "{{ query('fileglob', 'game_station/sddm.conf/*') }}" - name: Create log file for Jupiter BIOS update (dummy file) become: true @@ -475,6 +331,8 @@ - "{{ user_config_dir }}/steam-rom-manager/userData" - "/home/{{ user_name }}/.local/logs" - "/home/{{ user_name }}/.local/run" + - "/home/{{ user_name }}/.local/share/applications" + - "/home/{{ user_name }}/.local/share/icons" - "/home/{{ user_name }}/Emulation" - "/home/{{ user_name }}/Emulation/snes" - "/home/{{ user_name }}/Emulation/psp" @@ -618,14 +476,35 @@ owner: "{{ user_name }}" group: "{{ user_name }}" - - name: Enable User session service login + - name: Copy shortcuts to remote host + become: true + ansible.builtin.copy: + src: "{{ item }}" + dest: "/home/{{ user_name }}/.local/share/applications/{{ item | basename }}" + owner: "{{ user_name }}" + group: "{{ user_name }}" + mode: "0644" + loop: "{{ query('fileglob', 'game_station/shortcuts/*.desktop') }}" + + - name: Copy icons to remote host + become: true + ansible.builtin.copy: + src: "{{ item }}" + dest: "/home/{{ user_name }}/.local/share/icons/{{ item | basename }}" + owner: "{{ user_name }}" + group: "{{ user_name }}" + mode: "0644" + loop: "{{ query('fileglob', 'game_station/shortcuts/icons/*.png') }}" + + + - name: Enable Required services become: true - become_user: "{{ user_name }}" ansible.builtin.systemd: - name: steamos.service + name: "{{ item }}" enabled: true state: started - scope: user + loop: + - sddm.service handlers: - name: Update grub diff --git a/terraform/apps/dev-01/config.tf b/terraform/apps/dev-01/config.tf index 701041f..cedb470 100644 --- a/terraform/apps/dev-01/config.tf +++ b/terraform/apps/dev-01/config.tf @@ -18,8 +18,9 @@ locals { # DNS dns_nameservers = [ - "193.110.81.0", - "185.253.5.0" + "192.168.0.252", + "1.1.1.1", + "8.8.8.8" ] override_hosts = [