diff --git a/platform/inventory/fleet.yaml b/platform/inventory/fleet.yaml index 36a3e3a5..cc710b61 100644 --- a/platform/inventory/fleet.yaml +++ b/platform/inventory/fleet.yaml @@ -72,19 +72,17 @@ nodes: capacity: cpu_millicores: 28800 memory_mib: 16384 - gpus: - - vendor: nvidia - model: gtx960m - class: transcode + # No gpus entry: the GTX 960M is Maxwell, which cannot runtime-suspend + # (Runtime D3 needs Turing or newer), so the driver is left unloaded to + # stop the card drawing idle power. GPU work belongs on + # enschede-t1000-1 (transcode) or enschede-rx7900xtx-1 (render-compute). capabilities: - tailscale - lan-ingress - - game-streaming # agent-runner Pods mount this node's /var/run/docker.sock for # Docker/Testcontainers. The matching k3s label is required by # agents-api before scheduling host-equivalent runner Pods here. - docker-socket - - nvidia enschede-t1000-1: status: active @@ -254,7 +252,6 @@ service_intent: host_native: enschede-gtx-960m-1: - tailscale - - game-streaming enschede-rx7900xtx-1: - tailscale - game-streaming @@ -314,7 +311,6 @@ placement_intent: gpu_specific: jellyfin: preferred_gpu_model: t1000 - temporary_gpu_model: gtx960m exposure_intent: public: diff --git a/platform/nix/hosts/enschede-gtx-960m-1/default.nix b/platform/nix/hosts/enschede-gtx-960m-1/default.nix index f4c49c22..922433f3 100644 --- a/platform/nix/hosts/enschede-gtx-960m-1/default.nix +++ b/platform/nix/hosts/enschede-gtx-960m-1/default.nix @@ -1,22 +1,33 @@ -{ config, ... }: +{ ... }: { imports = [ ../../profiles/worker.nix ../../profiles/utility.nix - ../../profiles/gpu-nvidia.nix ../../modules/k3s/node-labels.nix - ../../modules/services/game-streaming.nix ./disko.nix ]; networking.hostName = "enschede-gtx-960m-1"; - # GTX 960M is Maxwell 2.0 (GM107). NVIDIA dropped Maxwell/Pascal/Volta - # from the mainline branch at R575; the 580.x legacy branch continues - # to support them. Without this override the default 595.x driver - # does not bind to the GPU and nvidia-container-toolkit-cdi-generator - # fails at activation with "NVML: Driver Not Loaded". - hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.legacy_580; + # No driver binds the GTX 960M on this host. Runtime D3 needs Turing or + # newer, so on Maxwell the proprietary driver reports + # "Runtime D3 status: Disabled by default" and never suspends the GPU: + # runtime_suspended_time stayed at 0 ms across 29.5 days of uptime while + # the card idled at P8 with no compute clients. Leaving the driver + # unloaded is the only way this generation stops drawing idle power, so + # transcode, CDI and game streaming move to hosts that can use a GPU. + boot.blacklistedKernelModules = [ + "nouveau" + "nvidia" + "nvidia_drm" + "nvidia_modeset" + "nvidia_uvm" + ]; + # With no driver attached the PCI core still needs runtime PM enabled + # before it will drop the unbound display controller out of D0. + services.udev.extraRules = '' + ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", ATTR{power/control}="auto" + ''; personalStack.k3sNodeLabels = { "personal-stack/site" = "enschede"; "personal-stack/node" = "enschede-gtx-960m-1"; @@ -25,16 +36,11 @@ "personal-stack/role-utility-host" = "true"; "personal-stack/capability-tailscale" = "true"; "personal-stack/capability-lan-ingress" = "true"; - "personal-stack/capability-game-streaming" = "true"; "personal-stack/capability-docker-socket" = "true"; # capability-samba deliberately absent: the media drive (/srv/media) # is mounted on enschede-t1000-1, not here. # capability-adguard deliberately absent: AdGuard runs only on # enschede-t1000-1. - "personal-stack/capability-nvidia" = "true"; - "personal-stack/gpu-vendor-nvidia" = "true"; - "personal-stack/gpu-model-gtx960m" = "true"; - "personal-stack/gpu-class-transcode" = "true"; }; # Keep Testcontainers' status.hostIP callback stable and aligned with the # runner NetworkPolicy's single allowed node IP. diff --git a/platform/nix/modules/services/game-streaming.nix b/platform/nix/modules/services/game-streaming.nix deleted file mode 100644 index 6e128713..00000000 --- a/platform/nix/modules/services/game-streaming.nix +++ /dev/null @@ -1,555 +0,0 @@ -{ config, lib, pkgs, ... }: -let - gameUser = "gamehost"; - gameHome = "/home/${gameUser}"; - gamesMount = "/srv/games"; - localGamesMount = "/srv/game-streaming"; - localRomsMount = "${localGamesMount}/roms"; - pcGamesMount = "${localGamesMount}/pc"; - wolfState = "/etc/wolf"; - wolfSteamApp = '' - [[profiles.apps]] - title = "Steam" - start_virtual_compositor = true - app_state_folder = "steam" - icon_png_path = "https://games-on-whales.github.io/wildlife/apps/steam/assets/icon.png" - - [profiles.apps.runner] - type = "docker" - name = "WolfSteam" - image = "ghcr.io/games-on-whales/steam:edge" - devices = [] - env = [ - "RUN_SWAY=true", - "STEAM_STARTUP_FLAGS=-bigpicture", - "GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*", - "NVIDIA_VISIBLE_DEVICES=all", - "NVIDIA_DRIVER_CAPABILITIES=all" - ] - mounts = [ - "${pcGamesMount}/steam:/home/retro/Games/SteamLibrary:rw", - "${pcGamesMount}/downloads:/home/retro/Downloads:rw" - ] - ports = [] - base_create_json = """ - { - "HostConfig": { - "IpcMode": "host", - "CapAdd": ["NET_RAW", "MKNOD", "NET_ADMIN", "SYS_ADMIN", "SYS_NICE"], - "SecurityOpt": ["seccomp=unconfined", "apparmor=unconfined"], - "Ulimits": [{"Name":"nofile", "Hard":10240, "Soft":10240}], - "Privileged": false, - "DeviceRequests": [ - { - "Driver": "nvidia", - "Count": -1, - "Capabilities": [["gpu"]] - } - ], - "DeviceCgroupRules": ["c 13:* rmw", "c 244:* rmw"] - } - } - """ - ''; - wolfHeroicApp = '' - - [[profiles.apps]] - title = "Heroic" - start_virtual_compositor = true - app_state_folder = "heroic" - icon_png_path = "https://games-on-whales.github.io/wildlife/apps/heroic-games-launcher/assets/icon.png" - - [profiles.apps.runner] - type = "docker" - name = "WolfHeroic" - image = "ghcr.io/games-on-whales/heroic-games-launcher:edge" - devices = [] - env = [ - "RUN_SWAY=true", - "GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*", - "NVIDIA_VISIBLE_DEVICES=all", - "NVIDIA_DRIVER_CAPABILITIES=all" - ] - mounts = [ - "${pcGamesMount}/heroic:/home/retro/Games/Heroic:rw", - "${pcGamesMount}/downloads:/home/retro/Downloads:rw" - ] - ports = [] - base_create_json = """ - { - "HostConfig": { - "IpcMode": "host", - "CapAdd": ["SYS_ADMIN", "SYS_NICE", "SYS_PTRACE", "NET_RAW", "MKNOD", "NET_ADMIN"], - "SecurityOpt": ["seccomp=unconfined", "apparmor=unconfined"], - "Ulimits": [{"Name":"nofile", "Hard":10240, "Soft":10240}], - "Privileged": false, - "DeviceRequests": [ - { - "Driver": "nvidia", - "Count": -1, - "Capabilities": [["gpu"]] - } - ], - "DeviceCgroupRules": ["c 13:* rmw", "c 244:* rmw"] - } - } - """ - ''; - wolfLutrisApp = '' - - [[profiles.apps]] - title = "Lutris" - start_virtual_compositor = true - app_state_folder = "lutris" - icon_png_path = "https://games-on-whales.github.io/wildlife/apps/lutris/assets/icon.png" - - [profiles.apps.runner] - type = "docker" - name = "WolfLutris" - image = "ghcr.io/games-on-whales/lutris:edge" - devices = [] - env = [ - "RUN_SWAY=true", - "WINEPREFIX=/home/retro/Games/Prefixes/default", - "GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*", - "NVIDIA_VISIBLE_DEVICES=all", - "NVIDIA_DRIVER_CAPABILITIES=all" - ] - mounts = [ - "${pcGamesMount}/lutris:/home/retro/Games/Lutris:rw", - "${pcGamesMount}/prefixes:/home/retro/Games/Prefixes:rw", - "${pcGamesMount}/downloads:/home/retro/Downloads:rw" - ] - ports = [] - base_create_json = """ - { - "HostConfig": { - "IpcMode": "host", - "CapAdd": ["SYS_ADMIN", "SYS_NICE", "SYS_PTRACE", "NET_RAW", "MKNOD", "NET_ADMIN"], - "SecurityOpt": ["seccomp=unconfined", "apparmor=unconfined"], - "Ulimits": [{"Name":"nofile", "Hard":10240, "Soft":10240}], - "Privileged": false, - "DeviceRequests": [ - { - "Driver": "nvidia", - "Count": -1, - "Capabilities": [["gpu"]] - } - ], - "DeviceCgroupRules": ["c 13:* rmw", "c 244:* rmw"] - } - } - """ - ''; - wolfStoreApps = wolfSteamApp + wolfHeroicApp + wolfLutrisApp; - wolfBaseApps = '' - [[profiles.apps]] - title = "Wolf UI" - start_virtual_compositor = true - icon_png_path = "https://raw.githubusercontent.com/games-on-whales/wolf-ui/refs/heads/main/src/Icons/wolf_ui_icon.png" - - [profiles.apps.runner] - type = "docker" - name = "Wolf-UI" - image = "ghcr.io/games-on-whales/wolf-ui:main" - devices = [] - env = [ - "GOW_REQUIRED_DEVICES=/dev/input/event* /dev/dri/* /dev/nvidia*", - "WOLF_SOCKET_PATH=/var/run/wolf/wolf.sock", - "WOLF_UI_AUTOUPDATE=False", - "LOGLEVEL=INFO", - "NVIDIA_VISIBLE_DEVICES=all", - "NVIDIA_DRIVER_CAPABILITIES=all" - ] - mounts = [ - "/var/run/wolf/wolf.sock:/var/run/wolf/wolf.sock" - ] - ports = [] - base_create_json = """ - { - "HostConfig": { - "IpcMode": "host", - "CapAdd": ["NET_RAW", "MKNOD", "NET_ADMIN", "SYS_ADMIN", "SYS_NICE"], - "Privileged": false, - "DeviceRequests": [ - { - "Driver": "nvidia", - "Count": -1, - "Capabilities": [["gpu"]] - } - ], - "DeviceCgroupRules": ["c 13:* rmw", "c 244:* rmw"] - } - } - """ - - [[profiles.apps]] - title = "RetroArch" - start_virtual_compositor = true - app_state_folder = "retroarch" - icon_png_path = "https://games-on-whales.github.io/wildlife/apps/retroarch/assets/icon.png" - - [profiles.apps.runner] - type = "docker" - name = "WolfRetroArch" - image = "ghcr.io/games-on-whales/retroarch:edge" - devices = [] - env = [ - "RUN_SWAY=1", - "GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*", - "NVIDIA_VISIBLE_DEVICES=all", - "NVIDIA_DRIVER_CAPABILITIES=all" - ] - mounts = [ - "${gamesMount}:/ROMs:ro", - "${gamesMount}:/games:ro", - "${localRomsMount}:/ROMs-local:ro", - "${localGamesMount}:/games-local:ro" - ] - ports = [] - base_create_json = """ - { - "HostConfig": { - "IpcMode": "host", - "CapAdd": ["NET_RAW", "MKNOD", "NET_ADMIN"], - "Privileged": false, - "DeviceRequests": [ - { - "Driver": "nvidia", - "Count": -1, - "Capabilities": [["gpu"]] - } - ], - "DeviceCgroupRules": ["c 13:* rmw", "c 244:* rmw"] - } - } - """ - - [[profiles.apps]] - title = "EmulationStation" - start_virtual_compositor = true - app_state_folder = "es-de" - icon_png_path = "https://games-on-whales.github.io/wildlife/apps/es-de/assets/icon.png" - - [profiles.apps.runner] - type = "docker" - name = "WolfES-DE" - image = "ghcr.io/games-on-whales/es-de:edge" - devices = [] - env = [ - "RUN_SWAY=1", - "MOZ_ENABLE_WAYLAND=1", - "GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*", - "NVIDIA_VISIBLE_DEVICES=all", - "NVIDIA_DRIVER_CAPABILITIES=all" - ] - mounts = [ - "${gamesMount}:/ROMs:ro", - "${gamesMount}:/games:ro", - "${localRomsMount}:/ROMs-local:ro", - "${localGamesMount}:/games-local:ro" - ] - ports = [] - base_create_json = """ - { - "HostConfig": { - "IpcMode": "host", - "CapAdd": ["NET_RAW", "MKNOD", "NET_ADMIN"], - "Privileged": false, - "DeviceRequests": [ - { - "Driver": "nvidia", - "Count": -1, - "Capabilities": [["gpu"]] - } - ], - "DeviceCgroupRules": ["c 13:* rmw", "c 244:* rmw"] - } - } - """ - - [[profiles.apps]] - title = "Desktop" - start_virtual_compositor = true - app_state_folder = "xfce" - icon_png_path = "https://games-on-whales.github.io/wildlife/apps/xfce/assets/icon.png" - - [profiles.apps.runner] - type = "docker" - name = "WolfXFCE" - image = "ghcr.io/games-on-whales/xfce:edge" - devices = [] - env = [ - "GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*", - "NVIDIA_VISIBLE_DEVICES=all", - "NVIDIA_DRIVER_CAPABILITIES=all" - ] - mounts = [ - "${gamesMount}:/ROMs:ro", - "${gamesMount}:/games:ro", - "${localRomsMount}:/ROMs-local:ro", - "${localGamesMount}:/games-local:rw" - ] - ports = [] - base_create_json = """ - { - "HostConfig": { - "IpcMode": "host", - "CapAdd": ["SYS_ADMIN", "SYS_NICE", "SYS_PTRACE", "NET_RAW", "MKNOD", "NET_ADMIN"], - "SecurityOpt": ["seccomp=unconfined", "apparmor=unconfined"], - "Privileged": false, - "DeviceRequests": [ - { - "Driver": "nvidia", - "Count": -1, - "Capabilities": [["gpu"]] - } - ], - "DeviceCgroupRules": ["c 13:* rmw", "c 244:* rmw"] - } - } - """ - ''; - wolfConfigSeed = pkgs.writeText "wolf-config.toml" ( - '' - hostname = "enschede-gtx-960m-1" - support_hevc = false - config_version = 2 - uuid = "96000000-0000-4000-8000-000000000960" - - paired_clients = [] - gstreamer = {} - - [[profiles]] - id = "moonlight-profile-id" - name = "Moonlight" - - '' - + wolfBaseApps - + wolfStoreApps - ); - wolfSteamAppFile = pkgs.writeText "wolf-steam-app.toml" wolfSteamApp; - wolfHeroicAppFile = pkgs.writeText "wolf-heroic-app.toml" wolfHeroicApp; - wolfLutrisAppFile = pkgs.writeText "wolf-lutris-app.toml" wolfLutrisApp; -in -{ - users.users.${gameUser} = { - isNormalUser = true; - uid = 1001; - home = gameHome; - createHome = true; - description = "Moonlight game streaming state owner"; - extraGroups = [ - "audio" - "docker" - "input" - "render" - "uinput" - "video" - ]; - }; - - hardware.uinput.enable = true; - - boot.kernelModules = [ - "nvidia" - "nvidia_uvm" - "nvidia_drm" - "uhid" - "uinput" - ]; - boot.kernelParams = [ "nvidia-drm.modeset=1" ]; - - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - pulse.enable = true; - }; - - virtualisation.docker = { - enable = true; - autoPrune.enable = true; - }; - virtualisation.oci-containers = { - backend = "docker"; - containers.wolf = { - image = "ghcr.io/games-on-whales/wolf:stable"; - autoStart = true; - # Wolf creates per-session virtual displays, so Moonlight clients can - # request 720p, 1080p, 1440p, 4K30, or best-effort 4K60 without X11 modes. - environment = { - HOST_APPS_STATE_FOLDER = wolfState; - NVIDIA_DRIVER_CAPABILITIES = "all"; - NVIDIA_VISIBLE_DEVICES = "all"; - WOLF_CFG_FILE = "${wolfState}/cfg/config.toml"; - WOLF_DOCKER_SOCKET = "/var/run/docker.sock"; - WOLF_LOG_LEVEL = "INFO"; - WOLF_RENDER_NODE = "/dev/dri/renderD129"; - WOLF_SOCKET_PATH = "/var/run/wolf/wolf.sock"; - WOLF_STOP_CONTAINER_ON_EXIT = "TRUE"; - }; - volumes = [ - "${wolfState}:${wolfState}:rw" - "/run/wolf:/var/run/wolf:rw" - "/var/run/docker.sock:/var/run/docker.sock:rw" - "/dev:/dev:rw" - "/run/udev:/run/udev:rw" - ]; - extraOptions = [ - "--network=host" - "--device=nvidia.com/gpu=all" - "--device=/dev/dri" - "--device=/dev/uinput" - "--device=/dev/uhid" - "--device-cgroup-rule=c 13:* rmw" - "--device-cgroup-rule=c 244:* rmw" - ]; - }; - }; - - environment.systemPackages = with pkgs; [ - docker - docker-compose - exfatprogs - mesa-demos - moonlight-qt - ntfs3g - pciutils - vulkan-tools - ]; - - systemd.tmpfiles.rules = [ - "d ${gamesMount} 0755 root root - -" - "d ${localGamesMount} 0775 ${gameUser} users - -" - "d ${localGamesMount}/imports 0775 ${gameUser} users - -" - "d ${localGamesMount}/imports/t1000 0775 ${gameUser} users - -" - "d ${localRomsMount} 0775 ${gameUser} users - -" - "d ${localRomsMount}/switch 0775 ${gameUser} users - -" - "d ${localRomsMount}/wii 0775 ${gameUser} users - -" - "d ${pcGamesMount} 0775 ${gameUser} users - -" - "d ${pcGamesMount}/downloads 0775 ${gameUser} users - -" - "d ${pcGamesMount}/heroic 0775 ${gameUser} users - -" - "d ${pcGamesMount}/lutris 0775 ${gameUser} users - -" - "d ${pcGamesMount}/prefixes 0775 ${gameUser} users - -" - "d ${pcGamesMount}/steam 0775 ${gameUser} users - -" - "d /var/lib/personal-stack/wolfmanager 0750 root docker - -" - "d /var/lib/personal-stack/wolfmanager/config 0750 root docker - -" - "d /run/wolf 0750 root docker - -" - "d ${wolfState} 0750 root docker - -" - "d ${wolfState}/cfg 0750 root docker - -" - "d ${wolfState}/profile_data 0750 ${gameUser} users - -" - "d ${gameHome}/.config 0755 ${gameUser} users - -" - "d ${gameHome}/.local 0755 ${gameUser} users - -" - "d ${gameHome}/.local/share 0755 ${gameUser} users - -" - ]; - - systemd.services.wolf-config-seed = { - description = "Seed Wolf Moonlight streaming configuration"; - wantedBy = [ "multi-user.target" ]; - before = [ "docker-wolf.service" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - script = '' - install -d -m 0750 -o root -g docker ${wolfState}/cfg - if [ ! -e ${wolfState}/cfg/config.toml ]; then - install -m 0640 -o root -g docker ${wolfConfigSeed} ${wolfState}/cfg/config.toml - fi - ''; - }; - - systemd.services.wolf-config-reconcile = { - description = "Append missing Wolf PC launcher applications"; - wantedBy = [ "multi-user.target" ]; - after = [ "wolf-config-seed.service" ]; - before = [ "docker-wolf.service" ]; - requires = [ "wolf-config-seed.service" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - script = '' - config=${wolfState}/cfg/config.toml - backup=${wolfState}/cfg/config.toml.pre-store-launchers - - if [ ! -e "$backup" ]; then - cp -a "$config" "$backup" - fi - - append_app() { - title="$1" - app_file="$2" - if ! grep -Fq "title = \"$title\"" "$config" && ! grep -Fq "title = '$title'" "$config"; then - printf '\n' >> "$config" - cat "$app_file" >> "$config" - fi - } - - append_app Steam ${wolfSteamAppFile} - append_app Heroic ${wolfHeroicAppFile} - append_app Lutris ${wolfLutrisAppFile} - - chown root:docker "$config" - chmod 0640 "$config" - ''; - }; - - systemd.services.docker-wolf = { - after = [ - "docker.service" - "network-online.target" - "wolf-config-reconcile.service" - "wolf-config-seed.service" - ]; - requires = [ - "docker.service" - "wolf-config-reconcile.service" - "wolf-config-seed.service" - ]; - }; - - fileSystems.${gamesMount} = { - device = "/dev/disk/by-uuid/1120-414D"; - fsType = "vfat"; - options = [ - "nofail" - "noauto" - "ro" - "x-systemd.automount" - "x-systemd.device-timeout=10s" - "x-systemd.idle-timeout=10min" - ]; - }; - - networking.firewall = { - allowedTCPPorts = [ - 47984 - 47989 - 47990 - 48010 - ]; - allowedUDPPortRanges = [ - { - from = 47998; - to = 48010; - } - { - from = 8000; - to = 8010; - } - ]; - }; - - assertions = [ - { - assertion = config.hardware.nvidia.modesetting.enable; - message = "game-streaming.nix requires the NVIDIA driver profile with DRM modesetting enabled."; - } - { - assertion = config.hardware.nvidia-container-toolkit.enable; - message = "game-streaming.nix requires NVIDIA Container Toolkit for Wolf Docker GPU access."; - } - ]; -} diff --git a/platform/tests/host-definitions.test.js b/platform/tests/host-definitions.test.js index cc1ce081..909fec88 100644 --- a/platform/tests/host-definitions.test.js +++ b/platform/tests/host-definitions.test.js @@ -84,20 +84,50 @@ test('flake exports deploy targets for every ssh reachable inventory node', asyn } }) -test('gtx 960m host imports game streaming service', async () => { +test('gtx 960m host runs with the nvidia driver unloaded', async () => { const fleet = await loadFleet() - const flake = await readRepoText('platform/flake.nix') const hostDefinition = await readRepoText('platform/nix/hosts/enschede-gtx-960m-1/default.nix') - const module = await readRepoText('platform/nix/modules/services/game-streaming.nix') - const gpuProfile = await readRepoText('platform/nix/profiles/gpu-nvidia.nix') const gtxNode = fleet.nodes['enschede-gtx-960m-1'] - assert.ok(gtxNode.capabilities.includes('game-streaming')) - assert.ok(gtxNode.capabilities.includes('nvidia')) - assert.ok(fleet.service_intent.host_native['enschede-gtx-960m-1'].includes('game-streaming')) - assertContains(flake, 'deploy.nodes.enschede-gtx-960m-1', 'magicRollback = false') + + // Maxwell cannot runtime-suspend (Runtime D3 needs Turing or newer), so the + // card idles at full power for as long as a driver is bound to it. The host + // therefore claims no GPU capability at all. + assert.ok(!gtxNode.capabilities.includes('nvidia')) + assert.ok(!gtxNode.capabilities.includes('game-streaming')) + assert.equal(gtxNode.gpus, undefined) + assert.ok(!fleet.service_intent.host_native['enschede-gtx-960m-1'].includes('game-streaming')) + assert.ok(!('temporary_gpu_model' in fleet.placement_intent.gpu_specific.jellyfin)) + + assert.ok(!hostDefinition.includes('profiles/gpu-nvidia.nix')) + assert.ok(!hostDefinition.includes('modules/services/game-streaming.nix')) + assert.ok(!hostDefinition.includes('capability-nvidia')) + assert.ok(!hostDefinition.includes('capability-game-streaming')) + assert.ok(!hostDefinition.includes('gpu-model-gtx960m')) + assertContains( + hostDefinition, + 'boot.blacklistedKernelModules', + '"nouveau"', + '"nvidia"', + '"nvidia_drm"', + '"nvidia_modeset"', + '"nvidia_uvm"', + 'ATTR{vendor}=="0x10de"', + 'ATTR{power/control}="auto"', + ) +}) + +test('rx7900xtx host imports game streaming service', async () => { + const fleet = await loadFleet() + const flake = await readRepoText('platform/flake.nix') + const hostDefinition = await readRepoText('platform/nix/hosts/enschede-rx7900xtx-1/default.nix') + const module = await readRepoText('platform/nix/modules/services/game-streaming-amd.nix') + const amdNode = fleet.nodes['enschede-rx7900xtx-1'] + assert.ok(amdNode.capabilities.includes('game-streaming')) + assert.ok(fleet.service_intent.host_native['enschede-rx7900xtx-1'].includes('game-streaming')) + assertContains(flake, 'deploy.nodes.enschede-rx7900xtx-1') assertContains( hostDefinition, - '../../modules/services/game-streaming.nix', + '../../modules/services/game-streaming-amd.nix', '"personal-stack/capability-game-streaming" = "true"', ) assertContains( @@ -109,59 +139,44 @@ test('gtx 960m host imports game streaming service', async () => { 'ghcr.io/games-on-whales/steam:edge', 'ghcr.io/games-on-whales/heroic-games-launcher:edge', 'ghcr.io/games-on-whales/lutris:edge', - 'support_hevc = false', 'Wolf UI', 'title = "Steam"', 'title = "Heroic"', 'title = "Lutris"', 'STEAM_STARTUP_FLAGS=-bigpicture', 'WINEPREFIX=/home/retro/Games/Prefixes/default', - '4K60', 'virtualisation.docker', 'virtualisation.oci-containers', - 'WOLF_RENDER_NODE = "/dev/dri/renderD129"', + 'WOLF_RENDER_NODE = "/dev/dri/renderD128"', 'WOLF_SOCKET_PATH = "/var/run/wolf/wolf.sock"', '"/run/wolf:/var/run/wolf:rw"', 'd /var/lib/personal-stack/wolfmanager/config', - '"DeviceRequests"', - '--device=nvidia.com/gpu=all', '--network=host', '--device=/dev/uinput', '--device=/dev/uhid', 'hardware.uinput.enable = true', - 'nvidia-drm.modeset=1', 'boot.kernelModules', 'services.pipewire', 'uid = 1001', 'localGamesMount = "/srv/game-streaming"', - 'localRomsMount = "${localGamesMount}/roms"', - 'device = "/dev/disk/by-uuid/1120-414D"', - 'fsType = "vfat"', - 'fileSystems.${gamesMount}', 'wolf-config-seed', 'wolf-config-reconcile', - 'config.toml.pre-store-launchers', 'append_app Steam', 'append_app Heroic', 'append_app Lutris', - '${wolfState}/cfg/config.toml', - '${gamesMount}:/ROMs:ro', - '${localRomsMount}:/ROMs-local:ro', - '${localGamesMount}:/games-local:ro', - 'd ${localGamesMount}/imports/t1000', - '${pcGamesMount}/steam:/home/retro/Games/SteamLibrary:rw', - '${pcGamesMount}/heroic:/home/retro/Games/Heroic:rw', - '${pcGamesMount}/lutris:/home/retro/Games/Lutris:rw', - '${pcGamesMount}/prefixes:/home/retro/Games/Prefixes:rw', - '${pcGamesMount}/downloads:/home/retro/Downloads:rw', '47984', '47989', '47990', '48010', 'from = 8000', 'to = 8010', - 'hardware.nvidia-container-toolkit.enable', ) +}) + +test('gpu nvidia profile still covers the t1000 transcode host', async () => { + const gpuProfile = await readRepoText('platform/nix/profiles/gpu-nvidia.nix') + const t1000 = await readRepoText('platform/nix/hosts/enschede-t1000-1/default.nix') + assertContains(t1000, '../../profiles/gpu-nvidia.nix', '"personal-stack/capability-nvidia" = "true"') assertContains( gpuProfile, 'lib.hasPrefix "nvidia-" name', diff --git a/platform/tests/scaffold.test.js b/platform/tests/scaffold.test.js index a67100cb..11e08757 100644 --- a/platform/tests/scaffold.test.js +++ b/platform/tests/scaffold.test.js @@ -11,7 +11,7 @@ test('platform scaffold exists for nix and flux bootstrap', () => { 'platform/nix/profiles/utility.nix', 'platform/nix/profiles/gpu-nvidia.nix', 'platform/nix/modules/base/default.nix', - 'platform/nix/modules/services/game-streaming.nix', + 'platform/nix/modules/services/game-streaming-amd.nix', 'platform/nix/authorized-keys/README.md', 'platform/nix/modules/image/raspberry-pi-sd-image.nix', 'platform/nix/hosts/frankfurt-contabo-1/default.nix',