Skip to content

Commit

Permalink
resolve undefined type error
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Roby committed Nov 25, 2023
1 parent 8da77ac commit 655c07f
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 3 deletions.
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ inputs:
description:
'The path to mount the workspace inside the docker container. For windows, leave out the drive letter. For example
c:/github/workspace should be defined as /github/workspace'
nvidiaGpus:
default: ''
required: false
description: 'Specify a Nvidia GPU to attach to the builder container.'

outputs:
volume:
Expand Down
10 changes: 8 additions & 2 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/platforms/ubuntu/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mkdir -p "$ACTIVATE_LICENSE_PATH"
#
# Run steps
#
source /steps/startx.sh
source /steps/set_extra_git_configs.sh
source /steps/set_gitcredential.sh
source /steps/activate.sh
Expand Down
238 changes: 238 additions & 0 deletions dist/platforms/ubuntu/steps/startx.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#!/bin/bash -e

# Source:
# https://github.com/selkies-project/docker-nvidia-glx-desktop/blob/main/entrypoint.sh
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

# Make all NVIDIA GPUs visible by default
export NVIDIA_VISIBLE_DEVICES=all
export DEBIAN_FRONTEND=noninteractive
export NVIDIA_DRIVER_CAPABILITIES=all
export APPIMAGE_EXTRACT_AND_RUN=1

