Initial snapshot before transformerlab recovery
This commit is contained in:
@@ -0,0 +1,514 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
ANSIBLE_VENV="$ROOT_DIR/.venv-ansible"
|
||||
ANSIBLE_PYTHON="$ANSIBLE_VENV/bin/python"
|
||||
ANSIBLE_PLAYBOOK="$ANSIBLE_VENV/bin/ansible-playbook"
|
||||
export ANSIBLE_CONFIG="$ROOT_DIR/ansible/ansible.cfg"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
./labctl up
|
||||
./labctl down
|
||||
./labctl preflight
|
||||
./labctl versions
|
||||
./labctl start [core|all|service...]
|
||||
./labctl stop [all|service...]
|
||||
./labctl status [all|service...]
|
||||
./labctl urls
|
||||
./labctl open kiln
|
||||
./labctl logs <service>
|
||||
EOF
|
||||
}
|
||||
|
||||
transformerlab_version() {
|
||||
local version_file=$ROOT_DIR/ansible/group_vars/all.yml
|
||||
|
||||
if [ ! -f "$version_file" ]; then
|
||||
printf '%s\n' "unknown"
|
||||
return
|
||||
fi
|
||||
|
||||
sed -nE 's/^courseware_transformerlab_version:[[:space:]]*"([^"]+)".*/\1/p' "$version_file" | head -n 1
|
||||
}
|
||||
|
||||
print_versions() {
|
||||
cat <<EOF
|
||||
Pinned component versions:
|
||||
TransformerLab: $(transformerlab_version) (single-user pinned install)
|
||||
Ansible Core: 2.18.6
|
||||
EOF
|
||||
}
|
||||
|
||||
confirm_installation() {
|
||||
local response
|
||||
local tlab_version
|
||||
tlab_version=$(transformerlab_version)
|
||||
|
||||
if [ ! -t 0 ]; then
|
||||
cat <<EOF >&2
|
||||
WARNING: THIS SCRIPT WILL CONFIGURE YOUR ENVIRONMENT WILL THE FOLLOWING SOFTWARE:
|
||||
|
||||
- Ollama
|
||||
- llama.cpp
|
||||
- TransformerLab (single-user pinned to ${tlab_version})
|
||||
- Open WebUI
|
||||
- ChunkViz
|
||||
- Embedding Atlas
|
||||
- Promptfoo
|
||||
- Unsloth Studio
|
||||
- Kiln Desktop
|
||||
- Course-specific support assets for lab 2 and lab 4
|
||||
|
||||
IT IS RECOMMENDED TO RUN THIS IN AN ISLOATED ENVIRONMENT (Dedicated WSL, VM, etc.)
|
||||
|
||||
This process may take a long time.
|
||||
|
||||
This command requires interactive confirmation. Re-run it from a terminal and answer the prompt.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
WARNING: THIS SCRIPT WILL CONFIGURE YOUR ENVIRONMENT WILL THE FOLLOWING SOFTWARE:
|
||||
|
||||
- Ollama
|
||||
- llama.cpp
|
||||
- TransformerLab (single-user pinned to ${tlab_version})
|
||||
- Open WebUI
|
||||
- ChunkViz
|
||||
- Embedding Atlas
|
||||
- Promptfoo
|
||||
- Unsloth Studio
|
||||
- Kiln Desktop
|
||||
- Course-specific support assets for lab 2 and lab 4
|
||||
|
||||
IT IS RECOMMENDED TO RUN THIS IN AN ISLOATED ENVIRONMENT (Dedicated WSL, VM, etc.)
|
||||
|
||||
This process may take a long time.
|
||||
EOF
|
||||
|
||||
read -r -p "CONFIRM INSTALLATION (y/N): " response
|
||||
case "$response" in
|
||||
y|Y)
|
||||
;;
|
||||
*)
|
||||
echo "Installation cancelled."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
host_is_wsl() {
|
||||
[ "$(uname -s)" = "Linux" ] && uname -r | grep -qiE 'microsoft|wsl'
|
||||
}
|
||||
|
||||
host_is_arm_mac() {
|
||||
[ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ]
|
||||
}
|
||||
|
||||
check_wsl_gpu_readiness() {
|
||||
if host_is_arm_mac; then
|
||||
return
|
||||
fi
|
||||
|
||||
if ! host_is_wsl; then
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
cat <<'EOF' >&2
|
||||
WSL GPU support is not ready yet, so the installer is stopping before Ansible runs.
|
||||
|
||||
This courseware expects WSL to already see your NVIDIA GPU.
|
||||
|
||||
Please do this on the Windows side first:
|
||||
1. Install or update the current NVIDIA Windows driver with WSL/CUDA support.
|
||||
2. Open Windows PowerShell and run: wsl --update
|
||||
3. Fully restart WSL: wsl --shutdown
|
||||
4. Reopen your Linux distro and confirm this works: nvidia-smi
|
||||
|
||||
If `nvidia-smi` still fails inside WSL:
|
||||
- Reboot Windows
|
||||
- Confirm WSL 2 is in use
|
||||
- Confirm the GPU is NVIDIA and the Windows driver is recent
|
||||
|
||||
After `nvidia-smi` works inside WSL, rerun:
|
||||
bash deploy-courseware.sh
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
linux_cuda_toolkit_is_ready() {
|
||||
command -v nvcc >/dev/null 2>&1 && return 0
|
||||
[ -f /usr/local/cuda/include/cuda_runtime.h ] && return 0
|
||||
[ -f /usr/include/cuda_runtime.h ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
linux_cuda_toolkit_package_is_available() {
|
||||
command -v apt-cache >/dev/null 2>&1 || return 1
|
||||
apt-cache show nvidia-cuda-toolkit >/dev/null 2>&1
|
||||
}
|
||||
|
||||
print_linux_cuda_toolkit_guidance() {
|
||||
local package_hint
|
||||
package_hint="sudo apt update && sudo apt install -y nvidia-cuda-toolkit"
|
||||
|
||||
if command -v apt-cache >/dev/null 2>&1; then
|
||||
if ! apt-cache show nvidia-cuda-toolkit >/dev/null 2>&1; then
|
||||
package_hint="Your distro does not expose nvidia-cuda-toolkit in its default apt sources, so add NVIDIA's CUDA repository for your Debian/Ubuntu release and install the toolkit from there."
|
||||
fi
|
||||
fi
|
||||
|
||||
if host_is_wsl; then
|
||||
cat <<EOF >&2
|
||||
CUDA Toolkit is still missing inside this WSL Linux environment, so the installer is stopping before Ansible runs.
|
||||
|
||||
WSL splits GPU support into two layers:
|
||||
- Windows side: the NVIDIA driver makes the GPU visible to WSL
|
||||
- Linux side: llama.cpp still needs the CUDA toolkit headers/compiler inside the distro
|
||||
|
||||
What to do:
|
||||
1. Confirm the driver side works in WSL: nvidia-smi
|
||||
2. Install the Linux-side CUDA toolkit
|
||||
$package_hint
|
||||
3. Verify the toolkit:
|
||||
nvcc --version
|
||||
ls /usr/local/cuda/include/cuda_runtime.h
|
||||
|
||||
After that, rerun:
|
||||
bash deploy-courseware.sh
|
||||
EOF
|
||||
return
|
||||
fi
|
||||
|
||||
cat <<EOF >&2
|
||||
CUDA Toolkit is not installed inside this Linux environment, so the installer is stopping before Ansible runs.
|
||||
|
||||
This courseware can only build CUDA-enabled llama.cpp when the Linux-side toolkit is present.
|
||||
|
||||
What to do:
|
||||
1. Install the CUDA toolkit
|
||||
$package_hint
|
||||
2. Verify the toolkit:
|
||||
nvcc --version
|
||||
ls /usr/local/cuda/include/cuda_runtime.h
|
||||
|
||||
After that, rerun:
|
||||
bash deploy-courseware.sh
|
||||
EOF
|
||||
}
|
||||
|
||||
check_linux_cuda_toolkit() {
|
||||
if host_is_arm_mac; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$(uname -s)" != "Linux" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if host_is_wsl; then
|
||||
return
|
||||
fi
|
||||
|
||||
if linux_cuda_toolkit_is_ready; then
|
||||
return
|
||||
fi
|
||||
|
||||
if linux_cuda_toolkit_package_is_available; then
|
||||
return
|
||||
fi
|
||||
|
||||
print_linux_cuda_toolkit_guidance
|
||||
exit 1
|
||||
}
|
||||
|
||||
resolve_python() {
|
||||
if [ -n "${PYTHON_BIN:-}" ] && command -v "${PYTHON_BIN}" >/dev/null 2>&1; then
|
||||
command -v "${PYTHON_BIN}"
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
command -v python3
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v python >/dev/null 2>&1; then
|
||||
command -v python
|
||||
return
|
||||
fi
|
||||
|
||||
cat <<'EOF' >&2
|
||||
Python 3 was not found.
|
||||
|
||||
Install it first, then rerun this command:
|
||||
- Debian/Ubuntu/WSL: sudo apt update && sudo apt install -y python3 python3-venv
|
||||
- macOS: brew install python@3.11
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
host_is_debian_family() {
|
||||
[ -f /etc/os-release ] || return 1
|
||||
grep -qiE '^(ID|ID_LIKE)=(.*debian|debian.*)$' /etc/os-release
|
||||
}
|
||||
|
||||
python_has_venv_support() {
|
||||
local python_bin=$1
|
||||
local probe_parent
|
||||
local probe_venv
|
||||
|
||||
probe_parent=$(mktemp -d 2>/dev/null || mktemp -d -t labctl-venv-probe)
|
||||
probe_venv="$probe_parent/venv"
|
||||
|
||||
if "$python_bin" -m venv "$probe_venv" >/dev/null 2>&1; then
|
||||
rm -rf "$probe_parent"
|
||||
return 0
|
||||
fi
|
||||
|
||||
rm -rf "$probe_parent"
|
||||
return 1
|
||||
}
|
||||
|
||||
install_debian_python_venv_support() {
|
||||
local python_bin=$1
|
||||
local installer=(apt-get)
|
||||
local versioned_venv_pkg
|
||||
local packages=(python3-venv python3-pip)
|
||||
|
||||
if ! command -v apt-get >/dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
if ! command -v sudo >/dev/null 2>&1; then
|
||||
cat <<'EOF' >&2
|
||||
Python can be found, but this Debian/Ubuntu system is missing the venv bootstrap packages that Ansible needs.
|
||||
|
||||
Install them, then rerun this command:
|
||||
apt-get update && apt-get install -y python3-venv python3-pip
|
||||
EOF
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -t 0 ]; then
|
||||
cat <<'EOF' >&2
|
||||
Python can be found, but this Debian/Ubuntu system still needs sudo access to install python3-venv and python3-pip.
|
||||
|
||||
Run this command from an interactive terminal so sudo can prompt for your password, or install the packages manually:
|
||||
sudo apt-get update && sudo apt-get install -y python3-venv python3-pip
|
||||
EOF
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "This step needs sudo to install missing Python packages. You may be prompted for your password."
|
||||
installer=(sudo apt-get)
|
||||
fi
|
||||
|
||||
versioned_venv_pkg=$("$python_bin" -c "import sys; print(f'python{sys.version_info.major}.{sys.version_info.minor}-venv')")
|
||||
if command -v apt-cache >/dev/null 2>&1 && apt-cache show "$versioned_venv_pkg" >/dev/null 2>&1; then
|
||||
packages=("$versioned_venv_pkg" "${packages[@]}")
|
||||
fi
|
||||
|
||||
echo "Installing missing Python venv support for this Debian/Ubuntu system..."
|
||||
"${installer[@]}" update
|
||||
"${installer[@]}" install -y "${packages[@]}"
|
||||
}
|
||||
|
||||
ansible_venv_is_usable() {
|
||||
if [ ! -x "$ANSIBLE_PYTHON" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$ANSIBLE_PLAYBOOK" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
"$ANSIBLE_PYTHON" -c "import ansible" >/dev/null 2>&1 || return 1
|
||||
"$ANSIBLE_PLAYBOOK" --version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
rebuild_ansible() {
|
||||
local python_bin
|
||||
|
||||
python_bin=$(resolve_python)
|
||||
|
||||
if ! python_has_venv_support "$python_bin"; then
|
||||
if host_is_debian_family; then
|
||||
install_debian_python_venv_support "$python_bin"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! python_has_venv_support "$python_bin"; then
|
||||
cat <<'EOF' >&2
|
||||
Python 3 is installed, but its virtual environment support is still unavailable.
|
||||
|
||||
Install the missing venv package for your platform, then rerun this command:
|
||||
- Debian/Ubuntu/WSL: sudo apt update && sudo apt install -y python3-venv python3-pip
|
||||
- macOS: brew reinstall python@3.11
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "$ANSIBLE_VENV"
|
||||
echo "Preparing local installer runtime..."
|
||||
"$python_bin" -m venv "$ANSIBLE_VENV"
|
||||
"$ANSIBLE_PYTHON" -m pip install --upgrade pip
|
||||
"$ANSIBLE_PYTHON" -m pip install "ansible-core==2.18.6"
|
||||
}
|
||||
|
||||
ensure_ansible() {
|
||||
if ansible_venv_is_usable; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -e "$ANSIBLE_VENV" ]; then
|
||||
echo "Refreshing installer runtime for this machine..."
|
||||
fi
|
||||
|
||||
rebuild_ansible
|
||||
}
|
||||
|
||||
sudo_keepalive_pid=""
|
||||
|
||||
ensure_sudo_session() {
|
||||
if [ "$(uname -s)" != "Linux" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if ! command -v sudo >/dev/null 2>&1; then
|
||||
cat <<'EOF' >&2
|
||||
This installer needs sudo for Linux package setup, but `sudo` is not installed.
|
||||
|
||||
Install sudo or rerun this command as root, then try again.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if sudo -n true >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ ! -t 0 ]; then
|
||||
cat <<'EOF' >&2
|
||||
This installer needs sudo for Linux package setup.
|
||||
|
||||
Run this command from an interactive terminal so sudo can prompt for your password, then rerun the same `./labctl` command.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "This step needs sudo for Linux package setup. You may be prompted for your password."
|
||||
sudo -v
|
||||
}
|
||||
|
||||
start_sudo_keepalive() {
|
||||
if [ "$(uname -s)" != "Linux" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if ! command -v sudo >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
(
|
||||
while true; do
|
||||
sudo -n true >/dev/null 2>&1 || exit 0
|
||||
sleep 60
|
||||
done
|
||||
) &
|
||||
sudo_keepalive_pid=$!
|
||||
}
|
||||
|
||||
stop_sudo_keepalive() {
|
||||
if [ -n "${sudo_keepalive_pid:-}" ]; then
|
||||
kill "$sudo_keepalive_pid" >/dev/null 2>&1 || true
|
||||
wait "$sudo_keepalive_pid" >/dev/null 2>&1 || true
|
||||
sudo_keepalive_pid=""
|
||||
fi
|
||||
}
|
||||
|
||||
run_playbook() {
|
||||
local playbook=$1
|
||||
local escaped_root
|
||||
shift
|
||||
|
||||
check_wsl_gpu_readiness
|
||||
check_linux_cuda_toolkit
|
||||
ensure_ansible
|
||||
ensure_sudo_session
|
||||
|
||||
if [ ! -x "$ANSIBLE_PLAYBOOK" ]; then
|
||||
echo "Installer runtime is incomplete. Rebuilding it..."
|
||||
rebuild_ansible
|
||||
fi
|
||||
|
||||
escaped_root=${ROOT_DIR//\\/\\\\}
|
||||
escaped_root=${escaped_root//\"/\\\"}
|
||||
|
||||
start_sudo_keepalive
|
||||
trap stop_sudo_keepalive RETURN
|
||||
"$ANSIBLE_PLAYBOOK" \
|
||||
-e "{\"courseware_root\":\"$escaped_root\"}" \
|
||||
"$ROOT_DIR/ansible/playbooks/$playbook" \
|
||||
"$@"
|
||||
}
|
||||
|
||||
require_arg() {
|
||||
if [ $# -lt 1 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
local cmd=${1:-}
|
||||
shift || true
|
||||
|
||||
case "$cmd" in
|
||||
up)
|
||||
confirm_installation
|
||||
run_playbook up.yml
|
||||
"$ROOT_DIR/scripts/service_manager.sh" start all
|
||||
;;
|
||||
down)
|
||||
"$ROOT_DIR/scripts/service_manager.sh" stop all || true
|
||||
run_playbook down.yml
|
||||
;;
|
||||
preflight)
|
||||
confirm_installation
|
||||
run_playbook up.yml --tags preflight
|
||||
;;
|
||||
versions)
|
||||
print_versions
|
||||
;;
|
||||
start|stop|status|urls|open|logs)
|
||||
exec "$ROOT_DIR/scripts/service_manager.sh" "$cmd" "$@"
|
||||
;;
|
||||
""|-h|--help|help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user