Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(kasmvnc): optimize KasmVNC deployment script #329

Merged
merged 31 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a8cc861
Refactor KasmVNC Deployment
djarbz Oct 24, 2024
8213a57
Make Prettier happy
djarbz Oct 24, 2024
6d6e0dd
Run KasmVNC server as coder user
djarbz Oct 24, 2024
c59ba95
Coder supports ssl now and remove sudo requirement
djarbz Oct 24, 2024
bb7d438
Require sudo to install only
djarbz Oct 24, 2024
10a86bd
Re-add SSL Req
djarbz Oct 24, 2024
46bbcb9
Alert KasmVNC started successfully
djarbz Oct 24, 2024
30e6bed
Remove unneeded shellcheck directive
djarbz Oct 24, 2024
4d831b4
Override kasm ssl certificate directives
djarbz Oct 24, 2024
9c3904d
Handle Fedora Distro Version
djarbz Oct 24, 2024
4a72b2e
Improve readability fo amd64 check
djarbz Oct 24, 2024
a2d8e72
Bash Array for download command
djarbz Oct 24, 2024
026a5bc
Don't mention distro
djarbz Oct 24, 2024
4fc9f6d
Bracket Consistency
djarbz Oct 24, 2024
d418c81
Naming cleanup
djarbz Oct 24, 2024
c4f88fa
cat vs tee
djarbz Oct 24, 2024
52ba74c
Update wording
djarbz Oct 24, 2024
d619e65
Print logs on failure
djarbz Oct 24, 2024
eff921e
Portability of checking server status
djarbz Oct 24, 2024
eb974cb
dnf localinstall
djarbz Oct 24, 2024
f3a0f98
Show up to 10 lines of log
djarbz Oct 24, 2024
ab96d93
Cleanup Package Install
djarbz Oct 25, 2024
ebc57a1
We don't use SSL Certificates
djarbz Oct 25, 2024
86b48dd
Prefer /etc instead of /home for Kasm Config
djarbz Oct 25, 2024
15e3ec2
Prettier formatting
djarbz Oct 25, 2024
41baf48
Do not overwrite custom user config
djarbz Oct 25, 2024
7d7c7e8
Prettier Format
djarbz Oct 25, 2024
f35b535
Fix Typo
djarbz Oct 25, 2024
a0373c0
Cleanup architecture mapping
djarbz Oct 25, 2024
ccf299b
Prettier Format
djarbz Oct 25, 2024
ef4f704
Merge branch 'main' into kasmVNC_optimize
matifali Oct 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kasmvnc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Automatically install [KasmVNC](https://kasmweb.com/kasmvnc) in a workspace, and
```tf
module "kasmvnc" {
source = "registry.coder.com/modules/kasmvnc/coder"
version = "1.0.22"
version = "1.0.23"
agent_id = coder_agent.example.id
desktop_environment = "xfce"
}
Expand Down
2 changes: 1 addition & 1 deletion kasmvnc/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ resource "coder_script" "kasm_vnc" {
script = templatefile("${path.module}/run.sh", {
PORT : var.port,
DESKTOP_ENVIRONMENT : var.desktop_environment,
VERSION : var.kasm_version
KASM_VERSION : var.kasm_version
})
run_on_start = true
}
Expand Down
264 changes: 160 additions & 104 deletions kasmvnc/run.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env bash

#!/bin/bash
# Exit on error, undefined variables, and pipe failures
set -euo pipefail

# Function to check if vncserver is already installed
check_installed() {
Expand All @@ -14,166 +15,221 @@ check_installed() {

# Function to download a file using wget, curl, or busybox as a fallback
download_file() {
local url=$1
local output=$2
if command -v wget &> /dev/null; then
wget $url -O $output
elif command -v curl &> /dev/null; then
curl -fsSL $url -o $output
local url="$1"
local output="$2"
local download_tool

if command -v curl &> /dev/null; then
# shellcheck disable=SC2034
download_tool=(curl -fsSL)
elif command -v wget &> /dev/null; then
# shellcheck disable=SC2034
download_tool=(wget -q -O-)
elif command -v busybox &> /dev/null; then
busybox wget -O $output $url
# shellcheck disable=SC2034
download_tool=(busybox wget -O-)
else
echo "Neither wget, curl, nor busybox is installed. Please install one of them to proceed."
echo "ERROR: No download tool available (curl, wget, or busybox required)"
exit 1
fi

# shellcheck disable=SC2288
"$${download_tool[@]}" "$url" > "$output" || {
echo "ERROR: Failed to download $url"
exit 1
}
}

# Function to install kasmvncserver for debian-based distros
install_deb() {
local url=$1
download_file $url /tmp/kasmvncserver.deb
sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get install --yes -qq --no-install-recommends --no-install-suggests /tmp/kasmvncserver.deb
sudo adduser $USER ssl-cert
rm /tmp/kasmvncserver.deb
}
local kasmdeb="/tmp/kasmvncserver.deb"

# Function to install kasmvncserver for Oracle 8
install_rpm_oracle8() {
local url=$1
download_file $url /tmp/kasmvncserver.rpm
sudo dnf config-manager --set-enabled ol8_codeready_builder
sudo dnf install oracle-epel-release-el8 -y
sudo dnf localinstall /tmp/kasmvncserver.rpm -y
sudo usermod -aG kasmvnc-cert $USER
rm /tmp/kasmvncserver.rpm
}
download_file "$url" "$kasmdeb"

# Function to install kasmvncserver for CentOS 7
install_rpm_centos7() {
djarbz marked this conversation as resolved.
Show resolved Hide resolved
local url=$1
download_file $url /tmp/kasmvncserver.rpm
sudo yum install epel-release -y
sudo yum install /tmp/kasmvncserver.rpm -y
sudo usermod -aG kasmvnc-cert $USER
rm /tmp/kasmvncserver.rpm
CACHE_DIR="/var/lib/apt/lists/partial"
# Check if the directory exists and was modified in the last 60 minutes
if [[ ! -d "$CACHE_DIR" ]] || ! find "$CACHE_DIR" -mmin -60 -print -quit &> /dev/null; then
echo "Stale package cache, updating..."
# Update package cache with a 300-second timeout for dpkg lock
sudo apt-get -o DPkg::Lock::Timeout=300 -qq update
fi

DEBIAN_FRONTEND=noninteractive sudo apt-get -o DPkg::Lock::Timeout=300 install --yes -qq --no-install-recommends --no-install-suggests "$kasmdeb"
rm "$kasmdeb"
}

# Function to install kasmvncserver for rpm-based distros
install_rpm() {
local url=$1
download_file $url /tmp/kasmvncserver.rpm
sudo rpm -i /tmp/kasmvncserver.rpm
rm /tmp/kasmvncserver.rpm
local kasmrpm="/tmp/kasmvncserver.rpm"
local package_manager

if command -v dnf &> /dev/null; then
# shellcheck disable=SC2034
package_manager=(dnf localinstall -y)
elif command -v zypper &> /dev/null; then
# shellcheck disable=SC2034
package_manager=(zypper install -y)
elif command -v yum &> /dev/null; then
# shellcheck disable=SC2034
package_manager=(yum localinstall -y)
elif command -v rpm &> /dev/null; then
# Do we need to manually handle missing dependencies?
# shellcheck disable=SC2034
package_manager=(rpm -i)
else
echo "ERROR: No supported package manager available (dnf, zypper, yum, or rpm required)"
exit 1
fi

download_file "$url" "$kasmrpm"

# shellcheck disable=SC2288
sudo "$${package_manager[@]}" "$kasmrpm" || {
echo "ERROR: Failed to install $kasmrpm"
exit 1
}

rm "$kasmrpm"
}

# Function to install kasmvncserver for Alpine Linux
install_alpine() {
local url=$1
download_file $url /tmp/kasmvncserver.tgz
tar -xzf /tmp/kasmvncserver.tgz -C /usr/local/bin/
rm /tmp/kasmvncserver.tgz
local kasmtgz="/tmp/kasmvncserver.tgz"

download_file "$url" "$kasmtgz"

tar -xzf "$kasmtgz" -C /usr/local/bin/
rm "$kasmtgz"
}

# Detect system information
distro=$(grep "^ID=" /etc/os-release | awk -F= '{print $2}')
version=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"')
arch=$(uname -m)
if [[ ! -f /etc/os-release ]]; then
djarbz marked this conversation as resolved.
Show resolved Hide resolved
echo "ERROR: Cannot detect OS: /etc/os-release not found"
exit 1
fi

# shellcheck disable=SC1091
source /etc/os-release
distro="$ID"
distro_version="$VERSION_ID"
codename="$VERSION_CODENAME"
arch="$(uname -m)"
if [[ "$ID" == "ol" ]]; then
distro="oracle"
distro_version="$${distro_version%%.*}"
elif [[ "$ID" == "fedora" ]]; then
distro_version="$(grep -oP '\(\K[\w ]+' /etc/fedora-release | tr '[:upper:]' '[:lower:]' | tr -d ' ')"
fi

echo "Detected Distribution: $distro"
echo "Detected Version: $version"
echo "Detected Version: $distro_version"
echo "Detected Codename: $codename"
echo "Detected Architecture: $arch"

# Map arch to package arch
if [[ "$arch" == "x86_64" ]]; then
if [[ "$distro" == "ubuntu" || "$distro" == "debian" || "$distro" == "kali" ]]; then
arch="amd64"
else
arch="x86_64"
fi
elif [[ "$arch" == "aarch64" || "$arch" == "arm64" ]]; then
if [[ "$distro" == "ubuntu" || "$distro" == "debian" || "$distro" == "kali" ]]; then
arch="arm64"
else
arch="aarch64"
fi
else
echo "Unsupported architecture: $arch"
exit 1
fi
case "$arch" in
x86_64)
if [[ "$distro" =~ ^(ubuntu|debian|kali)$ ]]; then
arch="amd64"
fi
;;
aarch64)
if [[ "$distro" =~ ^(ubuntu|debian|kali)$ ]]; then
arch="arm64"
fi
;;
arm64)
: # This is effectively a noop
;;
*)
echo "ERROR: Unsupported architecture: $arch"
exit 1
;;
esac

# Check if vncserver is installed, and install if not
if ! check_installed; then
echo "Installing KASM version: ${VERSION}"
# Check for NOPASSWD sudo (required)
if ! command -v sudo &> /dev/null || ! sudo -n true 2> /dev/null; then
echo "ERROR: sudo NOPASSWD access required!"
exit 1
fi

base_url="https://github.com/kasmtech/KasmVNC/releases/download/v${KASM_VERSION}"

echo "Installing KASM version: ${KASM_VERSION}"
case $distro in
ubuntu | debian | kali)
case $version in
"20.04")
install_deb "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_focal_${VERSION}_$${arch}.deb"
;;
"22.04")
install_deb "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_jammy_${VERSION}_$${arch}.deb"
;;
"24.04")
install_deb "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_noble_${VERSION}_$${arch}.deb"
;;
*)
echo "Unsupported Ubuntu/Debian/Kali version: $${version}"
exit 1
;;
esac
bin_name="kasmvncserver_$${codename}_${KASM_VERSION}_$${arch}.deb"
install_deb "$base_url/$bin_name"
;;
oracle)
if [[ "$version" == "8" ]]; then
install_rpm_oracle8 "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_oracle_8_${VERSION}_$${arch}.rpm"
else
echo "Unsupported Oracle version: $${version}"
exit 1
fi
;;
centos)
if [[ "$version" == "7" ]]; then
install_rpm_centos7 "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_centos_core_${VERSION}_$${arch}.rpm"
else
install_rpm "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_centos_core_${VERSION}_$${arch}.rpm"
fi
oracle | fedora | opensuse)
bin_name="kasmvncserver_$${distro}_$${distro_version}_${KASM_VERSION}_$${arch}.rpm"
djarbz marked this conversation as resolved.
Show resolved Hide resolved
install_rpm "$base_url/$bin_name"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need both install_rpm and install_dnf. I just tried the opensuse/leap image and it has neither dnf nor yum, only zypper and rpm.

I'm not sure if this is a script meant for installing the kasmvnc built package or something else, but this at least gives hints for the expectation per distro: https://github.com/kasmtech/KasmVNC/blob/3a8517d7dc461eaccc7ed8e3d3b155e233426fc8/builder/scripts/common.sh#L22-L29

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps in the install_rpm function, we have a switch case to select based on what tooling is available?
Similar to the download function?

Priority:

  1. dnf
  2. zypper
  3. yum
  4. rpm

;;
alpine)
if [[ "$version" == "3.17" || "$version" == "3.18" || "$version" == "3.19" || "$version" == "3.20" ]]; then
install_alpine "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvnc.alpine_$${version}_$${arch}.tgz"
else
echo "Unsupported Alpine version: $${version}"
exit 1
fi
;;
fedora | opensuse)
install_rpm "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_$${distro}_$${version}_${VERSION}_$${arch}.rpm"
bin_name="kasmvnc.alpine_$${distro_version//./}_$${arch}.tgz"
install_alpine "$base_url/$bin_name"
;;
*)
echo "Unsupported distribution: $${distro}"
echo "Unsupported distribution: $distro"
exit 1
;;
esac
else
echo "vncserver already installed. Skipping installation."
fi

# Coder port-forwarding from dashboard only supports HTTP
sudo bash -c "cat > /etc/kasmvnc/kasmvnc.yaml <<EOF
if command -v sudo &> /dev/null && sudo -n true 2> /dev/null; then
kasm_config_file="/etc/kasmvnc/kasmvnc.yaml"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need sudo mkdir -p /etc/kasmvnc here like for the user config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not run into the need for it.
I can add it as a catchall just in case if you want?

SUDO=sudo
else
kasm_config_file="$HOME/.vnc/kasmvnc.yaml"
SUDO=

echo "WARNING: Sudo access not available, using user config dir!"

if [[ -f "$kasm_config_file" ]]; then
echo "WARNING: Custom user KasmVNC config exists, not overwriting!"
echo "WARNING: Ensure that you manually configure the appropriate settings."
kasm_config_file="/dev/stderr"
djarbz marked this conversation as resolved.
Show resolved Hide resolved
else
echo "WARNING: This may prevent custom user KasmVNC settings from applying!"
mkdir -p "$HOME/.vnc"
fi
fi

echo "Writing KasmVNC config to $kasm_config_file"
$SUDO tee "$kasm_config_file" > /dev/null << EOF
network:
protocol: http
websocket_port: ${PORT}
ssl:
require_ssl: false
pem_certificate:
pem_key:
udp:
public_ip: 127.0.0.1
EOF"
EOF

# This password is not used since we start the server without auth.
# The server is protected via the Coder session token / tunnel
# and does not listen publicly
echo -e "password\npassword\n" | vncpasswd -wo -u $USER
echo -e "password\npassword\n" | vncpasswd -wo -u "$USER"

# Start the server
printf "🚀 Starting KasmVNC server...\n"
sudo -u $USER bash -c "vncserver -select-de ${DESKTOP_ENVIRONMENT} -disableBasicAuth" > /tmp/kasmvncserver.log 2>&1 &
vncserver -select-de "${DESKTOP_ENVIRONMENT}" -disableBasicAuth > /tmp/kasmvncserver.log 2>&1 &
pid=$!

# Wait for server to start
sleep 5
grep -v '^[[:space:]]*$' /tmp/kasmvncserver.log | tail -n 10
if ps -p $pid | grep -q "^$pid"; then
echo "ERROR: Failed to start KasmVNC server. Check full logs at /tmp/kasmvncserver.log"
exit 1
fi
printf "🚀 KasmVNC server started successfully!\n"