# System defaults that should not be changed
export DISPLAY=:0
export XDG_RUNTIME_DIR=/tmp/runtime-user
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:/usr/lib/i386-linux-gnu${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

# Default environment variables
export TZ=UTC
export SIZEW=1920
export SIZEH=1080
export REFRESH=60
export DPI=96
export CDEPTH=24
export VIDEO_PORT=DFP
export VNC_ENABLED=true
export RECORD_SCREEN=false

apt-get update
apt-get install -y tmux \
xorg \
xinit \
xterm \
icewm \
dbus-x11 \
xserver-xorg-core

if [ "${VNC_ENABLED}" == "true" ]; then
apt-get install -y x11vnc xvfb
fi

if [ "${RECORD_SCREEN}" == "true" ]; then
apt-get install -y ffmpeg
fi


init(){
# Start DBus without systemd
/etc/init.d/dbus start

# Change time zone from environment variable
ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" | tee /etc/timezone > /dev/null

# This symbolic link enables running Xorg inside a container with `-sharevts`
ln -snf /dev/ptmx /dev/tty7

# Allow starting Xorg from a pseudoterminal instead of strictly on a tty console
if [ ! -f /etc/X11/Xwrapper.config ]; then
echo -e "allowed_users=anybody\nneeds_root_rights=yes" | tee /etc/X11/Xwrapper.config > /dev/null
fi

if grep -Fxq "allowed_users=console" /etc/X11/Xwrapper.config; then
sed -i "s/allowed_users=console/allowed_users=anybody/;$ a needs_root_rights=yes" /etc/X11/Xwrapper.config
fi
}

install_driver() {
# Install NVIDIA userspace driver components including X graphic libraries
if ! command -v nvidia-xconfig &> /dev/null; then
# Driver version is provided by the kernel through the container toolkit
export DRIVER_VERSION=$(head -n1 </proc/driver/nvidia/version | awk '{print$8}')
cd /tmp
# If version is different, new installer will overwrite the existing components
if [ ! -f "/tmp/NVIDIA-Linux-x86_64-$DRIVER_VERSION.run" ]; then
# Check multiple sources in order to probe both consumer and datacenter driver versions
curl --progress-bar -fL -O "https://us.download.nvidia.com/XFree86/Linux-x86_64/$DRIVER_VERSION/NVIDIA-Linux-x86_64-$DRIVER_VERSION.run" || curl --progress-bar -fL -O "https://us.download.nvidia.com/tesla/$DRIVER_VERSION/NVIDIA-Linux-x86_64-$DRIVER_VERSION.run" || { echo "Failed NVIDIA GPU driver download. Exiting."; exit 1; }
fi
# Extract installer before installing
sh "NVIDIA-Linux-x86_64-$DRIVER_VERSION.run" -x
cd "NVIDIA-Linux-x86_64-$DRIVER_VERSION"
# Run installation without the kernel modules and host components
./nvidia-installer --silent \
--no-kernel-module \
--install-compat32-libs \
--no-nouveau-check \
--no-nvidia-modprobe \
--no-rpms \
--no-backup \
--no-check-for-alternate-installs || true
rm -rf /tmp/NVIDIA* && cd ~
fi
}

find_gpu(){
# Get first GPU device if all devices are available or `NVIDIA_VISIBLE_DEVICES` is not set
if [ "$NVIDIA_VISIBLE_DEVICES" == "all" ]; then
export GPU_SELECT=$(nvidia-smi --query-gpu=uuid --format=csv | sed -n 2p)
elif [ -z "$NVIDIA_VISIBLE_DEVICES" ]; then
export GPU_SELECT=$(nvidia-smi --query-gpu=uuid --format=csv | sed -n 2p)
# Get first GPU device out of the visible devices in other situations
else
export GPU_SELECT=$(nvidia-smi --id=$(echo "$NVIDIA_VISIBLE_DEVICES" | cut -d ',' -f1) --query-gpu=uuid --format=csv | sed -n 2p)
if [ -z "$GPU_SELECT" ]; then
export GPU_SELECT=$(nvidia-smi --query-gpu=uuid --format=csv | sed -n 2p)
fi
fi

if [ -z "$GPU_SELECT" ]; then
echo "No NVIDIA GPUs detected or nvidia-container-toolkit not configured. Using a dummy device."
apt-get install -y xserver-xorg-video-dummy
wget -O /xorg.conf https://raw.githubusercontent.com/buildstar-online/nvidia-desktops/main/firefox/dummy-xorg.conf
mv /xorg.conf /etc/X11/xorg.conf
else
apt-get install -y kmod pkg-config
install_driver
create_xorg_conf
fi

# Setting `VIDEO_PORT` to none disables RANDR/XRANDR, do not set this if using datacenter GPUs
if [ "${VIDEO_PORT,,}" = "none" ]; then
export CONNECTED_MONITOR="--use-display-device=None"
# The X server is otherwise deliberately set to a specific video port despite not
# being plugged to enable RANDR/XRANDR, monitor will display the screen if plugged to the
# specific port
else
export CONNECTED_MONITOR="--connected-monitor=${VIDEO_PORT}"
fi
}

create_xorg_conf(){
# Bus ID from nvidia-smi is in hexadecimal format, should be converted to decimal
# format which Xorg understands, required because nvidia-xconfig doesn't work as intended in
# a container
HEX_ID=$(nvidia-smi --query-gpu=pci.bus_id --id="$GPU_SELECT" --format=csv |sed -n 2p)
IFS=":." ARR_ID=($HEX_ID)
unset IFS
BUS_ID=PCI:$((16#${ARR_ID[1]})):$((16#${ARR_ID[2]})):$((16#${ARR_ID[3]}))

# A custom modeline should be generated because there is no monitor to fetch this
# information normally
export MODELINE=$(cvt -r "${SIZEW}" "${SIZEH}" "${REFRESH}" | sed -n 2p)

# Generate /etc/X11/xorg.conf with nvidia-xconfig
nvidia-xconfig --virtual="${SIZEW}x${SIZEH}" --depth="$CDEPTH" --mode=$(echo "$MODELINE" | awk '{print $2}' | tr -d '"') \
--allow-empty-initial-configuration \
--no-probe-all-gpus \
--busid="$BUS_ID" \
--no-multigpu \
--no-sli \
--no-base-mosaic \
--only-one-x-screen ${CONNECTED_MONITOR}

# Guarantee that the X server starts without a monitor by adding more options to
# the configuration
sed -i '/Driver\s\+"nvidia"/a\ Option "ModeValidation" "NoMaxPClkCheck, NoEdidMaxPClkCheck, NoMaxSizeCheck, NoHorizSyncCheck, NoVertRefreshCheck, NoVirtualSizeCheck, NoExtendedGpuCapabilitiesCheck, NoTotalSizeCheck, NoDualLinkDVICheck, NoDisplayPortBandwidthCheck, AllowNon3DVisionModes, AllowNonHDMI3DModes, AllowNonEdidModes, NoEdidHDMI2Check, AllowDpInterlaced"\n Option "HardDPMS" "False"' /etc/X11/xorg.conf

# Add custom generated modeline to the configuration
sed -i '/Section\s\+"Monitor"/a\ '"$MODELINE" /etc/X11/xorg.conf
}

start_app(){
# Since we dont boot the system with systemd, starting and maintaining long-running
# processes is tricky and has multiple approaches. You can do as the Nvidia-GLX-Desktop
# does and use supervisord to start process as shown in the link below.
# - https://github.com/selkies-project/docker-nvidia-glx-desktop/blob/main/supervisord.conf
#
# You can also use this neat project to simulate systemd/systemctl in a container:
# - https://github.com/gdraheim/docker-systemctl-replacement
#
# I'm using another option, which is to use tmux to manage sessions of the individual application.
# this method is janky and fragile but I think it's easier to use during development because
# it only relies on tmux (no special dependancies or extra config files) and attaching to the
# sessions via tmux attach-session -t <app> is easier and more intuitive than trying to find
# the process ID and re-attach a shell. Additionally it prevents the main user-shell from being
# monopoloized by stdout messages from supervisord andallows for additional commands to be run after
# entrypoint.sh has finished.
#
# I will probably switch to using supervisord or docker-systemctl-replacement later as a more
# stable solution after I'm done making constant changes to the project.

# Starts an empty Xorg session on DDISPLAY:0
tmux new-session -d -s "xorg"
tmux send-keys -t "xorg" "export DISPLAY=:0 && \
Xorg vt7 \
-noreset \
-novtswitch \
-sharevts \
-dpi ${DPI} \
+extension GLX \
+extension RANDR \
+extension RENDER \
+extension MIT-SHM ${DISPLAY}" ENTER

echo "Waiting for X socket"
until [ -S "/tmp/.X11-unix/X${DISPLAY/:/}" ]; do sleep 1; done
echo "X socket is ready"

# Start an x11vnc session that brodcasts the contents our X session
if [ "${VNC_ENABLED}" == "true" ]; then
tmux new-session -d -s "x11vnc"
tmux send-keys -t "x11vnc" "export DISPLAY=:0 && \
x11vnc -display ${DISPLAY} \
-shared \
-loop \
-repeat \
-xkb \
-snapfb \
-threads \
-xrandr resize \
-rfbport 5900 ${NOVNC_VIEWONLY}" ENTER
fi

# Start the desktop session
tmux new-session -d -s "app"
tmux send-keys -t "app" "export DISPLAY=:0 && \
icewm-session" ENTER

# Start recording the screen
if [ "$RECORD_SCREEN" == "true" ]; then
tmux new-session -d -s "ffmpeg"
tmux send-keys -t "ffmpeg" "export DISPLAY=:0 && \
ffmpeg -r ${REFRESH} \
-f x11grab \
-draw_mouse 1 \
-s ${SIZEW}x${SIZEH} \
-i ${DISPLAY} \
-c:v h264_nvenc \
-preset 8 \
/home/${USER}/desktop-recording.mp4" ENTER
fi
}

init
find_gpu
start_app

1 change: 1 addition & 0 deletions src/model/__mocks__/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const mockGetFromUser = jest.fn().mockResolvedValue({
sshAgent: '',
chownFilesTo: '',
gitPrivateToken: '',
nvidiaGpus: '',
});

export default {
Expand Down
2 changes: 2 additions & 0 deletions src/model/build-parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class BuildParameters {
public cacheUnityInstallationOnMac!: boolean;
public unityHubVersionOnMac!: string;
public dockerWorkspacePath!: string;
public nvidiaGpus!: string;

public static shouldUseRetainedWorkspaceMode(buildParameters: BuildParameters) {
return buildParameters.maxRetainedWorkspaces > 0 && CloudRunner.lockedWorkspace !== ``;
Expand Down Expand Up @@ -212,6 +213,7 @@ class BuildParameters {
cacheUnityInstallationOnMac: Input.cacheUnityInstallationOnMac,
unityHubVersionOnMac: Input.unityHubVersionOnMac,
dockerWorkspacePath: Input.dockerWorkspacePath,
nvidiaGpus: Input.nvidiaGpus,
};
}

Expand Down
4 changes: 4 additions & 0 deletions src/model/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Docker {
dockerWorkspacePath,
dockerCpuLimit,
dockerMemoryLimit,
nvidiaGpus,
} = parameters;

const githubHome = path.join(runnerTempPath, '_github_home');
Expand All @@ -61,6 +62,7 @@ class Docker {
return `docker run \
--workdir ${dockerWorkspacePath} \
--rm \
${nvidiaGpus ? `--gpus all` : ''} \
${ImageEnvironmentFactory.getEnvVarString(parameters, additionalVariables)} \
--env GITHUB_WORKSPACE=${dockerWorkspacePath} \
--env GIT_CONFIG_EXTENSIONS \
Expand Down Expand Up @@ -98,11 +100,13 @@ class Docker {
dockerCpuLimit,
dockerMemoryLimit,
dockerIsolationMode,
nvidiaGpus,
} = parameters;

return `docker run \
--workdir c:${dockerWorkspacePath} \
--rm \
${nvidiaGpus ? `--gpus all` : ''} \
${ImageEnvironmentFactory.getEnvVarString(parameters)} \
--env GITHUB_WORKSPACE=c:${dockerWorkspacePath} \
${gitPrivateToken ? `--env GIT_PRIVATE_TOKEN="${gitPrivateToken}"` : ''} \
Expand Down
4 changes: 4 additions & 0 deletions src/model/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ class Input {
return Input.getInput('containerRegistryImageVersion')!;
}

static get nvidiaGpus(): string {
return Input.getInput('nvidiaGpus') || '0';
}

public static ToEnvVarFormat(input: string) {
if (input.toUpperCase() === input) {
return input;
Expand Down

0 comments on commit 655c07f

Please sign in to comment.