setup
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
set -euo pipefail
shopt -s expand_aliases
declare -r githubUrl='https://github.com/5ouma/homelab'
declare -r homelab="$HOME/homelab"
TMPDIR="$(mktemp -d)" && declare -r TMPDIR
export GUM_CONFIRM_SELECTED_BACKGROUND='27'
export GUM_FORMAT_THEME="$TMPDIR/blue.json"
export GUM_INPUT_CURSOR_FOREGROUND='33'
export GUM_SPIN_SPINNER_FOREGROUND='27'
export GUM_WRITE_CURSOR_FOREGROUND='33'
declare executed=false
declare skipped=false
declare goThrough=false
declare pacmanArgs=(--noconfirm)
getGum() {
declare -r gumVer='0.17.0'
declare -r arch="$(uname -m)"
declare -r gumDir="gum_${gumVer}_$(uname)_${arch/aarch64/arm64}"
declare -r gumUrl="https://github.com/charmbracelet/gum/releases/download/v$gumVer/$gumDir.tar.gz"
declare -r gumThemeUrl="https://raw.githubusercontent.com/5ouma/dotfiles/main/data/blue.json"
printf ' 🚚💨 Now delivering...'
# shellcheck disable=SC2139
curl -sL "$gumUrl" | tar --strip-components=1 -zxC "$TMPDIR" "$gumDir/gum" && alias gumCom="$TMPDIR/gum"
printf '\r '
curl -s "$gumThemeUrl" -o "$GUM_FORMAT_THEME"
} && getGum
gum() {
case $1 in
confirm) gumCom confirm "$2" --affirmative="$3" --negative="$4" ;;
format) gumCom format "${@:2}" ;;
input) gumCom input --placeholder="$2" ;;
spin) gumCom spin --title="$2" -- "${@:4}" ;;
style) gumCom style --foreground="$2" "${@:3}" ;;
write) gumCom write --placeholder="$2" ;;
executed)
echo -en '\n ' && gumCom format '✅ Done!'
executed=true
;;
skipped) echo -en '\n ' && gumCom format '🟡 Skipped' ;;
esac
}
alias skip='skipped=true && return'
shouldProceed() {
($goThrough || gum confirm 'Proceed?' 'Yes' 'No')
}
run() {
gum format "$2"
eval '$1'
if ($skipped); then
skipped=false
gum skipped
else
gum executed
fi
}
helpMsg() {
gum format <<EOM
## Usage: setup
> 🥼 Self-hosted personal laboratory
## Commands:
- help Print help information
## Flags:
- -y, --yes Start without confirmation
EOM
}
errMsg() {
declare -r stat=$1 func="${2/"$HOME"/~}" line=$3
gum format <<EOM
> **$(gum style 1 'Error')**
> Unknown error has occurred!
> - Status: $stat
> - File or Function: $func
> - Line Number: $line
> - Process ID: $$
EOM
} && trap 'errMsg $? "$0" $LINENO' ERR
if [[ ! -x $0 ]]; then
gum format <<EOM
# Welcome to 🥼 Homelab setup!
> $githubUrl
---
EOM
fi
if (($# > 0)); then
case "$1" in
'help')
helpMsg
exit
;;
'-y' | '--yes')
goThrough=true
;;
*)
gum format <<EOM
> **$(gum style 1 'Error')**
> Unknown flag $1
EOM
helpMsg
exit 1
;;
esac
fi
if (! $goThrough); then
gum confirm "Let's start setup!" 'Yes!' 'No' || exit 1
pacmanArgs=()
fi
if [[ ! -d "$homelab" ]]; then
# shellcheck disable=SC2016
gum spin 'Cloning the repository into `~/homelab`...' -- git clone "$githubUrl" "$homelab"
else
gum spin 'Pulling the homelab repository...' -- git -C "$homelab" pull
fi
sudo -v
updateSystem() {
gum spin 'Synchronizing package databases...' -- yay -Sy
if (! yay -Qu &>/dev/null || ! shouldProceed); then
skip
fi
yay -Su "${pacmanArgs[@]}"
} && run 'updateSystem' '## 🔧 Update system'
installPackages() {
declare -r packages=(docker docker-compose firewalld jq pacman-contrib reflector tailscale)
if (yay -Q "${packages[@]}" &>/dev/null || ! shouldProceed); then
skip
fi
yay -S --needed "${pacmanArgs[@]}" "${packages[@]}"
} && run 'installPackages' '## 📦 Install packages'
enableServices() {
declare -r services=(docker firewalld paccache.timer reflector.timer tailscaled)
if (systemctl is-enabled "${services[@]}" | awk '$0 == "disabled" { exit 1 }' || ! shouldProceed); then
skip
fi
gum spin 'Enabling services...' -- sudo systemctl enable --now "${services[@]}"
} && run 'enableServices' '## 🎽 Enable system services'
configureReflector() {
declare -r country="$(curl -s https://ipapi.co/country_name)"
if (grep -q -- "--country $country" /etc/xdg/reflector/reflector.conf && grep -q -- '--sort rate' /etc/xdg/reflector/reflector.conf || ! shouldProceed); then
skip
fi
gum spin 'Setting auto country selection...' -- sudo sed -i "s/^# --country France,Germany/--country $country/" /etc/xdg/reflector/reflector.conf
gum spin 'Setting sorting by rate...' -- sudo sed -i 's/^--sort age/--sort rate/' /etc/xdg/reflector/reflector.conf
} && run 'configureReflector' '## 🪞 Configure Reflector'
addToDockerGroup() {
if (groups "$USER" | grep -q docker || ! shouldProceed); then
skip
fi
gum spin 'Adding user to Docker group...' -- sudo usermod -aG docker "$USER"
} && run 'addToDockerGroup' '## 🐳 Add user to Docker group'
setHostname() {
if [[ -n "$(hostnamectl status --pretty)" ]] || ! shouldProceed; then
skip
fi
hostname=$(gum input 'Enter hostname')
gum spin 'Setting hostname...' -- sudo hostnamectl set-hostname "${hostname// /-}"
gum spin 'Setting pretty hostname...' -- sudo hostnamectl set-hostname --pretty "$hostname"
} && run 'setHostname' '## 🖥️ Set system hostname'
configureFirewall() {
if (sudo firewall-cmd -q --query-service=mdns && sudo firewall-cmd -q --query-service=samba || ! shouldProceed); then
skip
fi
gum spin 'Adding Samba and mDNS services...' -- sudo firewall-cmd --add-service={mdns,samba} --permanent
gum spin 'Reloading firewall...' -- sudo firewall-cmd --reload
} && run 'configureFirewall' '## 🔥 Configure firewall'
configureBackupDrive() {
if (grep -q /mnt/backup /etc/fstab || ! shouldProceed); then
skip
fi
sudo blkid
backupDriveUUID="$(gum input 'Enter backup drive UUID')"
echo "UUID=$backupDriveUUID /mnt/backup ext4 defaults 0 0" | sudo tee -a /etc/fstab >/dev/null
} && run 'configureBackupDrive' '## 💾 Configure backup drive'
configureTailscale() {
if (tailscale status &>/dev/null || ! shouldProceed); then
skip
fi
sudo tailscale up --accept-routes --advertise-exit-node --ssh
gum spin 'Setting Tailscale hostname...' -- sudo tailscale set --hostname="$(hostnamectl status --pretty)"
} && run 'configureTailscale' '## 🛣️ Configure Tailscale'
if ($executed); then
gum format '# 🎉 Homelab setup completed!'
gum confirm "Reboot the system?" 'Yes' 'No' && sudo reboot
else
gum format '# 🧊 Nothing has changed'
fi