diff --git a/.github/workflows/auto-update-app-headers.yml b/.github/workflows/auto-update-app-headers.yml index 147bf07e1b2..386a6477aaa 100644 --- a/.github/workflows/auto-update-app-headers.yml +++ b/.github/workflows/auto-update-app-headers.yml @@ -6,6 +6,8 @@ on: - main paths: - "ct/**.sh" + - "tools/**.sh" + - "vm/**.sh" workflow_dispatch: jobs: diff --git a/.github/workflows/scripts/generate-app-headers.sh b/.github/workflows/scripts/generate-app-headers.sh index 96050795e0a..e9674491bfe 100755 --- a/.github/workflows/scripts/generate-app-headers.sh +++ b/.github/workflows/scripts/generate-app-headers.sh @@ -24,7 +24,9 @@ generate_headers() { app_name=$(grep -oP '^APP="\K[^"]+' "$script" 2>/dev/null) if [[ -n "$app_name" ]]; then - output_file="${headers_dir}/$(basename "${script%.*}")" + # core.func/vm-core.func look the header up as "${APP,,}" without spaces, + # so the generated file has to be named after APP - not after the script. + output_file="${headers_dir}/$(echo "${app_name,,}" | tr -d ' ')" figlet_output=$(figlet -w 500 -f slant "$app_name") if [[ -n "$figlet_output" ]]; then echo "$figlet_output" >"$output_file" diff --git a/misc/core.func b/misc/core.func index e09a07d8385..18739325f8f 100644 --- a/misc/core.func +++ b/misc/core.func @@ -299,6 +299,72 @@ root_check() { fi } +# ------------------------------------------------------------------------------ +# on_pve_host() +# +# - Returns 0 when executed on a Proxmox VE node, 1 otherwise +# - Cheap probe used by the guards below; never exits on its own +# ------------------------------------------------------------------------------ +on_pve_host() { + command -v pveversion &>/dev/null +} + +# ------------------------------------------------------------------------------ +# require_pve_host() +# +# - Guard for tools that drive the node itself (pct/pveam/pvesm/pvesh/qm) +# - Aborts when not on a PVE node, then validates the PVE version +# ------------------------------------------------------------------------------ +require_pve_host() { + if ! on_pve_host; then + msg_error "${APP:-This script} must be run on the Proxmox VE host." + msg_error "Proxmox tooling (pct/pveam/pvesm/qm) is not available here." + exit 232 + fi + pve_check +} + +# ------------------------------------------------------------------------------ +# confirm_not_pve_host() +# +# - Guard for tools that belong inside an LXC/VM but would technically run +# on the node as well +# - Warns and asks for confirmation instead of hard-failing +# ------------------------------------------------------------------------------ +confirm_not_pve_host() { + on_pve_host || return 0 + + msg_error "Running on the Proxmox VE host is NOT recommended!" + msg_error "${APP:-This script} is meant to be executed inside an LXC container." + echo "" + echo -n "${TAB:- }Continue anyway? (y/N): " + local confirm + read -r confirm + if [[ ! "${confirm,,}" =~ ^(y|yes)$ ]]; then + msg_warn "Aborted. Please run this inside an LXC container." + exit 0 + fi + msg_warn "Proceeding on the Proxmox VE host at your own risk!" +} + +# ------------------------------------------------------------------------------ +# require_debian_like() +# +# - Guard for addons that have no Alpine code path +# - Aborts early instead of failing halfway through with apt/systemd errors +# ------------------------------------------------------------------------------ +require_debian_like() { + if is_alpine; then + msg_error "${APP:-This script} does not support Alpine Linux." + msg_error "Please use a Debian or Ubuntu based LXC container." + exit 238 + fi + if ! command -v apt-get &>/dev/null; then + msg_error "${APP:-This script} requires a Debian or Ubuntu based system." + exit 238 + fi +} + # ------------------------------------------------------------------------------ # pve_check() # @@ -308,6 +374,10 @@ root_check() { # ------------------------------------------------------------------------------ pve_check() { local PVE_VER + if ! on_pve_host; then + msg_error "${APP:-This script} must be run on the Proxmox VE host." + exit 232 + fi PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')" # Check for Proxmox VE 8.x: allow 8.0–8.9 diff --git a/misc/tools.func b/misc/tools.func index 0f13f8c5324..369831dc46b 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -4628,6 +4628,53 @@ _docker_is_noninteractive() { [[ "${DOCKER_NONINTERACTIVE:-}" == "1" || "${DOCKER_NONINTERACTIVE:-}" == "true" || "${DOCKER_NONINTERACTIVE:-}" == "TRUE" ]] || [[ ! -t 0 ]] } +# ------------------------------------------------------------------------------ +# ensure_docker() +# +# - Docker precondition for addon scripts that ship a compose stack +# - Reuses an existing installation, otherwise offers to install Docker +# (Debian/Ubuntu via setup_docker, Alpine via apk) +# - Aborts when the user declines or Compose is unavailable afterwards +# ------------------------------------------------------------------------------ +ensure_docker() { + if command -v docker &>/dev/null; then + msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') is available" + if docker compose version &>/dev/null; then + msg_ok "Docker Compose is available" + return 0 + fi + msg_error "Docker Compose plugin is not available. Please install it." + exit 237 + fi + + msg_warn "Docker is not installed." + echo -n "${TAB:- }Install Docker now? (y/N): " + local install_docker_prompt + read -r install_docker_prompt + if [[ ! "${install_docker_prompt,,}" =~ ^(y|yes)$ ]]; then + msg_error "Docker is required for ${APP:-this script}. Exiting." + exit 254 + fi + + if is_alpine; then + msg_info "Installing Docker" + $STD apk add --no-cache docker docker-cli-compose + $STD rc-update add docker default + $STD rc-service docker start + msg_ok "Installed Docker" + else + setup_docker || { + msg_error "Docker installation failed." + exit 237 + } + fi + + if ! command -v docker &>/dev/null || ! docker compose version &>/dev/null; then + msg_error "Docker or the Compose plugin is still unavailable after installation." + exit 237 + fi +} + setup_docker() { local docker_installed=false local USE_DOCKER_REPO="${USE_DOCKER_REPO:-true}" diff --git a/tools/addon/actual-budget-prometheus-exporter.sh b/tools/addon/actual-budget-prometheus-exporter.sh index a75a9580e32..15e335008a9 100644 --- a/tools/addon/actual-budget-prometheus-exporter.sh +++ b/tools/addon/actual-budget-prometheus-exporter.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -20,6 +25,7 @@ declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "actual-budget set -Eeuo pipefail trap 'error_handler' ERR load_functions +require_debian_like # ============================================================================== # CONFIGURATION @@ -31,14 +37,6 @@ INSTALL_PATH="/opt/actual-budget-prometheus-exporter" CONFIG_PATH="/opt/actual-budget-prometheus-exporter.env" SERVICE_PATH="/etc/systemd/system/actual-budget-prometheus-exporter.service" -# ============================================================================== -# OS DETECTION -# ============================================================================== -if ! grep -qE 'ID=debian|ID=ubuntu' /etc/os-release 2>/dev/null; then - echo -e "${CROSS} Unsupported OS detected. This script only supports Debian and Ubuntu." - exit 238 -fi - # ============================================================================== # UNINSTALL # ============================================================================== diff --git a/tools/addon/add-netbird-lxc.sh b/tools/addon/add-netbird-lxc.sh index 5c21e672f6e..643c735ecde 100644 --- a/tools/addon/add-netbird-lxc.sh +++ b/tools/addon/add-netbird-lxc.sh @@ -6,39 +6,45 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://netbird.io/ | Github: https://github.com/netbirdio/netbird -function header_info { - clear - cat <<"EOF" - _ __ __ ____ _ __ - / | / /__ / /_/ __ )(_)________/ / - / |/ / _ \/ __/ __ / / ___/ __ / - / /| / __/ /_/ /_/ / / / / /_/ / -/_/ |_/\___/\__/_____/_/_/ \__,_/ +APP="add-netbird-lxc" +APP_TYPE="addon" -EOF -} -header_info -set -e - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "add-netbird-lxc" "addon" +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions + +header_info +require_pve_host + while true; do - read -p "This will add NetBird to an existing LXC Container ONLY. Proceed(y/n)?" yn + read -r -p "This will add NetBird to an existing LXC Container ONLY. Proceed(y/n)? " yn case $yn in [Yy]*) break ;; - [Nn]*) exit ;; + [Nn]*) exit 0 ;; *) echo "Please answer yes or no." ;; esac done -header_info -echo "Loading..." -function msg() { - local TEXT="$1" - echo -e "$TEXT" -} +echo -e "Loading container list..." NODE=$(hostname) MSG_MAX_LENGTH=0 @@ -61,37 +67,51 @@ done LXC_STATUS=$(pct status "$CTID" | awk '{print $2}') if [[ "$LXC_STATUS" != "running" ]]; then - msg "\e[1;33m The container $CTID is not running. Starting it now...\e[0m" + msg_info "Container $CTID is not running. Starting it now..." pct start "$CTID" while [[ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]]; do - msg "\e[1;33m Waiting for the container to start...\e[0m" + msg_info "Waiting for the container to start..." sleep 2 done - msg "\e[1;32m Container $CTID is now running.\e[0m" + msg_ok "Container $CTID is now running." fi DISTRO=$(pct exec "$CTID" -- cat /etc/os-release | grep -w "ID" | cut -d'=' -f2 | tr -d '"') if [[ "$DISTRO" != "debian" && "$DISTRO" != "ubuntu" ]]; then - msg "\e[1;31m Error: This script only supports Debian or Ubuntu LXC containers. Detected: $DISTRO. Aborting...\e[0m" + msg_error "This script only supports Debian or Ubuntu LXC containers. Detected: $DISTRO. Aborting..." exit 238 fi -CTID_CONFIG_PATH=/etc/pve/lxc/${CTID}.conf -cat <>$CTID_CONFIG_PATH +CTID_CONFIG_PATH="/etc/pve/lxc/${CTID}.conf" +cat <>"$CTID_CONFIG_PATH" lxc.cgroup2.devices.allow: c 10:200 rwm lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file EOF -header_info -msg "Installing NetBird..." + +msg_info "Installing NetBird" pct exec "$CTID" -- bash -c ' +set -e if ! command -v curl &>/dev/null; then apt-get update -qq apt-get install -y curl >/dev/null fi -apt install -y ca-certificates gpg &>/dev/null -curl -fsSL "https://pkgs.netbird.io/debian/public.key" | gpg --dearmor >/usr/share/keyrings/netbird-archive-keyring.gpg -echo "deb [signed-by=/usr/share/keyrings/netbird-archive-keyring.gpg] https://pkgs.netbird.io/debian stable main" >/etc/apt/sources.list.d/netbird.list -apt-get update &>/dev/null +apt-get install -y ca-certificates gpg &>/dev/null + +# Reuse the shared repository helper instead of hand-rolling the sources entry +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +load_functions + +# Drop the legacy keyring from the pre-deb822 layout +rm -f /usr/share/keyrings/netbird-archive-keyring.gpg + +setup_deb822_repo \ + "netbird" \ + "https://pkgs.netbird.io/debian/public.key" \ + "https://pkgs.netbird.io/debian" \ + "stable" \ + "main" + apt-get install -y netbird-ui &>/dev/null if systemctl list-unit-files docker.service &>/dev/null; then mkdir -p /etc/systemd/system/netbird.service.d @@ -103,6 +123,5 @@ OVERRIDE systemctl daemon-reload fi ' -msg "\e[1;32m ✔ Installed NetBird.\e[0m" -sleep 2 -msg "\e[1;31m Reboot ${CTID} LXC to apply the changes, then run netbird up in the LXC console\e[0m" +msg_ok "Installed NetBird." +echo -e "${YW}Reboot ${CTID} LXC${CL} to apply the changes, then run 'netbird up' in the LXC console" diff --git a/tools/addon/add-tailscale-lxc.sh b/tools/addon/add-tailscale-lxc.sh index 70e883c2ec2..59a6cca8334 100644 --- a/tools/addon/add-tailscale-lxc.sh +++ b/tools/addon/add-tailscale-lxc.sh @@ -5,35 +5,34 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://tailscale.com/ | Github: https://github.com/tailscale/tailscale -set -Eeuo pipefail -trap 'echo -e "\n[ERROR] in line $LINENO: exit code $?"' ERR +APP="add-tailscale-lxc" +APP_TYPE="addon" -function header_info() { - clear - cat <<"EOF" - ______ _ __ __ - /_ __/___ _(_) /_____________ _/ /__ - / / / __ `/ / / ___/ ___/ __ `/ / _ \ - / / / /_/ / / (__ ) /__/ /_/ / / __/ -/_/ \__,_/_/_/____/\___/\__,_/_/\___/ - -EOF -} - -function msg_info() { echo -e " \e[1;36m➤\e[0m $1"; } -function msg_ok() { echo -e " \e[1;32m✔\e[0m $1"; } -function msg_error() { echo -e " \e[1;31m✖\e[0m $1"; } - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "add-tailscale-lxc" "addon" -header_info +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR -if ! command -v pveversion &>/dev/null; then - msg_error "This script must be run on the Proxmox VE host (not inside an LXC container)" - exit 232 -fi +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions + +header_info +require_pve_host while true; do read -rp "This will add Tailscale to an existing LXC Container ONLY. Proceed (y/n)? " yn @@ -44,7 +43,6 @@ while true; do esac done -header_info msg_info "Loading container list..." NODE=$(hostname) @@ -73,10 +71,9 @@ CTID_CONFIG_PATH="/etc/pve/lxc/${CTID}.conf" grep -q "lxc.cgroup2.devices.allow: c 10:200 rwm" "$CTID_CONFIG_PATH" || echo "lxc.cgroup2.devices.allow: c 10:200 rwm" >>"$CTID_CONFIG_PATH" grep -q "lxc.mount.entry: /dev/net/tun" "$CTID_CONFIG_PATH" || echo "lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file" >>"$CTID_CONFIG_PATH" -header_info msg_info "Installing Tailscale in CT $CTID" -pct exec "$CTID" -- sh -c ' +pct exec "$CTID" -- bash -c ' set -e # Detect OS inside container @@ -144,16 +141,21 @@ else apt-get install -y curl >/dev/null fi - # Ensure keyrings directory exists - mkdir -p /usr/share/keyrings + # Reuse the shared repository helper instead of hand-rolling the sources entry + source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) + source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) + load_functions - curl -fsSL "https://pkgs.tailscale.com/stable/${ID}/${VERSION_CODENAME}.noarmor.gpg" \ - | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null + # Drop the legacy keyring from the pre-deb822 layout + rm -f /usr/share/keyrings/tailscale-archive-keyring.gpg - echo "deb [signed-by=/usr/share/keyrings/tailscale-archive-keyring.gpg] https://pkgs.tailscale.com/stable/${ID} ${VERSION_CODENAME} main" \ - >/etc/apt/sources.list.d/tailscale.list + setup_deb822_repo \ + "tailscale" \ + "https://pkgs.tailscale.com/stable/${ID}/${VERSION_CODENAME}.noarmor.gpg" \ + "https://pkgs.tailscale.com/stable/${ID}" \ + "${VERSION_CODENAME}" \ + "main" - apt-get update -qq apt-get install -y tailscale >/dev/null if [ -f /tmp/resolv.conf.backup ]; then @@ -168,4 +170,4 @@ TAGS="${TAGS:+$TAGS; }tailscale" pct set "$CTID" -tags "$TAGS" msg_ok "Tailscale installed on CT $CTID" -msg_info "Reboot the container, then run 'tailscale up' inside the container to activate." +echo -e "${YW}Reboot the container${CL}, then run 'tailscale up' inside the container to activate." diff --git a/tools/addon/adguardhome-sync.sh b/tools/addon/adguardhome-sync.sh index 406c00d5de8..66b65b81a0c 100644 --- a/tools/addon/adguardhome-sync.sh +++ b/tools/addon/adguardhome-sync.sh @@ -7,8 +7,9 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - if [[ -f "/etc/alpine-release" ]]; then - apk -U add curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 else apt-get update >/dev/null 2>&1 apt-get install -y curl >/dev/null 2>&1 @@ -36,28 +37,6 @@ DEFAULT_PORT=8080 # Initialize all core functions (colors, formatting, icons, STD mode) load_functions -# ============================================================================== -# HEADER -# ============================================================================== -function header_info { - clear - cat <<"EOF" - ___ __ ____ __ _____ - / | ____/ /___ ___ ______ __________/ / / / /___ ____ ___ ___ / ___/__ ______ _____ - / /| |/ __ / __ `/ / / / __ `/ ___/ __ / /_/ / __ \/ __ `__ \/ _ \ \__ \/ / / / __ \/ ___/ - / ___ / /_/ / /_/ / /_/ / /_/ / / / /_/ / __ / /_/ / / / / / / __/ ___/ / /_/ / / / / /__ -/_/ |_\__,_/\__, /\__,_/\__,_/_/ \__,_/_/ /_/\____/_/ /_/ /_/\___/ /____/\__, /_/ /_/\___/ - /____/ /____/ -EOF -} - -# ============================================================================== -# HELPER FUNCTIONS -# ============================================================================== -get_ip() { - hostname -I 2>/dev/null | awk '{print $1}' || ip -4 addr show scope global 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1 || echo "127.0.0.1" -} - # ============================================================================== # OS DETECTION # ============================================================================== @@ -114,16 +93,12 @@ function update() { fi msg_ok "Stopped service" - msg_info "Backing up configuration" - cp "$CONFIG_PATH" /tmp/adguardhome-sync.yaml.bak 2>/dev/null || true - msg_ok "Backed up configuration" + BACKUP_DIR="/opt/adguardhome-sync_backup" + create_backup "$CONFIG_PATH" - CLEAN_INSTALL=1 fetch_and_deploy_gh_release "adguardhome-sync" "bakito/adguardhome-sync" "prebuild" "latest" "$INSTALL_PATH" "adguardhome-sync_*_linux_amd64.tar.gz" + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "adguardhome-sync" "bakito/adguardhome-sync" "prebuild" "latest" "$INSTALL_PATH" "adguardhome-sync_*_linux_$(arch_resolve).tar.gz" - msg_info "Restoring configuration" - cp /tmp/adguardhome-sync.yaml.bak "$CONFIG_PATH" 2>/dev/null || true - rm -f /tmp/adguardhome-sync.yaml.bak - msg_ok "Restored configuration" + restore_backup msg_info "Starting service" if [[ "$OS" == "Alpine" ]]; then @@ -141,10 +116,7 @@ function update() { # INSTALL # ============================================================================== function install() { - local ip - ip=$(get_ip) - - fetch_and_deploy_gh_release "adguardhome-sync" "bakito/adguardhome-sync" "prebuild" "latest" "$INSTALL_PATH" "adguardhome-sync_*_linux_amd64.tar.gz" + fetch_and_deploy_gh_release "adguardhome-sync" "bakito/adguardhome-sync" "prebuild" "latest" "$INSTALL_PATH" "adguardhome-sync_*_linux_$(arch_resolve).tar.gz" # Gather configuration from user echo "" @@ -153,7 +125,7 @@ function install() { echo "" # Origin instance - echo -e "${YW}── Origin (Primary) Instance ──${CL}" + echo -e "${YW}── Origin (Primary) Instance ──${CL}" local origin_url origin_user origin_pass read -rp " Origin URL (e.g., http://192.168.1.1): " origin_url origin_url="${origin_url:-http://192.168.1.1}" @@ -167,7 +139,7 @@ function install() { # Replica instance echo "" - echo -e "${YW}── Replica Instance ──${CL}" + echo -e "${YW}── Replica Instance ──${CL}" local replica_url replica_user replica_pass read -rp " Replica URL (e.g., http://192.168.1.2): " replica_url replica_url="${replica_url:-http://192.168.1.2}" @@ -293,7 +265,7 @@ UPDATEEOF echo "" msg_ok "${APP} installed successfully" - msg_ok "Web UI: ${BL}http://${ip}:${DEFAULT_PORT}${CL}" + msg_ok "Web UI: ${BL}http://${IP}:${DEFAULT_PORT}${CL}" msg_ok "Config: ${BL}${CONFIG_PATH}${CL}" echo "" msg_warn "Edit the config file to add your AdGuardHome instances!" @@ -319,7 +291,8 @@ fi header_info -IP=$(get_ip) +get_lxc_ip +IP="$LOCAL_IP" # Check if already installed if [[ -d "$INSTALL_PATH" && -f "$INSTALL_PATH/adguardhome-sync" ]]; then diff --git a/tools/addon/all-templates.sh b/tools/addon/all-templates.sh index b23e98e00e2..481b28c33d5 100644 --- a/tools/addon/all-templates.sh +++ b/tools/addon/all-templates.sh @@ -1,52 +1,40 @@ #!/usr/bin/env bash + # Copyright (c) 2021-2026 tteck # Author: tteck (tteckster) -# License: MIT -# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -function header_info { - clear - cat <<"EOF" - ___ ____ ______ __ __ - / _ | / / / /_ __/__ __ _ ___ / /__ _/ /____ ___ - / __ |/ / / / / / -_) ' \/ _ \/ / _ `/ __/ -_|_-< -/_/ |_/_/_/ /_/ \__/_/_/_/ .__/_/\_,_/\__/\__/___/ - /_/ -EOF -} +APP="all-templates" +APP_TYPE="addon" -set -eEuo pipefail -shopt -s expand_aliases -alias die='EXIT=$? LINE=$LINENO error_exit' -trap die ERR -function error_exit() { - trap - ERR - local DEFAULT='Unknown failure occured.' - local REASON="\e[97m${1:-$DEFAULT}\e[39m" - local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE" - msg "$FLAG $REASON" 1>&2 - [ ! -z ${CTID-} ] && cleanup_ctid - exit $EXIT -} -function warn() { - local REASON="\e[97m$1\e[39m" - local FLAG="\e[93m[WARNING]\e[39m" - msg "$FLAG $REASON" -} -function info() { - local REASON="$1" - local FLAG="\e[36m[INFO]\e[39m" - msg "$FLAG $REASON" -} -function msg() { - local TEXT="$1" - echo -e "$TEXT" -} - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "all-templates" "addon" +# Enable error handling; destroy any partially-created container before reporting the error +set -Eeuo pipefail +function _cleanup_on_error() { + local ec=$? cmd="$BASH_COMMAND" + [[ -n "${CTID:-}" ]] && cleanup_ctid + error_handler "$ec" "$cmd" +} +trap '_cleanup_on_error' ERR + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions + function validate_container_id() { local ctid="$1" # Check if ID is numeric @@ -79,12 +67,14 @@ function cleanup_ctid() { fi } +header_info +require_pve_host + # Stop Proxmox VE Monitor-All if running if systemctl is-active -q ping-instances.service; then systemctl stop ping-instances.service fi -header_info -echo "Loading..." +msg_info "Loading" pveam update >/dev/null 2>&1 whiptail --backtitle "Proxmox VE Helper Scripts" --title "All Templates" --yesno "This will allow for the creation of one of the many Template LXC Containers. Proceed?" 10 68 TEMPLATE_MENU=() @@ -97,8 +87,8 @@ done < <(pveam available) TEMPLATE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "All Template LXCs" --radiolist "\nSelect a Template LXC to create:\n" 16 $((MSG_MAX_LENGTH + 58)) 10 "${TEMPLATE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"') [ -z "$TEMPLATE" ] && { whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Template LXC Selected" --msgbox "It appears that no Template LXC container was selected" 10 68 - msg "Done" - exit + echo "Done" + exit 0 } # Setup script environment @@ -108,9 +98,9 @@ PASS="$(openssl rand -base64 8)" # Get valid Container ID CTID=$(pvesh get /cluster/nextid) if ! validate_container_id "$CTID"; then - warn "Container ID $CTID is already in use." + msg_warn "Container ID $CTID is already in use." CTID=$(get_valid_container_id "$CTID") - info "Using next available ID: $CTID" + msg_info "Using next available ID: $CTID" fi PCT_OPTIONS=" @@ -142,7 +132,10 @@ function select_storage() { CONTENT='vztmpl' CONTENT_LABEL='Container template' ;; - *) false || die "Invalid storage class." ;; + *) + msg_error "Invalid storage class." + exit 112 + ;; esac # Query all storage locations @@ -161,8 +154,9 @@ function select_storage() { # Select storage location if [ $((${#MENU[@]} / 3)) -eq 0 ]; then - warn "'$CONTENT_LABEL' needs to be selected for at least one storage location." - die "Unable to detect valid storage location." + msg_warn "'$CONTENT_LABEL' needs to be selected for at least one storage location." + msg_error "Unable to detect valid storage location." + if [[ "$CONTENT" == "rootdir" ]]; then exit 119; else exit 120; fi elif [ $((${#MENU[@]} / 3)) -eq 1 ]; then printf ${MENU[0]} else @@ -171,43 +165,54 @@ function select_storage() { STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \ "Which storage pool would you like to use for the ${CONTENT_LABEL,,}?\n\n" \ 16 $(($MSG_MAX_LENGTH + 23)) 6 \ - "${MENU[@]}" 3>&1 1>&2 2>&3) || die "Menu aborted." + "${MENU[@]}" 3>&1 1>&2 2>&3) || { + msg_error "Menu aborted." + exit 254 + } done printf $STORAGE fi } -header_info + # Get template storage TEMPLATE_STORAGE=$(select_storage template) -info "Using '$TEMPLATE_STORAGE' for template storage." +msg_info "Using '$TEMPLATE_STORAGE' for template storage." # Get container storage CONTAINER_STORAGE=$(select_storage container) -info "Using '$CONTAINER_STORAGE' for container storage." +msg_info "Using '$CONTAINER_STORAGE' for container storage." # Download template -msg "Downloading LXC template (Patience)..." -pveam download $TEMPLATE_STORAGE $TEMPLATE >/dev/null || die "A problem occured while downloading the LXC template." +msg_info "Downloading LXC template (Patience)" +pveam download $TEMPLATE_STORAGE $TEMPLATE >/dev/null || { + msg_error "A problem occured while downloading the LXC template." + exit 222 +} +msg_ok "Downloaded LXC template" # Create variable for 'pct' options PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}}) -[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs $CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}) +[[ " ${PCT_OPTIONS[*]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs $CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}) # Create LXC -msg "Creating LXC container..." -pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[@]} >/dev/null || - die "A problem occured while trying to create container." +msg_info "Creating LXC container" +pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} "${PCT_OPTIONS[@]}" >/dev/null || { + msg_error "A problem occured while trying to create container." + exit 209 +} +msg_ok "Created LXC container" # Save password echo "$NAME password: ${PASS}" >>~/$NAME.creds # file is located in the Proxmox root directory # Start container -msg "Starting LXC Container..." +msg_info "Starting LXC Container" pct start "$CTID" sleep 5 +msg_ok "Started LXC Container" # Get container IP -set +eEuo pipefail +set +Eeuo pipefail max_attempts=5 attempt=1 IP="" @@ -216,30 +221,29 @@ while [[ $attempt -le $max_attempts ]]; do if [[ -n $IP ]]; then break else - warn "Attempt $attempt: IP address not found. Pausing for 5 seconds..." + msg_warn "Attempt $attempt: IP address not found. Pausing for 5 seconds..." sleep 5 ((attempt++)) fi done if [[ -z $IP ]]; then - warn "Maximum number of attempts reached. IP address not found." + msg_warn "Maximum number of attempts reached. IP address not found." IP="NOT FOUND" fi -set -eEuo pipefail +set -Eeuo pipefail # Start Proxmox VE Monitor-All if available if [[ -f /etc/systemd/system/ping-instances.service ]]; then systemctl start ping-instances.service fi # Success message -header_info echo -info "LXC container '$CTID' was successfully created, and its IP address is ${IP}." +msg_ok "LXC container '$CTID' was successfully created, and its IP address is ${IP}." echo -info "Proceed to the LXC console to complete the setup." +echo -e "${YW}Proceed to the LXC console to complete the setup.${CL}" echo -info "login: root" -info "password: $PASS" +echo -e "${YW}login: root${CL}" +echo -e "${YW}password: $PASS${CL}" echo diff --git a/tools/addon/arcane.sh b/tools/addon/arcane.sh index b63b8306fb1..02b2968cd5f 100644 --- a/tools/addon/arcane.sh +++ b/tools/addon/arcane.sh @@ -6,8 +6,13 @@ # Source: https://github.com/getarcaneapp/arcane if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -32,21 +37,6 @@ DEFAULT_PORT=3552 # Initialize all core functions (colors, formatting, icons, STD mode) load_functions -# ============================================================================== -# HEADER -# ============================================================================== -function header_info { - clear - cat <<"EOF" - ___ ____ _________ _ ________ - / | / __ \/ ____/ | / | / / ____/ - / /| | / /_/ / / / /| | / |/ / __/ - / ___ |/ _, _/ /___/ ___ |/ /| / /___ -/_/ |_/_/ |_|\____/_/ |_/_/ |_/_____/ - -EOF -} - # ============================================================================== # UNINSTALL # ============================================================================== @@ -82,26 +72,11 @@ function update() { exit } -# ============================================================================== -# CHECK DOCKER -# ============================================================================== -function check_docker() { - if ! command -v docker &>/dev/null; then - msg_error "Docker is not installed. This script requires an existing Docker LXC. Exiting." - exit 10 - fi - if ! docker compose version &>/dev/null; then - msg_error "Docker Compose plugin is not available. Please install it before running this script. Exiting." - exit 10 - fi - msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') and Docker Compose are available" -} - # ============================================================================== # INSTALL # ============================================================================== function install() { - check_docker + ensure_docker msg_info "Creating install directory" mkdir -p "$INSTALL_PATH" @@ -178,6 +153,7 @@ if [[ "${type:-}" == "update" ]]; then fi header_info +confirm_not_pve_host get_lxc_ip # Check if already installed diff --git a/tools/addon/coder-code-server.sh b/tools/addon/coder-code-server.sh index 95039aebec7..b75bc36a4af 100644 --- a/tools/addon/coder-code-server.sh +++ b/tools/addon/coder-code-server.sh @@ -5,62 +5,153 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://coder.com/ | Github: https://github.com/coder/code-server -function header_info { - cat <<"EOF" - ______ __ _____ - / ____/___ ____/ /__ / ___/___ ______ _____ _____ - / / / __ \/ __ / _ \ \__ \/ _ \/ ___/ | / / _ \/ ___/ -/ /___/ /_/ / /_/ / __/ ___/ / __/ / | |/ / __/ / -\____/\____/\__,_/\___/ /____/\___/_/ |___/\___/_/ - -EOF -} -IP=$(hostname -I | awk '{print $1}') -YW=$(echo "\033[33m") -BL=$(echo "\033[36m") -RD=$(echo "\033[01;31m") -BGN=$(echo "\033[4;92m") -GN=$(echo "\033[1;92m") -DGN=$(echo "\033[32m") -CL=$(echo "\033[m") -BFR="\\r\\033[K" -HOLD="-" -CM="${GN}✓${CL}" -APP="Coder Code Server" -hostname="$(hostname)" - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "coder-code-server" "addon" -set -o errexit -set -o errtrace -set -o nounset -set -o pipefail -shopt -s expand_aliases -alias die='EXIT=$? LINE=$LINENO error_exit' -trap die ERR +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR + +APP="Coder Code Server" +APP_TYPE="addon" + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions -function error_exit() { - trap - ERR - local reason="Unknown failure occured." - local msg="${1:-$reason}" - local flag="${RD}‼ ERROR ${CL}$EXIT@$LINE" - echo -e "$flag $msg" 1>&2 - exit "$EXIT" -} -clear header_info -if command -v pveversion >/dev/null 2>&1; then - echo -e "⚠️ Can't Install on Proxmox " - exit +ensure_usr_local_bin_persist +get_lxc_ip +IP="$LOCAL_IP" + +confirm_not_pve_host +require_debian_like + +# ============================================================================== +# UNINSTALL +# ============================================================================== +function uninstall() { + msg_info "Uninstalling ${APP}" + systemctl disable --now code-server@"$USER" &>/dev/null || true + $STD apt remove -y code-server + rm -f "$HOME/.coder-code-server" + msg_ok "${APP} has been uninstalled" +} + +# ============================================================================== +# UPDATE +# ============================================================================== +function update() { + if check_for_gh_release "coder-code-server" "coder/code-server"; then + msg_info "Updating ${APP}" + fetch_and_deploy_gh_release "coder-code-server" "coder/code-server" "binary" "latest" "/opt/coder-code-server" "code-server_*_$(arch_resolve).deb" + systemctl restart code-server@"$USER" + msg_ok "Updated successfully!" + exit + fi +} + +# ============================================================================== +# INSTALL +# ============================================================================== +function install() { + msg_info "Installing Dependencies" + $STD apt update + $STD apt install -y \ + curl \ + git + msg_ok "Installed Dependencies" + + msg_info "Installing ${APP}" + config_path="${HOME}/.config/code-server/config.yaml" + preexisting_config=false + if [ -f "$config_path" ]; then + preexisting_config=true + fi + + fetch_and_deploy_gh_release "coder-code-server" "coder/code-server" "binary" "latest" "/opt/coder-code-server" "code-server_*_$(arch_resolve).deb" + mkdir -p "${HOME}/.config/code-server/" + + if [ "$preexisting_config" = false ]; then + cat <"$config_path" +bind-addr: 0.0.0.0:8680 +auth: none +password: +cert: false +EOF + fi + systemctl enable -q --now code-server@"$USER" + systemctl restart code-server@"$USER" + if ! systemctl is-active --quiet code-server@"$USER"; then + msg_error "code-server service failed to start." + exit 150 + fi + msg_ok "Installed ${APP}" + + msg_info "Creating update script" + ensure_usr_local_bin_persist + cat <<'EOF' >/usr/local/bin/update_coder-code-server +#!/usr/bin/env bash +# Coder Code Server Update Script +type=update bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coder-code-server.sh)" +EOF + chmod +x /usr/local/bin/update_coder-code-server + msg_ok "Created update script (/usr/local/bin/update_coder-code-server)" + + echo -e "${APP} should be reachable by going to the following URL. + ${BL}http://${IP}:8680${CL} \n" +} + +# ============================================================================== +# MAIN +# ============================================================================== + +# Handle type=update (called from update script) +if [[ "${type:-}" == "update" ]]; then + if command -v code-server &>/dev/null; then + update + else + msg_error "${APP} is not installed. Nothing to update." + exit 233 + fi + exit 0 fi -if [ -e /etc/alpine-release ]; then - echo -e "⚠️ Can't Install on Alpine" - exit + +if [[ -d "$HOME" && -f "$HOME/.coder-code-server" ]] || command -v code-server &>/dev/null; then + msg_warn "${APP} is already installed." + echo -n "${TAB}Uninstall ${APP}? (y/N): " + read -r uninstall_prompt + if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then + uninstall + exit 0 + fi + + echo -n "${TAB}Update ${APP}? (y/N): " + read -r update_prompt + if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then + update + exit 0 + fi + + msg_warn "No action selected. Exiting." + exit 0 fi + while true; do - read -p "This will Install ${APP} on $hostname. Proceed(y/n)?" yn + echo -n "${TAB}This will Install ${APP}. Proceed (y/n)? " + read -r yn case $yn in [Yy]*) break ;; [Nn]*) exit ;; @@ -68,53 +159,4 @@ while true; do esac done -function msg_info() { - local msg="$1" - echo -ne " ${HOLD} ${YW}${msg}..." -} - -function msg_ok() { - local msg="$1" - echo -e "${BFR} ${CM} ${GN}${msg}${CL}" -} - -msg_info "Installing Dependencies" -apt-get update &>/dev/null -apt-get install -y curl &>/dev/null -apt-get install -y git &>/dev/null -msg_ok "Installed Dependencies" - -VERSION=$(curl -fsSL https://api.github.com/repos/coder/code-server/releases/latest | - grep "tag_name" | - awk '{print substr($2, 3, length($2)-4) }') - -msg_info "Installing Code-Server v${VERSION}" -config_path="${HOME}/.config/code-server/config.yaml" -preexisting_config=false - -if [ -f "$config_path" ]; then - preexisting_config=true -fi - -curl -fOL https://github.com/coder/code-server/releases/download/v"$VERSION"/code-server_"${VERSION}"_amd64.deb &>/dev/null -dpkg -i code-server_"${VERSION}"_amd64.deb &>/dev/null -rm -rf code-server_"${VERSION}"_amd64.deb -mkdir -p "${HOME}/.config/code-server/" - -if [ "$preexisting_config" = false ]; then -cat <"$config_path" -bind-addr: 0.0.0.0:8680 -auth: none -password: -cert: false -EOF -fi -systemctl enable -q --now code-server@"$USER" -systemctl restart code-server@"$USER" -if ! systemctl is-active --quiet code-server@"$USER"; then - error_exit "code-server service failed to start." -fi -msg_ok "Installed Code-Server v${VERSION} on $hostname" - -echo -e "${APP} should be reachable by going to the following URL. - ${BL}http://$IP:8680${CL} \n" +install diff --git a/tools/addon/coolify.sh b/tools/addon/coolify.sh index 31b4ebe448f..fd70e90805f 100644 --- a/tools/addon/coolify.sh +++ b/tools/addon/coolify.sh @@ -66,66 +66,11 @@ function update() { exit } -# ============================================================================== -# PROXMOX HOST CHECK -# ============================================================================== -function check_proxmox_host() { - if command -v pveversion &>/dev/null; then - msg_error "Running on the Proxmox host is NOT recommended!" - msg_error "This should be executed inside an LXC container." - echo "" - echo -n "${TAB}Continue anyway? (y/N): " - read -r confirm - if [[ ! "${confirm,,}" =~ ^(y|yes)$ ]]; then - msg_warn "Aborted. Please run this inside an LXC container." - exit 0 - fi - msg_warn "Proceeding on Proxmox host at your own risk!" - fi -} - -# ============================================================================== -# CHECK / INSTALL DOCKER -# ============================================================================== -function check_or_install_docker() { - if command -v docker &>/dev/null; then - msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') is available" - if docker compose version &>/dev/null; then - msg_ok "Docker Compose is available" - else - msg_error "Docker Compose plugin is not available. Please install it." - exit 10 - fi - return - fi - - msg_warn "Docker is not installed." - echo -n "${TAB}Install Docker now? (y/N): " - read -r install_docker_prompt - if [[ ! "${install_docker_prompt,,}" =~ ^(y|yes)$ ]]; then - msg_error "Docker is required for ${APP}. Exiting." - exit 10 - fi - - msg_info "Installing Docker" - if [[ -f /etc/alpine-release ]]; then - $STD apk add docker docker-cli-compose - $STD rc-service docker start - $STD rc-update add docker default - else - DOCKER_CONFIG_PATH='/etc/docker/daemon.json' - mkdir -p "$(dirname "$DOCKER_CONFIG_PATH")" - echo -e '{\n "log-driver": "journald"\n}' >"$DOCKER_CONFIG_PATH" - $STD sh <(curl -fsSL https://get.docker.com) - fi - msg_ok "Installed Docker" -} - # ============================================================================== # INSTALL # ============================================================================== function install() { - check_or_install_docker + ensure_docker msg_info "Installing dependencies" if [[ -f /etc/alpine-release ]]; then @@ -172,7 +117,7 @@ if [[ "${type:-}" == "update" ]]; then fi header_info -check_proxmox_host +confirm_not_pve_host get_lxc_ip # Check if already installed diff --git a/tools/addon/copyparty.sh b/tools/addon/copyparty.sh index a56e862e00e..ad07c4c5dfd 100644 --- a/tools/addon/copyparty.sh +++ b/tools/addon/copyparty.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -45,28 +50,13 @@ if [[ -f "/etc/alpine-release" ]]; then SERVICE_PATH="/etc/init.d/copyparty" elif grep -qE 'ID=debian|ID=ubuntu' /etc/os-release; then OS="Debian" - PKG_MANAGER="apt-get install -y" + PKG_MANAGER="apt install -y" SERVICE_PATH="/etc/systemd/system/copyparty.service" else msg_error "Unsupported OS detected. Exiting." exit 238 fi -# ============================================================================== -# HEADER -# ============================================================================== -function header_info() { - clear - cat <<"EOF" - ______ ____ __ - / ____/___ ____ __ __/ __ \____ ______/ /___ __ - / / / __ \/ __ \/ / / / /_/ / __ `/ ___/ __/ / / / -/ /___/ /_/ / /_/ / /_/ / ____/ /_/ / / / /_/ /_/ / -\____/\____/ .___/\__, /_/ \__,_/_/ \__/\__, / - /_/ /____/ /____/ -EOF -} - # ============================================================================== # HELPER FUNCTIONS # ============================================================================== @@ -173,9 +163,17 @@ function install() { msg_info "Installing dependencies" if [[ "$OS" == "Debian" ]]; then - $STD $PKG_MANAGER python3 python3-pil ffmpeg curl + $STD $PKG_MANAGER \ + python3 \ + python3-pil \ + ffmpeg \ + curl else - $STD $PKG_MANAGER python3 py3-pillow ffmpeg curl + $STD $PKG_MANAGER \ + python3 \ + py3-pillow \ + ffmpeg \ + curl fi msg_ok "Dependencies installed (with thumbnail support)" diff --git a/tools/addon/cronmaster.sh b/tools/addon/cronmaster.sh index 450572a6838..2ab4cbb1a76 100644 --- a/tools/addon/cronmaster.sh +++ b/tools/addon/cronmaster.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -20,6 +25,7 @@ declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "cronmaster" " set -Eeuo pipefail trap 'error_handler' ERR load_functions +require_debian_like # ============================================================================== # CONFIGURATION @@ -31,29 +37,6 @@ CONFIG_PATH="/opt/cronmaster/.env" SERVICE_PATH="/etc/systemd/system/cronmaster.service" DEFAULT_PORT=3000 -# ============================================================================== -# HEADER -# ============================================================================== -function header_info { - clear - cat <<"EOF" - ______ __ ___ __ - / ____/________ ____ / |/ /___ ______/ /____ _____ - / / / ___/ __ \/ __ \/ /|_/ / __ `/ ___/ __/ _ \/ ___/ -/ /___/ / / /_/ / / / / / / / /_/ (__ ) /_/ __/ / -\____/_/ \____/_/ /_/_/ /_/\__,_/____/\__/\___/_/ - -EOF -} - -# ============================================================================== -# OS DETECTION -# ============================================================================== -if ! grep -qE 'ID=debian|ID=ubuntu' /etc/os-release 2>/dev/null; then - echo -e "${CROSS} Unsupported OS detected. This script only supports Debian and Ubuntu." - exit 238 -fi - # ============================================================================== # UNINSTALL # ============================================================================== @@ -77,16 +60,12 @@ function update() { systemctl stop cronmaster.service &>/dev/null || true msg_ok "Stopped service" - msg_info "Backing up configuration" - cp "$CONFIG_PATH" /tmp/cronmaster.env.bak 2>/dev/null || true - msg_ok "Backed up configuration" + BACKUP_DIR="/opt/cronmaster_backup" + create_backup "$CONFIG_PATH" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cronmaster" "fccview/cronmaster" "prebuild" "latest" "$INSTALL_PATH" "cronmaster_*_prebuild.tar.gz" - msg_info "Restoring configuration" - cp /tmp/cronmaster.env.bak "$CONFIG_PATH" 2>/dev/null || true - rm -f /tmp/cronmaster.env.bak - msg_ok "Restored configuration" + restore_backup msg_info "Starting service" systemctl start cronmaster diff --git a/tools/addon/crowdsec.sh b/tools/addon/crowdsec.sh index 11ec83320c8..905385d28fb 100644 --- a/tools/addon/crowdsec.sh +++ b/tools/addon/crowdsec.sh @@ -5,89 +5,61 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://www.crowdsec.net/ | Github: https://github.com/crowdsecurity/crowdsec -YW=$(echo "\033[33m") -BL=$(echo "\033[36m") -RD=$(echo "\033[01;31m") -BGN=$(echo "\033[4;92m") -GN=$(echo "\033[1;92m") -DGN=$(echo "\033[32m") -CL=$(echo "\033[m") -BFR="\\r\\033[K" -HOLD="-" -CM="${GN}✓${CL}" APP="CrowdSec" -hostname="$(hostname)" +APP_TYPE="addon" -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "crowdsec" "addon" -set -o errexit -set -o errtrace -set -o nounset -set -o pipefail -shopt -s expand_aliases -alias die='EXIT=$? LINE=$LINENO error_exit' -trap die ERR +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions +require_debian_like + +header_info +confirm_not_pve_host -function error_exit() { - trap - ERR - local reason="Unknown failure occured." - local msg="${1:-$reason}" - local flag="${RD}‼ ERROR ${CL}$EXIT@$LINE" - echo -e "$flag $msg" 1>&2 - exit "$EXIT" -} -if command -v pveversion >/dev/null 2>&1; then - echo -e "⚠️ Can't Install on Proxmox " - exit -fi while true; do - read -p "This will Install ${APP} on $hostname. Proceed(y/n)?" yn + echo -n "${TAB}This will Install ${APP}. Proceed (y/n)? " + read -r yn case $yn in [Yy]*) break ;; [Nn]*) exit ;; *) echo "Please answer yes or no." ;; esac done -clear -function header_info() { - echo -e "${BL} - _____ _ _____ - / ____| | |/ ____| - | | _ __ _____ ____| | (___ ___ ___ - | | | __/ _ \ \ /\ / / _ |\___ \ / _ \/ __| - | |____| | | (_) \ V V / (_| |____) | __/ (__ - \_____|_| \___/ \_/\_/ \__ _|_____/ \___|\___| -${CL}" -} - -header_info - -function msg_info() { - local msg="$1" - echo -ne " ${HOLD} ${YW}${msg}..." -} - -function msg_ok() { - local msg="$1" - echo -e "${BFR} ${CM} ${GN}${msg}${CL}" -} msg_info "Setting up ${APP} Repository" -apt-get update &>/dev/null -apt-get install -y curl &>/dev/null -apt-get install -y gnupg &>/dev/null -curl -fsSL "https://install.crowdsec.net" | bash &>/dev/null +$STD apt update +$STD apt install -y \ + curl \ + gnupg +$STD bash -c "curl -fsSL https://install.crowdsec.net | bash" msg_ok "Setup ${APP} Repository" msg_info "Installing ${APP}" -apt-get update &>/dev/null -apt-get install -y crowdsec &>/dev/null -msg_ok "Installed ${APP} on $hostname" +$STD apt update +$STD apt install -y crowdsec +msg_ok "Installed ${APP}" msg_info "Installing ${APP} Common Bouncer" -apt-get install -y crowdsec-firewall-bouncer-iptables &>/dev/null +$STD apt install -y crowdsec-firewall-bouncer-iptables msg_ok "Installed ${APP} Common Bouncer" msg_ok "Completed successfully!\n" diff --git a/tools/addon/dockge.sh b/tools/addon/dockge.sh index ef8e2d27a63..52042a352d8 100644 --- a/tools/addon/dockge.sh +++ b/tools/addon/dockge.sh @@ -72,66 +72,11 @@ function update() { exit } -# ============================================================================== -# PROXMOX HOST CHECK -# ============================================================================== -function check_proxmox_host() { - if command -v pveversion &>/dev/null; then - msg_error "Running on the Proxmox host is NOT recommended!" - msg_error "This should be executed inside an LXC container." - echo "" - echo -n "${TAB}Continue anyway? (y/N): " - read -r confirm - if [[ ! "${confirm,,}" =~ ^(y|yes)$ ]]; then - msg_warn "Aborted. Please run this inside an LXC container." - exit 0 - fi - msg_warn "Proceeding on Proxmox host at your own risk!" - fi -} - -# ============================================================================== -# CHECK / INSTALL DOCKER -# ============================================================================== -function check_or_install_docker() { - if command -v docker &>/dev/null; then - msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') is available" - if docker compose version &>/dev/null; then - msg_ok "Docker Compose is available" - else - msg_error "Docker Compose plugin is not available. Please install it." - exit 10 - fi - return - fi - - msg_warn "Docker is not installed." - echo -n "${TAB}Install Docker now? (y/N): " - read -r install_docker_prompt - if [[ ! "${install_docker_prompt,,}" =~ ^(y|yes)$ ]]; then - msg_error "Docker is required for ${APP}. Exiting." - exit 10 - fi - - msg_info "Installing Docker" - if [[ -f /etc/alpine-release ]]; then - $STD apk add docker docker-cli-compose - $STD rc-service docker start - $STD rc-update add docker default - else - DOCKER_CONFIG_PATH='/etc/docker/daemon.json' - mkdir -p "$(dirname "$DOCKER_CONFIG_PATH")" - echo -e '{\n "log-driver": "journald"\n}' >"$DOCKER_CONFIG_PATH" - $STD sh <(curl -fsSL https://get.docker.com) - fi - msg_ok "Installed Docker" -} - # ============================================================================== # INSTALL # ============================================================================== function install() { - check_or_install_docker + ensure_docker msg_info "Creating install directories" mkdir -p "$INSTALL_PATH" "$STACKS_PATH" @@ -167,7 +112,7 @@ if [[ "${type:-}" == "update" ]]; then fi header_info -check_proxmox_host +confirm_not_pve_host get_lxc_ip # Check if already installed diff --git a/tools/addon/dokploy.sh b/tools/addon/dokploy.sh index 85dd7d53bfc..7cf49330819 100644 --- a/tools/addon/dokploy.sh +++ b/tools/addon/dokploy.sh @@ -65,66 +65,11 @@ function update() { exit } -# ============================================================================== -# PROXMOX HOST CHECK -# ============================================================================== -function check_proxmox_host() { - if command -v pveversion &>/dev/null; then - msg_error "Running on the Proxmox host is NOT recommended!" - msg_error "This should be executed inside an LXC container." - echo "" - echo -n "${TAB}Continue anyway? (y/N): " - read -r confirm - if [[ ! "${confirm,,}" =~ ^(y|yes)$ ]]; then - msg_warn "Aborted. Please run this inside an LXC container." - exit 0 - fi - msg_warn "Proceeding on Proxmox host at your own risk!" - fi -} - -# ============================================================================== -# CHECK / INSTALL DOCKER -# ============================================================================== -function check_or_install_docker() { - if command -v docker &>/dev/null; then - msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') is available" - if docker compose version &>/dev/null; then - msg_ok "Docker Compose is available" - else - msg_error "Docker Compose plugin is not available. Please install it." - exit 10 - fi - return - fi - - msg_warn "Docker is not installed." - echo -n "${TAB}Install Docker now? (y/N): " - read -r install_docker_prompt - if [[ ! "${install_docker_prompt,,}" =~ ^(y|yes)$ ]]; then - msg_error "Docker is required for ${APP}. Exiting." - exit 10 - fi - - msg_info "Installing Docker" - if [[ -f /etc/alpine-release ]]; then - $STD apk add docker docker-cli-compose - $STD rc-service docker start - $STD rc-update add docker default - else - DOCKER_CONFIG_PATH='/etc/docker/daemon.json' - mkdir -p "$(dirname "$DOCKER_CONFIG_PATH")" - echo -e '{\n "log-driver": "journald"\n}' >"$DOCKER_CONFIG_PATH" - $STD sh <(curl -fsSL https://get.docker.com) - fi - msg_ok "Installed Docker" -} - # ============================================================================== # INSTALL # ============================================================================== function install() { - check_or_install_docker + ensure_docker msg_info "Installing dependencies" if [[ -f /etc/alpine-release ]]; then @@ -170,7 +115,7 @@ if [[ "${type:-}" == "update" ]]; then fi header_info -check_proxmox_host +confirm_not_pve_host get_lxc_ip # Check if already installed diff --git a/tools/addon/filebrowser-quantum.sh b/tools/addon/filebrowser-quantum.sh index ca586f04d07..8cc2439c1d6 100644 --- a/tools/addon/filebrowser-quantum.sh +++ b/tools/addon/filebrowser-quantum.sh @@ -5,55 +5,51 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://github.com/filebrowserspace/quantum -function header_info() { - clear - cat <<"EOF" - _______ __ ____ ____ __ - / ____(_) /__ / __ )_________ _ __________ _____ / __ \__ ______ _____ / /___ ______ ___ - / /_ / / / _ \/ __ / ___/ __ \ | /| / / ___/ _ \/ ___/ / / / / / / / __ `/ __ \/ __/ / / / __ `__ \ - / __/ / / / __/ /_/ / / / /_/ / |/ |/ (__ ) __/ / / /_/ / /_/ / /_/ / / / / /_/ /_/ / / / / / / -/_/ /_/_/\___/_____/_/ \____/|__/|__/____/\___/_/ \___\_\__,_/\__,_/_/ /_/\__/\__,_/_/ /_/ /_/ - -EOF -} - -YW=$(echo "\033[33m") -GN=$(echo "\033[1;92m") -RD=$(echo "\033[01;31m") -BL=$(echo "\033[36m") -CL=$(echo "\033[m") -CM="${GN}✔️${CL}" -CROSS="${RD}✖️${CL}" -INFO="${BL}ℹ️${CL}" - APP="FileBrowser Quantum" +APP_TYPE="addon" INSTALL_PATH="/usr/local/bin/filebrowser" CONFIG_PATH="/usr/local/community-scripts/fq-config.yaml" DEFAULT_PORT=8080 SRC_DIR="/" -TMP_BIN="/tmp/filebrowser.$$" -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "filebrowser-quantum" "addon" -# Get primary IP -IFACE=$(ip -4 route | awk '/default/ {print $5; exit}') -IP=$(ip -4 addr show "$IFACE" | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1) -[[ -z "$IP" ]] && IP=$(hostname -I | awk '{print $1}') -[[ -z "$IP" ]] && IP="127.0.0.1" +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions + +header_info +get_lxc_ip +IP="$LOCAL_IP" # Proxmox Host Warning if [[ -d "/etc/pve" ]]; then - echo -e "${RD}⚠️ Warning: Running this addon directly on the Proxmox host is not recommended!${CL}" - echo -e "${YW} Only the boot disk will be visible — passthrough drives will not be indexed.${CL}" - echo -e "${YW} This causes incorrect disk usage stats and incomplete file browsing.${CL}" - echo -e "${YW} Run this addon inside an LXC or VM instead and mount your drives there.${CL}" + msg_warn "Running this addon directly on the Proxmox host is not recommended!" + msg_warn "Only the boot disk will be visible — passthrough drives will not be indexed." + msg_warn "This causes incorrect disk usage stats and incomplete file browsing." + msg_warn "Run this addon inside an LXC or VM instead and mount your drives there." echo "" - echo -n "Continue anyway on the Proxmox host? (y/N): " + echo -n "${TAB}Continue anyway on the Proxmox host? (y/N): " read -r host_confirm if [[ ! "${host_confirm,,}" =~ ^(y|yes)$ ]]; then - echo -e "${YW}Aborted.${CL}" + msg_error "Aborted." exit 0 fi fi @@ -66,18 +62,12 @@ if [[ -f "/etc/alpine-release" ]]; then elif [[ -f "/etc/debian_version" ]]; then OS="Debian" SERVICE_PATH="/etc/systemd/system/filebrowser.service" - PKG_MANAGER="apt-get install -y" + PKG_MANAGER="apt install -y" else - echo -e "${CROSS} Unsupported OS detected. Exiting." + msg_error "Unsupported OS detected. Exiting." exit 238 fi -header_info - -function msg_info() { echo -e "${INFO} ${YW}$1...${CL}"; } -function msg_ok() { echo -e "${CM} ${GN}$1${CL}"; } -function msg_error() { echo -e "${CROSS} ${RD}$1${CL}"; } - # Detect legacy FileBrowser installation LEGACY_DB="/usr/local/community-scripts/filebrowser.db" LEGACY_BIN="/usr/local/bin/filebrowser" @@ -85,80 +75,82 @@ LEGACY_SERVICE_DEB="/etc/systemd/system/filebrowser.service" LEGACY_SERVICE_ALP="/etc/init.d/filebrowser" if [[ -f "$LEGACY_DB" || -f "$LEGACY_BIN" && ! -f "$CONFIG_PATH" ]]; then - echo -e "${YW}⚠️ Detected legacy FileBrowser installation.${CL}" - echo -n "Uninstall legacy FileBrowser and continue with Quantum install? (y/n): " + msg_warn "Detected legacy FileBrowser installation." + echo -n "${TAB}Uninstall legacy FileBrowser and continue with Quantum install? (y/n): " read -r remove_legacy if [[ "${remove_legacy,,}" =~ ^(y|yes)$ ]]; then msg_info "Uninstalling legacy FileBrowser" if [[ -f "$LEGACY_SERVICE_DEB" ]]; then - systemctl disable --now filebrowser.service &>/dev/null + systemctl disable --now filebrowser.service &>/dev/null || true rm -f "$LEGACY_SERVICE_DEB" elif [[ -f "$LEGACY_SERVICE_ALP" ]]; then - rc-service filebrowser stop &>/dev/null - rc-update del filebrowser &>/dev/null + rc-service filebrowser stop &>/dev/null || true + rc-update del filebrowser &>/dev/null || true rm -f "$LEGACY_SERVICE_ALP" fi rm -f "$LEGACY_BIN" "$LEGACY_DB" msg_ok "Legacy FileBrowser removed" else - echo -e "${YW}❌ Installation aborted by user.${CL}" + msg_error "Installation aborted by user." exit 0 fi fi # Existing installation if [[ -f "$INSTALL_PATH" ]]; then - echo -e "${YW}⚠️ ${APP} is already installed.${CL}" - echo -n "Uninstall ${APP}? (y/N): " + msg_warn "${APP} is already installed." + echo -n "${TAB}Uninstall ${APP}? (y/N): " read -r uninstall_prompt if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Uninstalling ${APP}" if [[ "$OS" == "Debian" ]]; then - systemctl disable --now filebrowser.service &>/dev/null + systemctl disable --now filebrowser.service &>/dev/null || true rm -f "$SERVICE_PATH" else - rc-service filebrowser stop &>/dev/null - rc-update del filebrowser &>/dev/null + rc-service filebrowser stop &>/dev/null || true + rc-update del filebrowser &>/dev/null || true rm -f "$SERVICE_PATH" fi - rm -f "$INSTALL_PATH" "$CONFIG_PATH" + rm -f "$INSTALL_PATH" "$CONFIG_PATH" "$HOME/.filebrowser-quantum" msg_ok "${APP} has been uninstalled." exit 0 fi - echo -n "Update ${APP}? (y/N): " + echo -n "${TAB}Update ${APP}? (y/N): " read -r update_prompt if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then - msg_info "Updating ${APP}" - if ! command -v curl &>/dev/null; then $PKG_MANAGER curl &>/dev/null; fi - curl -fsSL https://github.com/gtsteffaniak/filebrowser/releases/latest/download/linux-amd64-filebrowser -o "$TMP_BIN" - chmod +x "$TMP_BIN" - mv -f "$TMP_BIN" /usr/local/bin/filebrowser - msg_ok "Updated ${APP}" + if check_for_gh_release "filebrowser-quantum" "gtsteffaniak/filebrowser"; then + msg_info "Updating ${APP}" + if ! command -v curl &>/dev/null; then $STD $PKG_MANAGER curl; fi + fetch_and_deploy_gh_release "filebrowser-quantum" "gtsteffaniak/filebrowser" "singlefile" "latest" "/usr/local/bin" "linux-$(arch_resolve)-filebrowser" + mv -f /usr/local/bin/filebrowser-quantum "$INSTALL_PATH" + msg_ok "Updated ${APP}" + fi exit 0 else - echo -e "${YW}⚠️ Update skipped. Exiting.${CL}" + msg_warn "Update skipped. Exiting." exit 0 fi fi -echo -e "${YW}⚠️ ${APP} is not installed.${CL}" -echo -n "Enter port number (Default: ${DEFAULT_PORT}): " +msg_warn "${APP} is not installed." +echo -n "${TAB}Enter port number (Default: ${DEFAULT_PORT}): " read -r PORT PORT=${PORT:-$DEFAULT_PORT} -echo -n "Install ${APP}? (y/n): " +echo -n "${TAB}Install ${APP}? (y/n): " read -r install_prompt if ! [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then - echo -e "${YW}⚠️ Installation skipped. Exiting.${CL}" + msg_warn "Installation skipped. Exiting." exit 0 fi msg_info "Installing ${APP} on ${OS}" -$PKG_MANAGER curl ffmpeg &>/dev/null -curl -fsSL https://github.com/gtsteffaniak/filebrowser/releases/latest/download/linux-amd64-filebrowser -o "$TMP_BIN" -chmod +x "$TMP_BIN" -mv -f "$TMP_BIN" /usr/local/bin/filebrowser +$STD $PKG_MANAGER \ + curl \ + ffmpeg +fetch_and_deploy_gh_release "filebrowser-quantum" "gtsteffaniak/filebrowser" "singlefile" "latest" "/usr/local/bin" "linux-$(arch_resolve)-filebrowser" +mv -f /usr/local/bin/filebrowser-quantum "$INSTALL_PATH" msg_ok "Installed ${APP}" msg_info "Preparing configuration directory" @@ -167,7 +159,7 @@ chown root:root /usr/local/community-scripts chmod 755 /usr/local/community-scripts msg_ok "Directory prepared" -echo -n "Use No Authentication? (y/N): " +echo -n "${TAB}Use No Authentication? (y/N): " read -r noauth_prompt # === YAML CONFIG GENERATION === @@ -251,9 +243,9 @@ depend() { } EOF chmod +x "$SERVICE_PATH" - rc-update add filebrowser default &>/dev/null - rc-service filebrowser start &>/dev/null + $STD rc-update add filebrowser default + $STD rc-service filebrowser start fi msg_ok "Service created successfully" -echo -e "${CM} ${GN}${APP} is reachable at: ${BL}http://$IP:$PORT${CL}" +msg_ok "${APP} is reachable at: ${BL}http://${IP}:${PORT}${CL}" diff --git a/tools/addon/filebrowser.sh b/tools/addon/filebrowser.sh index a7db5f12250..743330e4734 100644 --- a/tools/addon/filebrowser.sh +++ b/tools/addon/filebrowser.sh @@ -5,53 +5,50 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://filebrowser.org/ | Github: https://github.com/filebrowser/filebrowser -function header_info { - clear - cat <<"EOF" - _______ __ ____ - / ____(_) /__ / __ )_________ _ __________ _____ - / /_ / / / _ \/ __ / ___/ __ \ | /| / / ___/ _ \/ ___/ - / __/ / / / __/ /_/ / / / /_/ / |/ |/ (__ ) __/ / -/_/ /_/_/\___/_____/_/ \____/|__/|__/____/\___/_/ -EOF -} - -YW=$(echo "\033[33m") -GN=$(echo "\033[1;92m") -RD=$(echo "\033[01;31m") -BL=$(echo "\033[36m") -CL=$(echo "\033[m") -CM="${GN}✔️${CL}" -CROSS="${RD}✖️${CL}" -INFO="${BL}ℹ️${CL}" - APP="FileBrowser" +APP_TYPE="addon" INSTALL_PATH="/usr/local/bin/filebrowser" DB_PATH="/usr/local/community-scripts/filebrowser.db" DEFAULT_PORT=8080 -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "filebrowser" "addon" -# Get first non-loopback IP & Detect primary network interface dynamically -IFACE=$(ip -4 route | awk '/default/ {print $5; exit}') -IP=$(ip -4 addr show "$IFACE" | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1) +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR -[[ -z "$IP" ]] && IP=$(hostname -I | awk '{print $1}') -[[ -z "$IP" ]] && IP="127.0.0.1" +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions + +header_info +get_lxc_ip +IP="$LOCAL_IP" # Proxmox Host Warning if [[ -d "/etc/pve" ]]; then - echo -e "${RD}⚠️ Warning: Running this addon directly on the Proxmox host is not recommended!${CL}" - echo -e "${YW} Only the boot disk will be visible — passthrough drives will not be indexed.${CL}" - echo -e "${YW} This causes incorrect disk usage stats and incomplete file browsing.${CL}" - echo -e "${YW} Run this addon inside an LXC or VM instead and mount your drives there.${CL}" + msg_warn "Running this addon directly on the Proxmox host is not recommended!" + msg_warn "Only the boot disk will be visible — passthrough drives will not be indexed." + msg_warn "This causes incorrect disk usage stats and incomplete file browsing." + msg_warn "Run this addon inside an LXC or VM instead and mount your drives there." echo "" - echo -n "Continue anyway on the Proxmox host? (y/N): " + echo -n "${TAB}Continue anyway on the Proxmox host? (y/N): " read -r host_confirm if [[ ! "${host_confirm,,}" =~ ^(y|yes)$ ]]; then - echo -e "${YW}Aborted.${CL}" + msg_error "Aborted." exit 0 fi fi @@ -64,71 +61,59 @@ if [[ -f "/etc/alpine-release" ]]; then elif [[ -f "/etc/debian_version" ]]; then OS="Debian" SERVICE_PATH="/etc/systemd/system/filebrowser.service" - PKG_MANAGER="apt-get install -y" + PKG_MANAGER="apt install -y" else - echo -e "${CROSS} Unsupported OS detected. Exiting." + msg_error "Unsupported OS detected. Exiting." exit 238 fi -header_info - -function msg_info() { - local msg="$1" - echo -e "${INFO} ${YW}${msg}...${CL}" -} - -function msg_ok() { - local msg="$1" - echo -e "${CM} ${GN}${msg}${CL}" -} - -function msg_error() { - local msg="$1" - echo -e "${CROSS} ${RD}${msg}${CL}" -} - if [ -f "$INSTALL_PATH" ]; then - echo -e "${YW}⚠️ ${APP} is already installed.${CL}" + msg_warn "${APP} is already installed." read -r -p "Would you like to uninstall ${APP}? (y/N): " uninstall_prompt if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Uninstalling ${APP}" if [[ "$OS" == "Debian" ]]; then - systemctl disable --now filebrowser.service &>/dev/null + systemctl disable --now filebrowser.service &>/dev/null || true rm -f "$SERVICE_PATH" else - rc-service filebrowser stop &>/dev/null - rc-update del filebrowser &>/dev/null + rc-service filebrowser stop &>/dev/null || true + rc-update del filebrowser &>/dev/null || true rm -f "$SERVICE_PATH" fi - rm -f "$INSTALL_PATH" "$DB_PATH" + rm -f "$INSTALL_PATH" "$DB_PATH" "$HOME/.filebrowser" msg_ok "${APP} has been uninstalled." exit 0 fi read -r -p "Would you like to update ${APP}? (y/N): " update_prompt if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then - msg_info "Updating ${APP}" - if ! command -v curl &>/dev/null; then $PKG_MANAGER curl &>/dev/null; fi - curl -fsSL "https://github.com/filebrowser/filebrowser/releases/latest/download/linux-amd64-filebrowser.tar.gz" | tar -xzv -C /usr/local/bin &>/dev/null - chmod +x "$INSTALL_PATH" - msg_ok "Updated ${APP}" + if check_for_gh_release "filebrowser" "filebrowser/filebrowser"; then + msg_info "Updating ${APP}" + fetch_and_deploy_gh_release "filebrowser" "filebrowser/filebrowser" "prebuild" "latest" "/opt/filebrowser-dist" "linux-$(arch_resolve)-filebrowser.tar.gz" + install -m 755 /opt/filebrowser-dist/filebrowser "$INSTALL_PATH" + rm -rf /opt/filebrowser-dist + msg_ok "Updated ${APP}" + fi exit 0 else - echo -e "${YW}⚠️ Update skipped. Exiting.${CL}" + msg_warn "Update skipped. Exiting." exit 0 fi fi -echo -e "${YW}⚠️ ${APP} is not installed.${CL}" +msg_warn "${APP} is not installed." read -r -p "Enter port number (Default: ${DEFAULT_PORT}): " PORT PORT=${PORT:-$DEFAULT_PORT} read -r -p "Would you like to install ${APP}? (y/n): " install_prompt if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing ${APP} on ${OS}" - $PKG_MANAGER wget tar curl &>/dev/null - curl -fsSL "https://github.com/filebrowser/filebrowser/releases/latest/download/linux-amd64-filebrowser.tar.gz" | tar -xzv -C /usr/local/bin &>/dev/null - chmod +x "$INSTALL_PATH" + $STD $PKG_MANAGER \ + tar \ + curl + fetch_and_deploy_gh_release "filebrowser" "filebrowser/filebrowser" "prebuild" "latest" "/opt/filebrowser-dist" "linux-$(arch_resolve)-filebrowser.tar.gz" + install -m 755 /opt/filebrowser-dist/filebrowser "$INSTALL_PATH" + rm -rf /opt/filebrowser-dist msg_ok "Installed ${APP}" msg_info "Creating FileBrowser directory" @@ -144,19 +129,19 @@ if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then if [[ "${auth_prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Configuring No Authentication" cd /usr/local/community-scripts - filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null - filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null - filebrowser config set --auth.method=noauth --database "$DB_PATH" &>/dev/null + $STD filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" + $STD filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" + $STD filebrowser config set --auth.method=noauth --database "$DB_PATH" if ! filebrowser users update 1 --perm.admin --database "$DB_PATH" &>/dev/null; then - filebrowser users add admin community-scripts.org --perm.admin --database "$DB_PATH" &>/dev/null + $STD filebrowser users add admin community-scripts.org --perm.admin --database "$DB_PATH" fi msg_ok "No Authentication configured" else msg_info "Setting up default authentication" cd /usr/local/community-scripts - filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null - filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null - filebrowser users add admin community-scripts.org --perm.admin --database "$DB_PATH" &>/dev/null + $STD filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" + $STD filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" + $STD filebrowser users add admin community-scripts.org --perm.admin --database "$DB_PATH" msg_ok "Default authentication configured (admin:community-scripts.org)" fi @@ -194,13 +179,13 @@ depend() { } EOF chmod +x "$SERVICE_PATH" - rc-update add filebrowser default &>/dev/null - rc-service filebrowser start &>/dev/null + $STD rc-update add filebrowser default + $STD rc-service filebrowser start fi msg_ok "Service created successfully" - echo -e "${CM} ${GN}${APP} is reachable at: ${BL}http://$IP:$PORT${CL}" + msg_ok "${APP} is reachable at: ${BL}http://${IP}:${PORT}${CL}" else - echo -e "${YW}⚠️ Installation skipped. Exiting.${CL}" + msg_warn "Installation skipped. Exiting." exit 0 fi diff --git a/tools/addon/glances.sh b/tools/addon/glances.sh index 7c9d7f9d824..842457a8407 100644 --- a/tools/addon/glances.sh +++ b/tools/addon/glances.sh @@ -5,55 +5,47 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://nicolargo.github.io/glances/ | Github: https://github.com/nicolargo/glances -function header_info { - clear - cat <<"EOF" - ________ - / ____/ /___ _____ ________ _____ - / / __/ / __ `/ __ \/ ___/ _ \/ ___/ -/ /_/ / / /_/ / / / / /__/ __(__ ) -\____/_/\__,_/_/ /_/\___/\___/____/ - -EOF -} - APP="Glances" -YW=$(echo "\033[33m") -GN=$(echo "\033[1;92m") -RD=$(echo "\033[01;31m") -BL=$(echo "\033[36m") -CL=$(echo "\033[m") -CM="${GN}✔️${CL}" -CROSS="${RD}✖️${CL}" -INFO="${BL}ℹ️${CL}" +APP_TYPE="addon" -function msg_info() { echo -e "${INFO} ${YW}$1...${CL}"; } -function msg_ok() { echo -e "${CM} ${GN}$1${CL}"; } -function msg_error() { echo -e "${CROSS} ${RD}$1${CL}"; } - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "glances" "addon" -get_lxc_ip() { - if command -v hostname >/dev/null 2>&1 && hostname -I 2>/dev/null; then - hostname -I | awk '{print $1}' - elif command -v ip >/dev/null 2>&1; then - ip -4 addr show scope global | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1 - else - echo "127.0.0.1" - fi -} -IP=$(get_lxc_ip) +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions + +header_info +get_lxc_ip +IP="$LOCAL_IP" install_glances_debian() { msg_info "Installing dependencies" - apt-get update >/dev/null 2>&1 - apt-get install -y gcc lm-sensors wireless-tools curl >/dev/null 2>&1 + $STD apt update + $STD apt install -y \ + gcc \ + lm-sensors \ + wireless-tools \ + curl msg_ok "Installed dependencies" msg_info "Setting up Python + uv" - source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) setup_uv PYTHON_VERSION="3.12" msg_ok "Setup Python + uv" @@ -61,10 +53,10 @@ install_glances_debian() { cd /opt mkdir -p glances cd glances - uv venv --clear + $STD uv venv --clear source .venv/bin/activate >/dev/null 2>&1 - uv pip install --upgrade pip wheel setuptools >/dev/null 2>&1 - uv pip install "glances[web]" >/dev/null 2>&1 + $STD uv pip install --upgrade pip wheel setuptools + $STD uv pip install "glances[web]" deactivate msg_ok "Installed $APP" @@ -86,7 +78,7 @@ EOF systemctl enable -q --now glances msg_ok "Created systemd service" - echo -e "\n$APP is now running at: http://$IP:61208\n" + msg_ok "$APP is now running at: http://${IP}:61208" } # update on Debian/Ubuntu @@ -98,7 +90,7 @@ update_glances_debian() { msg_info "Updating $APP" cd /opt/glances source .venv/bin/activate - uv pip install --upgrade "glances[web]" >/dev/null 2>&1 + $STD uv pip install --upgrade "glances[web]" deactivate systemctl restart glances msg_ok "Updated successfully!" @@ -116,14 +108,13 @@ uninstall_glances_debian() { # install on Alpine install_glances_alpine() { msg_info "Installing dependencies" - apk update >/dev/null 2>&1 + $STD apk update $STD apk add --no-cache \ gcc musl-dev linux-headers python3-dev \ - python3 py3-pip py3-virtualenv lm-sensors wireless-tools curl >/dev/null 2>&1 + python3 py3-pip py3-virtualenv lm-sensors wireless-tools curl msg_ok "Installed dependencies" msg_info "Setting up Python + uv" - source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) setup_uv PYTHON_VERSION="3.12" msg_ok "Setup Python + uv" @@ -131,10 +122,10 @@ install_glances_alpine() { cd /opt mkdir -p glances cd glances - uv venv --clear + $STD uv venv --clear source .venv/bin/activate - uv pip install --upgrade pip wheel setuptools >/dev/null 2>&1 - uv pip install "glances[web]" >/dev/null 2>&1 + $STD uv pip install --upgrade pip wheel setuptools + $STD uv pip install "glances[web]" deactivate msg_ok "Installed $APP" @@ -165,7 +156,7 @@ update_glances_alpine() { msg_info "Updating $APP" cd /opt/glances source .venv/bin/activate - uv pip install --upgrade "glances[web]" >/dev/null 2>&1 + $STD uv pip install --upgrade "glances[web]" deactivate rc-service glances restart msg_ok "Updated successfully!" diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh index 16b114b7a6b..77e1f134f86 100644 --- a/tools/addon/homebrew.sh +++ b/tools/addon/homebrew.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -19,7 +24,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV set -Eeuo pipefail trap 'error_handler' ERR load_functions -init_tool_telemetry "" "addon" +declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "homebrew" "addon" # ============================================================================== # CONFIGURATION @@ -29,18 +34,7 @@ APP="homebrew" APP_TYPE="tools" INSTALL_PATH="/home/linuxbrew/.linuxbrew" -# ============================================================================== -# OS DETECTION -# ============================================================================== -if [[ -f "/etc/alpine-release" ]]; then - echo -e "${CROSS} Alpine is not supported by Homebrew. Exiting." - exit 1 -elif grep -qE 'ID=debian|ID=ubuntu' /etc/os-release; then - OS="Debian" -else - echo -e "${CROSS} Unsupported OS detected. Exiting." - exit 1 -fi +require_debian_like # ============================================================================== # UNINSTALL @@ -81,7 +75,7 @@ function install() { msg_ok "Created user 'brew'" else msg_error "Cannot install Homebrew without a non-root user. Exiting." - exit 1 + exit 254 fi fi msg_ok "Detected User: $BREW_USER" diff --git a/tools/addon/immich-public-proxy.sh b/tools/addon/immich-public-proxy.sh index f6d72fd5145..4981dfdb1f3 100644 --- a/tools/addon/immich-public-proxy.sh +++ b/tools/addon/immich-public-proxy.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -27,39 +32,12 @@ APP="Immich Public Proxy" APP_TYPE="addon" INSTALL_PATH="/opt/immich-proxy" CONFIG_PATH="/opt/immich-proxy/app" +SERVICE_PATH="/etc/systemd/system/immich-proxy.service" DEFAULT_PORT=3000 # Initialize all core functions (colors, formatting, icons, $STD mode) load_functions - -# ============================================================================== -# HEADER -# ============================================================================== -function header_info { - clear - cat <<"EOF" - ____ _ __ ____ - / _/___ ___ ____ ___ (_)____/ /_ / __ \_________ _ ____ __ - / // __ `__ \/ __ `__ \/ / ___/ __ \______/ /_/ / ___/ __ \| |/_/ / / / - _/ // / / / / / / / / / / / /__/ / / /_____/ ____/ / / /_/ /> /dev/null || true msg_ok "Stopped service" - msg_info "Backing up configuration" - cp "$CONFIG_PATH"/.env /tmp/ipp.env.bak 2>/dev/null || true - cp "$CONFIG_PATH"/config.json /tmp/ipp.config.json.bak 2>/dev/null || true - msg_ok "Backed up configuration" + BACKUP_DIR="/opt/immich-public-proxy_backup" + create_backup "$CONFIG_PATH"/.env "$CONFIG_PATH"/config.json NODE_VERSION="24" setup_nodejs CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Immich Public Proxy" "alangrainger/immich-public-proxy" "tarball" "latest" "$INSTALL_PATH" - msg_info "Restoring configuration" - cp /tmp/ipp.env.bak "$CONFIG_PATH"/.env 2>/dev/null || true - cp /tmp/ipp.config.json.bak "$CONFIG_PATH"/config.json 2>/dev/null || true - rm -f /tmp/ipp.*.bak - msg_ok "Restored configuration" + restore_backup msg_info "Installing dependencies" cd "$CONFIG_PATH" diff --git a/tools/addon/jellystat.sh b/tools/addon/jellystat.sh index e9950b1565e..f9c97d75993 100644 --- a/tools/addon/jellystat.sh +++ b/tools/addon/jellystat.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -27,39 +32,12 @@ APP="Jellystat" APP_TYPE="addon" INSTALL_PATH="/opt/jellystat" CONFIG_PATH="/opt/jellystat/.env" +SERVICE_PATH="/etc/systemd/system/jellystat.service" DEFAULT_PORT=3000 # Initialize all core functions (colors, formatting, icons, STD mode) load_functions - -# ============================================================================== -# HEADER -# ============================================================================== -function header_info { - clear - cat <<"EOF" - __ ____ __ __ - / /__ / / /_ _______/ /_____ _/ /_ - __ / / _ \/ / / / / / ___/ __/ __ `/ __/ -/ /_/ / __/ / / /_/ (__ ) /_/ /_/ / /_ -\____/\___/_/_/\__, /____/\__/\__,_/\__/ - /____/ -EOF -} - -# ============================================================================== -# OS DETECTION -# ============================================================================== -if [[ -f "/etc/alpine-release" ]]; then - msg_error "Alpine is not supported for ${APP}. Use Debian/Ubuntu." - exit 238 -elif [[ -f "/etc/debian_version" ]]; then - OS="Debian" - SERVICE_PATH="/etc/systemd/system/jellystat.service" -else - echo -e "${CROSS} Unsupported OS detected. Exiting." - exit 238 -fi +require_debian_like # ============================================================================== # UNINSTALL @@ -102,16 +80,12 @@ function update() { systemctl stop jellystat.service &>/dev/null || true msg_ok "Stopped service" - msg_info "Backing up configuration" - cp "$CONFIG_PATH" /tmp/jellystat.env.bak 2>/dev/null || true - msg_ok "Backed up configuration" + BACKUP_DIR="/opt/jellystat_backup" + create_backup "$CONFIG_PATH" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "jellystat" "CyferShepard/Jellystat" "tarball" "latest" "$INSTALL_PATH" - msg_info "Restoring configuration" - cp /tmp/jellystat.env.bak "$CONFIG_PATH" 2>/dev/null || true - rm -f /tmp/jellystat.env.bak - msg_ok "Restored configuration" + restore_backup msg_info "Installing dependencies" cd "$INSTALL_PATH" diff --git a/tools/addon/komodo.sh b/tools/addon/komodo.sh index 9815cac525d..69765ddf6dc 100644 --- a/tools/addon/komodo.sh +++ b/tools/addon/komodo.sh @@ -6,8 +6,13 @@ # Source: https://komo.do/ | Github: https://github.com/moghtech/komodo if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 || apk update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 || apk add --no-cache curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -131,25 +136,7 @@ function update() { } # ============================================================================== -# PROXMOX HOST CHECK -# ============================================================================== -function check_proxmox_host() { - if command -v pveversion &>/dev/null; then - msg_error "Running on the Proxmox host is NOT recommended!" - msg_error "This should be executed inside an LXC container." - echo "" - echo -n "${TAB}Continue anyway? (y/N): " - read -r confirm - if [[ ! "${confirm,,}" =~ ^(y|yes)$ ]]; then - msg_warn "Aborted. Please run this inside an LXC container." - exit 0 - fi - msg_warn "Proceeding on Proxmox host at your own risk!" - fi -} - -# ============================================================================== -# CHECK / INSTALL DOCKER +# DEPENDENCIES # ============================================================================== function ensure_openssl() { if command -v openssl &>/dev/null; then @@ -163,53 +150,17 @@ function ensure_openssl() { $STD apt-get install -y openssl else msg_error "openssl is required but could not be installed automatically." - exit 10 + exit 237 fi msg_ok "Installed openssl" } -function check_or_install_docker() { - if command -v docker &>/dev/null; then - msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') is available" - if docker compose version &>/dev/null; then - msg_ok "Docker Compose is available" - else - msg_error "Docker Compose plugin is not available. Please install it." - exit 10 - fi - ensure_openssl - return - fi - - msg_warn "Docker is not installed." - echo -n "${TAB}Install Docker now? (y/N): " - read -r install_docker_prompt - if [[ ! "${install_docker_prompt,,}" =~ ^(y|yes)$ ]]; then - msg_error "Docker is required for ${APP}. Exiting." - exit 10 - fi - - msg_info "Installing Docker" - if [[ -f /etc/alpine-release ]]; then - $STD apk add docker docker-cli-compose - $STD rc-service docker start - $STD rc-update add docker default - else - DOCKER_CONFIG_PATH='/etc/docker/daemon.json' - mkdir -p "$(dirname "$DOCKER_CONFIG_PATH")" - echo -e '{\n "log-driver": "journald"\n}' >"$DOCKER_CONFIG_PATH" - $STD sh <(curl -fsSL https://get.docker.com) - fi - msg_ok "Installed Docker" - - ensure_openssl -} - # ============================================================================== # INSTALL # ============================================================================== function install() { - check_or_install_docker + ensure_docker + ensure_openssl echo -e "${TAB}Choose the database for Komodo:" echo -e "${TAB} 1) MongoDB (recommended)" @@ -292,7 +243,7 @@ if [[ "${type:-}" == "update" ]]; then fi header_info -check_proxmox_host +confirm_not_pve_host get_lxc_ip # Declare variables used by find_compose_file diff --git a/tools/addon/netdata.sh b/tools/addon/netdata.sh index 3570c230100..7e04ff0b918 100644 --- a/tools/addon/netdata.sh +++ b/tools/addon/netdata.sh @@ -5,74 +5,31 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://www.netdata.cloud/ | Github: https://github.com/netdata/netdata -function header_info { - clear - cat <<"EOF" - _ __ __ ____ __ - / | / /__ / /_/ __ \____ _/ /_____ _ - / |/ / _ \/ __/ / / / __ `/ __/ __ `/ - / /| / __/ /_/ /_/ / /_/ / /_/ /_/ / -/_/ |_/\___/\__/_____/\__,_/\__/\__,_/ +APP="Netdata" +APP_TYPE="addon" -EOF -} - -YW=$(echo "\033[33m") -BL=$(echo "\033[36m") -RD=$(echo "\033[01;31m") -GN=$(echo "\033[1;92m") -CL=$(echo "\033[m") -BFR="\\r\\033[K" -HOLD="-" -CM="${GN}✓${CL}" -silent() { "$@" >/dev/null 2>&1; } - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "netdata" "addon" -set -e -header_info -echo "Loading..." -function msg_info() { - local msg="$1" - echo -ne " ${HOLD} ${YW}${msg}..." -} +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR -function msg_ok() { - local msg="$1" - echo -e "${BFR} ${CM} ${GN}${msg}${CL}" -} - -function msg_error() { echo -e "${RD}✗ $1${CL}"; } - -# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported. -# Supported: Proxmox VE 8.0.x – 8.9.x and 9.0–9.x -pve_check() { - local PVE_VER - PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')" - - # Check for Proxmox VE 8.x: allow 8.0–8.9 - if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then - local MINOR="${BASH_REMATCH[1]}" - if ((MINOR < 0 || MINOR > 9)); then - msg_error "This version of Proxmox VE is not supported." - msg_error "Supported: Proxmox VE version 8.0 – 8.9" - exit 105 - fi - return 0 - fi - - # Check for Proxmox VE 9.x: allow 9.0–9.x - if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then - return 0 - fi - - # All other unsupported versions - msg_error "This version of Proxmox VE is not supported." - msg_error "Supported versions: Proxmox VE 8.0 – 8.9 or 9.0–9.x" - exit 105 -} +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions detect_codename() { source /etc/os-release @@ -83,7 +40,7 @@ detect_codename() { CODENAME="${VERSION_CODENAME:-}" if [[ -z "$CODENAME" ]]; then msg_error "Could not detect Debian codename." - exit 71 + exit 238 fi echo "$CODENAME" } @@ -97,9 +54,8 @@ get_latest_repo_pkg() { } install() { - header_info while true; do - read -p "Are you sure you want to install NetData on Proxmox VE host. Proceed(y/n)? " yn + read -r -p "Are you sure you want to install ${APP} on Proxmox VE host. Proceed(y/n)? " yn case $yn in [Yy]*) break ;; [Nn]*) exit ;; @@ -107,56 +63,51 @@ install() { esac done - read -r -p "Verbose mode? " prompt - [[ ${prompt,,} =~ ^(y|yes)$ ]] && STD="" || STD="silent" - CODENAME=$(detect_codename) REPO_URL="https://repo.netdata.cloud/repos/repoconfig/debian/${CODENAME}/" msg_info "Setting up repository" - $STD apt-get install -y debian-keyring + $STD apt install -y debian-keyring PKG=$(get_latest_repo_pkg "$REPO_URL") if [[ -z "$PKG" ]]; then msg_error "Could not find netdata-repo package for Debian $CODENAME" exit 237 fi - curl -fsSL "${REPO_URL}${PKG}" -o "$PKG" - $STD dpkg -i "$PKG" - rm -f "$PKG" + TMP_DEB=$(mktemp --suffix=.deb) + curl -fsSL "${REPO_URL}${PKG}" -o "$TMP_DEB" + $STD dpkg -i "$TMP_DEB" + rm -f "$TMP_DEB" msg_ok "Set up repository" - msg_info "Installing Netdata" - $STD apt-get update - $STD apt-get install -y netdata - msg_ok "Installed Netdata" + msg_info "Installing ${APP}" + $STD apt update + $STD apt install -y netdata + msg_ok "Installed ${APP}" msg_ok "Completed successfully!\n" - echo -e "\n Netdata should be reachable at${BL} http://$(hostname -I | awk '{print $1}'):19999 ${CL}\n" + get_lxc_ip + echo -e "\n${APP} should be reachable at${BL} http://${LOCAL_IP}:19999 ${CL}\n" } uninstall() { - header_info - read -r -p "Verbose mode? " prompt - [[ ${prompt,,} =~ ^(y|yes)$ ]] && STD="" || STD="silent" - - msg_info "Uninstalling Netdata" + msg_info "Uninstalling ${APP}" systemctl stop netdata || true rm -rf /var/log/netdata /var/lib/netdata /var/cache/netdata /etc/netdata/go.d rm -rf /etc/apt/trusted.gpg.d/netdata-archive-keyring.gpg /etc/apt/sources.list.d/netdata.list - $STD apt-get remove --purge -y netdata netdata-repo + $STD apt remove --purge -y netdata netdata-repo systemctl daemon-reload $STD apt autoremove -y $STD userdel netdata || true - msg_ok "Uninstalled Netdata" + msg_ok "Uninstalled ${APP}" msg_ok "Completed successfully!\n" } header_info -pve_check +require_pve_host -OPTIONS=(Install "Install NetData on Proxmox VE" - Uninstall "Uninstall NetData from Proxmox VE") +OPTIONS=(Install "Install ${APP} on Proxmox VE" + Uninstall "Uninstall ${APP} from Proxmox VE") -CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "NetData" \ +CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "${APP}" \ --menu "Select an option:" 10 58 2 "${OPTIONS[@]}" 3>&1 1>&2 2>&3) case $CHOICE in diff --git a/tools/addon/nextcloud-exporter.sh b/tools/addon/nextcloud-exporter.sh index d76dc009905..b3617122e07 100644 --- a/tools/addon/nextcloud-exporter.sh +++ b/tools/addon/nextcloud-exporter.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -20,6 +25,7 @@ declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "nextcloud-exp set -Eeuo pipefail trap 'error_handler' ERR load_functions +require_debian_like # ============================================================================== # CONFIGURATION @@ -31,14 +37,6 @@ BINARY_PATH="/usr/bin/nextcloud-exporter" CONFIG_PATH="/etc/nextcloud-exporter.env" SERVICE_PATH="/etc/systemd/system/nextcloud-exporter.service" -# ============================================================================== -# OS DETECTION -# ============================================================================== -if ! grep -qE 'ID=debian|ID=ubuntu' /etc/os-release 2>/dev/null; then - echo -e "${CROSS} Unsupported OS detected. This script only supports Debian and Ubuntu." - exit 238 -fi - # ============================================================================== # UNINSTALL # ============================================================================== diff --git a/tools/addon/olivetin.sh b/tools/addon/olivetin.sh index afe6d811c7e..86f182f5837 100644 --- a/tools/addon/olivetin.sh +++ b/tools/addon/olivetin.sh @@ -5,67 +5,131 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://docs.olivetin.app/ | Github: https://github.com/OliveTin/OliveTin -function header_info { - clear - cat <<"EOF" - ____ ___ _______ - / __ \/ (_) _____/_ __(_)___ - / / / / / / | / / _ \/ / / / __ \ -/ /_/ / / /| |/ / __/ / / / / / / -\____/_/_/ |___/\___/_/ /_/_/ /_/ - -EOF -} - -IP=$(hostname -I | awk '{print $1}') -YW=$(echo "\033[33m") -BL=$(echo "\033[36m") -GN=$(echo "\033[1;92m") -CL=$(echo "\033[m") -BFR="\\r\\033[K" -HOLD="-" -CM="${GN}✓${CL}" APP="OliveTin" -hostname="$(hostname)" +APP_TYPE="addon" -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "olivetin" "addon" -set-e +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions +require_debian_like + header_info +ensure_usr_local_bin_persist +get_lxc_ip +IP="$LOCAL_IP" + +# ============================================================================== +# UNINSTALL +# ============================================================================== +function uninstall() { + msg_info "Uninstalling ${APP}" + systemctl disable --now OliveTin &>/dev/null || true + $STD apt remove -y olivetin + rm -f "$HOME/.olivetin" + msg_ok "${APP} has been uninstalled" +} + +# ============================================================================== +# UPDATE +# ============================================================================== +function update() { + if check_for_gh_release "olivetin" "OliveTin/OliveTin"; then + msg_info "Updating ${APP}" + fetch_and_deploy_gh_release "olivetin" "OliveTin/OliveTin" "binary" + systemctl restart OliveTin + msg_ok "Updated successfully!" + exit + fi +} + +# ============================================================================== +# INSTALL +# ============================================================================== +function install() { + msg_info "Installing ${APP}" + fetch_and_deploy_gh_release "olivetin" "OliveTin/OliveTin" "binary" + systemctl enable --now OliveTin &>/dev/null + msg_ok "Installed ${APP}" + + msg_info "Creating update script" + ensure_usr_local_bin_persist + cat <<'EOF' >/usr/local/bin/update_olivetin +#!/usr/bin/env bash +# OliveTin Update Script +type=update bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/olivetin.sh)" +EOF + chmod +x /usr/local/bin/update_olivetin + msg_ok "Created update script (/usr/local/bin/update_olivetin)" + + msg_ok "Completed successfully!\n" + echo -e "${APP} should be reachable by going to the following URL. + ${BL}http://${IP}:1337${CL} \n" +} + +# ============================================================================== +# MAIN +# ============================================================================== + +# Handle type=update (called from update script) +if [[ "${type:-}" == "update" ]]; then + if command -v olivetin &>/dev/null; then + update + else + msg_error "${APP} is not installed. Nothing to update." + exit 233 + fi + exit 0 +fi + +if [[ -d "$HOME" && -f "$HOME/.olivetin" ]] || command -v olivetin &>/dev/null; then + msg_warn "${APP} is already installed." + echo -n "${TAB}Uninstall ${APP}? (y/N): " + read -r uninstall_prompt + if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then + uninstall + exit 0 + fi + + echo -n "${TAB}Update ${APP}? (y/N): " + read -r update_prompt + if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then + update + exit 0 + fi + + msg_warn "No action selected. Exiting." + exit 0 +fi while true; do - read -p "This will Install ${APP} on $hostname. Proceed(y/n)?" yn + echo -n "${TAB}This will Install ${APP}. Proceed (y/n)? " + read -r yn case $yn in [Yy]*) break ;; [Nn]*) exit ;; *) echo "Please answer yes or no." ;; esac done +unset _HEADER_SHOWN header_info -function msg_info() { - local msg="$1" - echo -ne " ${HOLD} ${YW}${msg}..." -} - -function msg_ok() { - local msg="$1" - echo -e "${BFR} ${CM} ${GN}${msg}${CL}" -} - -msg_info "Installing ${APP}" -if ! command -v curl &>/dev/null; then - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 -fi -curl -fsSL "https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin_linux_amd64.deb" -o $(basename "https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin_linux_amd64.deb") -dpkg -i OliveTin_linux_amd64.deb &>/dev/null -systemctl enable --now OliveTin &>/dev/null -rm OliveTin_linux_amd64.deb -msg_ok "Installed ${APP} on $hostname" - -msg_ok "Completed successfully!\n" -echo -e "${APP} should be reachable by going to the following URL. - ${BL}http://$IP:1337${CL} \n" +install diff --git a/tools/addon/phpmyadmin.sh b/tools/addon/phpmyadmin.sh index 8f59efaf956..dfcb2cd2269 100644 --- a/tools/addon/phpmyadmin.sh +++ b/tools/addon/phpmyadmin.sh @@ -5,39 +5,36 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://www.phpmyadmin.net/ | Github: https://github.com/phpmyadmin/phpmyadmin -function header_info { - clear - cat <<"EOF" - ____ __ __ ___ ___ __ _ - / __ \/ /_ ____ / |/ /_ __/ | ____/ /___ ___ (_)___ - / /_/ / __ \/ __ \/ /|_/ / / / / /| |/ __ / __ `__ \/ / __ \ - / ____/ / / / /_/ / / / / /_/ / ___ / /_/ / / / / / / / / / / -/_/ /_/ /_/ .___/_/ /_/\__, /_/ |_\__,_/_/ /_/ /_/_/_/ /_/ - /_/ /____/ -EOF -} - -YW=$(echo "\033[33m") -GN=$(echo "\033[1;92m") -RD=$(echo "\033[01;31m") -BL=$(echo "\033[36m") -CL=$(echo "\033[m") -CM="${GN}✔️${CL}" -CROSS="${RD}✖️${CL}" -INFO="${BL}ℹ️${CL}" - APP="phpMyAdmin" +APP_TYPE="addon" INSTALL_DIR_DEBIAN="/var/www/html/phpMyAdmin" INSTALL_DIR_ALPINE="/usr/share/phpmyadmin" -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "phpmyadmin" "addon" -IFACE=$(ip -4 route | awk '/default/ {print $5; exit}') -IP=$(ip -4 addr show "$IFACE" | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1) -[[ -z "$IP" ]] && IP=$(hostname -I | awk '{print $1}') -[[ -z "$IP" ]] && IP="127.0.0.1" +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions + +get_lxc_ip +IP="$LOCAL_IP" # Detect OS if [[ -f "/etc/alpine-release" ]]; then @@ -47,24 +44,20 @@ if [[ -f "/etc/alpine-release" ]]; then INSTALL_DIR="$INSTALL_DIR_ALPINE" elif [[ -f "/etc/debian_version" ]]; then OS="Debian" - PKG_MANAGER_INSTALL="apt-get install -y" + PKG_MANAGER_INSTALL="apt install -y" PKG_QUERY="dpkg -l" INSTALL_DIR="$INSTALL_DIR_DEBIAN" else - echo -e "${CROSS} Unsupported OS detected. Exiting." + msg_error "Unsupported OS detected. Exiting." exit 238 fi header_info -function msg_info() { echo -e "${INFO} ${YW}${1}...${CL}"; } -function msg_ok() { echo -e "${CM} ${GN}${1}${CL}"; } -function msg_error() { echo -e "${CROSS} ${RD}${1}${CL}"; } - function check_internet() { if ! command -v curl &>/dev/null; then - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + $STD apt update + $STD apt install -y curl fi msg_info "Checking Internet connectivity to GitHub" HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://github.com) @@ -103,7 +96,7 @@ function install_php_and_modules() { done if [[ ${#MISSING_PACKAGES[@]} -gt 0 ]]; then msg_info "Installing missing PHP packages: ${MISSING_PACKAGES[*]}" - if ! apt-get update &>/dev/null || ! apt-get install -y "${MISSING_PACKAGES[@]}" &>/dev/null; then + if ! $STD apt update || ! $STD apt install -y "${MISSING_PACKAGES[@]}"; then msg_error "Failed to install required PHP modules. Exiting." exit 237 fi @@ -113,30 +106,41 @@ function install_php_and_modules() { fi else msg_info "Installing Lighttpd and PHP for Alpine" - $PKG_MANAGER_INSTALL lighttpd php php-fpm php-session php-json php-mysqli curl tar openssl &>/dev/null + $STD $PKG_MANAGER_INSTALL \ + lighttpd \ + php \ + php-fpm \ + php-session \ + php-json \ + php-mysqli \ + curl \ + tar \ + openssl msg_ok "Installed Lighttpd and PHP" fi } function install_phpmyadmin() { msg_info "Fetching latest phpMyAdmin release from GitHub" - LATEST_VERSION_RAW=$(curl -s https://api.github.com/repos/phpmyadmin/phpmyadmin/releases/latest | grep tag_name | cut -d '"' -f4) + LATEST_VERSION_RAW=$(get_latest_github_release "phpmyadmin/phpmyadmin" false) || true LATEST_VERSION=$(echo "$LATEST_VERSION_RAW" | sed -e 's/^RELEASE_//' -e 's/_/./g') if [[ -z "$LATEST_VERSION" ]]; then - msg_error "Could not determine latest phpMyAdmin version from GitHub – falling back to 5.2.2" - LATEST_VERSION="RELEASE_5_2_2" + msg_error "Could not determine latest phpMyAdmin version from GitHub – falling back to 5.2.2" + LATEST_VERSION="5.2.2" fi msg_ok "Latest version: $LATEST_VERSION" TARBALL_URL="https://files.phpmyadmin.net/phpMyAdmin/${LATEST_VERSION}/phpMyAdmin-${LATEST_VERSION}-all-languages.tar.gz" msg_info "Downloading ${TARBALL_URL}" - if ! curl -fsSL "$TARBALL_URL" -o /tmp/phpmyadmin.tar.gz; then + tarball=$(mktemp) + if ! curl -fsSL "$TARBALL_URL" -o "$tarball"; then msg_error "Download failed: $TARBALL_URL" exit 115 fi mkdir -p "$INSTALL_DIR" - tar xf /tmp/phpmyadmin.tar.gz --strip-components=1 -C "$INSTALL_DIR" + tar xf "$tarball" --strip-components=1 -C "$INSTALL_DIR" + rm -f "$tarball" } function configure_phpmyadmin() { @@ -223,47 +227,43 @@ function uninstall_phpmyadmin() { function update_phpmyadmin() { msg_info "Fetching latest phpMyAdmin release from GitHub" - LATEST_VERSION_RAW=$(curl -s https://api.github.com/repos/phpmyadmin/phpmyadmin/releases/latest | grep tag_name | cut -d '"' -f4) + LATEST_VERSION_RAW=$(get_latest_github_release "phpmyadmin/phpmyadmin" false) || true LATEST_VERSION=$(echo "$LATEST_VERSION_RAW" | sed -e 's/^RELEASE_//' -e 's/_/./g') if [[ -z "$LATEST_VERSION" ]]; then - msg_error "Could not determine latest phpMyAdmin version from GitHub – falling back to 5.2.2" + msg_error "Could not determine latest phpMyAdmin version from GitHub – falling back to 5.2.2" LATEST_VERSION="5.2.2" fi msg_ok "Latest version: $LATEST_VERSION" TARBALL_URL="https://files.phpmyadmin.net/phpMyAdmin/${LATEST_VERSION}/phpMyAdmin-${LATEST_VERSION}-all-languages.tar.gz" msg_info "Downloading ${TARBALL_URL}" + tarball=$(mktemp) - if ! curl -fsSL "$TARBALL_URL" -o /tmp/phpmyadmin.tar.gz; then + if ! curl -fsSL "$TARBALL_URL" -o "$tarball"; then msg_error "Download failed: $TARBALL_URL" exit 115 fi - BACKUP_DIR="/tmp/phpmyadmin-backup-$(date +%Y%m%d-%H%M%S)" - mkdir -p "$BACKUP_DIR" - BACKUP_ITEMS=("config.inc.php" "upload" "save" "tmp" "themes") + BACKUP_DIR="/opt/phpmyadmin_backup" + create_backup \ + "$INSTALL_DIR/config.inc.php" \ + "$INSTALL_DIR/upload" \ + "$INSTALL_DIR/save" \ + "$INSTALL_DIR/tmp" \ + "$INSTALL_DIR/themes" - msg_info "Backing up existing phpMyAdmin data" - for item in "${BACKUP_ITEMS[@]}"; do - [[ -e "$INSTALL_DIR/$item" ]] && cp -a "$INSTALL_DIR/$item" "$BACKUP_DIR/" && echo " ↪︎ $item" - done - msg_ok "Backup completed: $BACKUP_DIR" - - tar xf /tmp/phpmyadmin.tar.gz --strip-components=1 -C "$INSTALL_DIR" + tar xf "$tarball" --strip-components=1 -C "$INSTALL_DIR" + rm -f "$tarball" msg_ok "Extracted phpMyAdmin $LATEST_VERSION" - msg_info "Restoring preserved files" - for item in "${BACKUP_ITEMS[@]}"; do - [[ -e "$BACKUP_DIR/$item" ]] && cp -a "$BACKUP_DIR/$item" "$INSTALL_DIR/" && echo " ↪︎ $item restored" - done - msg_ok "Restoration completed" + restore_backup configure_phpmyadmin } if is_phpmyadmin_installed; then - echo -e "${YW}⚠️ ${APP} is already installed at ${INSTALL_DIR}.${CL}" + msg_warn "${APP} is already installed at ${INSTALL_DIR}." read -r -p "Would you like to Update (1), Uninstall (2) or Cancel (3)? [1/2/3]: " action action="${action//[[:space:]]/}" case "$action" in @@ -275,11 +275,11 @@ if is_phpmyadmin_installed; then uninstall_phpmyadmin ;; 3) - echo -e "${YW}⚠️ Action cancelled. Exiting.${CL}" + msg_warn "Action cancelled. Exiting." exit 0 ;; *) - echo -e "${YW}⚠️ Invalid input. Exiting.${CL}" + msg_warn "Invalid input. Exiting." exit 112 ;; esac @@ -292,12 +292,12 @@ else install_phpmyadmin configure_phpmyadmin if [[ "$OS" == "Debian" ]]; then - echo -e "${CM} ${GN}${APP} is reachable at: ${BL}http://${IP}/phpMyAdmin${CL}" + msg_ok "${APP} is reachable at: ${BL}http://${IP}/phpMyAdmin${CL}" else - echo -e "${CM} ${GN}${APP} is reachable at: ${BL}http://${IP}/${CL}" + msg_ok "${APP} is reachable at: ${BL}http://${IP}/${CL}" fi else - echo -e "${YW}⚠️ Installation skipped. Exiting.${CL}" + msg_warn "Installation skipped. Exiting." exit 0 fi fi diff --git a/tools/addon/pihole-exporter.sh b/tools/addon/pihole-exporter.sh index 0cba93a30c3..4fbef1d94f8 100644 --- a/tools/addon/pihole-exporter.sh +++ b/tools/addon/pihole-exporter.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) diff --git a/tools/addon/prometheus-paperless-ngx-exporter.sh b/tools/addon/prometheus-paperless-ngx-exporter.sh index e5bc64775ca..b77a7a73ad8 100644 --- a/tools/addon/prometheus-paperless-ngx-exporter.sh +++ b/tools/addon/prometheus-paperless-ngx-exporter.sh @@ -5,6 +5,16 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://github.com/hansmi/prometheus-paperless-exporter +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) @@ -15,6 +25,7 @@ declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "prometheus-pa set -Eeuo pipefail trap 'error_handler' ERR load_functions +require_debian_like # ============================================================================== # CONFIGURATION @@ -27,14 +38,6 @@ CONFIG_PATH="/etc/prometheus-paperless-ngx-exporter/config.env" SERVICE_PATH="/etc/systemd/system/prometheus-paperless-ngx-exporter.service" AUTH_TOKEN_FILE="/etc/prometheus-paperless-ngx-exporter/paperless_auth_token_file" -# ============================================================================== -# OS DETECTION -# ============================================================================== -if ! grep -qE 'ID=debian|ID=ubuntu' /etc/os-release 2>/dev/null; then - echo -e "${CROSS} Unsupported OS detected. This script only supports Debian and Ubuntu." - exit 238 -fi - # ============================================================================== # UNINSTALL # ============================================================================== diff --git a/tools/addon/pyenv.sh b/tools/addon/pyenv.sh index 71e37398b87..51e32eedf16 100644 --- a/tools/addon/pyenv.sh +++ b/tools/addon/pyenv.sh @@ -5,77 +5,123 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://pyenv.run/ | Github: https://github.com/pyenv/pyenv -set -e -YW=$(echo "\033[33m") -RD=$(echo "\033[01;31m") -BL=$(echo "\033[36m") -GN=$(echo "\033[1;92m") -CL=$(echo "\033[m") -CM="${GN}✓${CL}" -CROSS="${RD}✗${CL}" -BFR="\\r\\033[K" -HOLD="-" -function msg_info() { - local msg="$1" - echo -ne " ${HOLD} ${YW}${msg}..." -} +APP="pyenv" +APP_TYPE="addon" -function msg_ok() { - local msg="$1" - echo -e "${BFR} ${CM} ${GN}${msg}${CL}" -} -function msg_error() { - local msg="$1" - echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}" -} - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "pyenv" "addon" -if command -v pveversion >/dev/null 2>&1; then - msg_error "Can't Install on Proxmox " - exit -fi -msg_info "Installing pyenv" -apt-get install -y \ - make \ - build-essential \ - libjpeg-dev \ - libpcap-dev \ - libssl-dev \ - zlib1g-dev \ - libbz2-dev \ - libreadline-dev \ - libsqlite3-dev \ - autoconf \ - git \ - curl \ - sudo \ - llvm \ - libncursesw5-dev \ - xz-utils \ - tk-dev \ - libxml2-dev \ - libxmlsec1-dev \ - libffi-dev \ - libopenjp2-7 \ - libtiff5 \ - libturbojpeg0-dev \ - liblzma-dev &>/dev/null +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR -git clone https://github.com/pyenv/pyenv.git ~/.pyenv &>/dev/null -set +e -echo 'export PYENV_ROOT="$HOME/.pyenv"' >>~/.bashrc -echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >>~/.bashrc -echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init --path)"\nfi' >>~/.bashrc -msg_ok "Installed pyenv" -. ~/.bashrc -set -e -msg_info "Installing Python 3.11.1" -pyenv install 3.11.1 &>/dev/null -pyenv global 3.11.1 -msg_ok "Installed Python 3.11.1" +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions +require_debian_like + +header_info +confirm_not_pve_host +get_lxc_ip +export PYENV_ROOT="${HOME}/.pyenv" + +msg_info "Installing dependencies" +$STD apt update + +# Official Python build dependencies for Debian/Ubuntu +# https://github.com/pyenv/pyenv/wiki#suggested-build-environment +PYENV_DEPS=( + build-essential + libssl-dev + zlib1g-dev + libbz2-dev + libreadline-dev + libsqlite3-dev + curl + git + xz-utils + tk-dev + libxml2-dev + libxmlsec1-dev + libffi-dev + liblzma-dev +) + +# Extras for the optional Home Assistant / ESPHome installs below (Pillow et al.) +PYENV_DEPS+=(make llvm libjpeg-dev libpcap-dev libopenjp2-7) + +# These were renamed between releases (libtiff5 is gone on Debian 13 / Ubuntu 24.04), +# so take whichever variant the distro actually ships +for candidates in "libncurses-dev libncursesw5-dev" "libtiff-dev libtiff5-dev" "libturbojpeg0-dev libturbojpeg-dev"; do + for pkg in $candidates; do + if apt-cache show "$pkg" &>/dev/null; then + PYENV_DEPS+=("$pkg") + break + fi + done +done + +install_packages_with_retry "${PYENV_DEPS[@]}" +msg_ok "Installed dependencies" + +# The upstream installer refuses to run when PYENV_ROOT already exists +if [[ -d "$PYENV_ROOT" ]]; then + msg_ok "${APP} is already installed at ${PYENV_ROOT}" +else + msg_info "Installing ${APP}" + # Official installer - also sets up the pyenv-doctor/update/virtualenv plugins + $STD bash <(curl -fsSL https://pyenv.run) + msg_ok "Installed ${APP}" +fi + +# Shell setup per upstream docs. On Debian-based systems ~/.profile prepends the +# per-user bin dirs *after* sourcing ~/.bashrc, so both files need the init call. +msg_info "Configuring shell environment" +for rc in "${HOME}/.bashrc" "${HOME}/.profile"; do + [[ -f "$rc" ]] || touch "$rc" + if ! grep -q 'PYENV_ROOT' "$rc"; then + cat >>"$rc" <<'EOF' + +# pyenv +export PYENV_ROOT="$HOME/.pyenv" +[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH" +eval "$(pyenv init - bash)" +EOF + fi +done +msg_ok "Configured shell environment" + +# Activate pyenv for the remainder of this script +export PATH="${PYENV_ROOT}/bin:$PATH" +set +Eeuo pipefail +eval "$(pyenv init - bash)" +set -Eeuo pipefail + +# pyenv resolves a version prefix to the latest release in that line, so pinning +# a patch level (the old 3.11.1) is neither needed nor portable across distros. +# +# 3.14 is the only series all three optional payloads below agree on: +# Home Assistant Core >= 3.14.2 +# ESPHome >= 3.12.0, < 3.15 +# python-matter-server >= 3.12 +# (3.11 has been security-fix-only since 2024 and is EOL in 10/2027.) +PYTHON_SERIES="3.14" +msg_info "Installing Python ${PYTHON_SERIES} (latest patch release)" +$STD pyenv install -s "$PYTHON_SERIES" +pyenv global "$PYTHON_SERIES" +msg_ok "Installed Python $(pyenv version-name)" read -r -p "Would you like to install Home Assistant Beta? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Home Assistant Beta" @@ -95,13 +141,13 @@ EOF cd /srv/homeassistant python3 -m venv . source bin/activate - python3 -m pip install wheel &>/dev/null - pip3 install --upgrade pip &>/dev/null - pip3 install psycopg2-binary &>/dev/null - pip3 install --pre homeassistant &>/dev/null + $STD python3 -m pip install wheel + $STD pip3 install --upgrade pip + $STD pip3 install psycopg2-binary + $STD pip3 install --pre homeassistant systemctl enable homeassistant &>/dev/null msg_ok "Installed Home Assistant Beta" - echo -e " Go to $(hostname -I | awk '{print $1}'):8123" + echo -e " Go to ${LOCAL_IP}:8123" hass fi @@ -112,9 +158,9 @@ if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then cd /srv/esphome python3 -m venv . source bin/activate - python3 -m pip install wheel &>/dev/null - pip3 install --upgrade pip &>/dev/null - pip3 install --pre esphome &>/dev/null + $STD python3 -m pip install wheel + $STD pip3 install --upgrade pip + $STD pip3 install --pre esphome cat </srv/esphome/start.sh #!/usr/bin/env bash @@ -143,25 +189,26 @@ WantedBy=multi-user.target EOF systemctl enable --now esphomedashboard &>/dev/null msg_ok "Installed ESPHome Beta" - echo -e " Go to $(hostname -I | awk '{print $1}'):6052" + echo -e " Go to ${LOCAL_IP}:6052" exec $SHELL fi read -r -p "Would you like to install Matter-Server (Beta)? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Matter Server" - apt-get install -y \ + $STD apt install -y \ libcairo2-dev \ libjpeg62-turbo-dev \ libgirepository1.0-dev \ libpango1.0-dev \ libgif-dev \ - g++ &>/dev/null - python3 -m pip install wheel - pip3 install --upgrade pip - pip install python-matter-server[server] + g++ + $STD python3 -m pip install wheel + $STD pip3 install --upgrade pip + $STD pip install python-matter-server[server] msg_ok "Installed Matter Server" echo -e "Start server > python -m matter_server.server" fi msg_ok "\nFinished\n" exec $SHELL + diff --git a/tools/addon/qbittorrent-exporter.sh b/tools/addon/qbittorrent-exporter.sh index e7a7b1f805f..17af8ce0898 100644 --- a/tools/addon/qbittorrent-exporter.sh +++ b/tools/addon/qbittorrent-exporter.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) diff --git a/tools/addon/runtipi.sh b/tools/addon/runtipi.sh index d4ba9bddbcd..0f291f13ce0 100644 --- a/tools/addon/runtipi.sh +++ b/tools/addon/runtipi.sh @@ -35,55 +35,6 @@ DEFAULT_PORT=80 # Initialize all core functions (colors, formatting, icons, STD mode) load_functions -# ============================================================================== -# PROXMOX HOST CHECK -# ============================================================================== -function check_proxmox_host() { - if command -v pveversion &>/dev/null; then - msg_error "Running on the Proxmox host is NOT recommended!" - msg_error "This should be executed inside an LXC container." - echo "" - echo -n "${TAB}Continue anyway? (y/N): " - read -r confirm - if [[ ! "${confirm,,}" =~ ^(y|yes)$ ]]; then - msg_warn "Aborted. Please run this inside an LXC container." - exit 0 - fi - msg_warn "Proceeding on Proxmox host at your own risk!" - fi -} - -# ============================================================================== -# CHECK / INSTALL DOCKER -# ============================================================================== -function check_or_install_docker() { - if command -v docker &>/dev/null; then - msg_ok "Docker $(docker --version | cut -d' ' -f3 | tr -d ',') is available" - if docker compose version &>/dev/null; then - msg_ok "Docker Compose is available" - else - msg_error "Docker Compose plugin is not available. Please install it." - exit 10 - fi - return - fi - - msg_warn "Docker is not installed." - echo -n "${TAB}Install Docker now? (y/N): " - read -r install_docker_prompt - if [[ ! "${install_docker_prompt,,}" =~ ^(y|yes)$ ]]; then - msg_error "Docker is required for ${APP}. Exiting." - exit 10 - fi - - msg_info "Installing Docker" - DOCKER_CONFIG_PATH='/etc/docker/daemon.json' - mkdir -p "$(dirname "$DOCKER_CONFIG_PATH")" - echo -e '{\n "log-driver": "journald"\n}' >"$DOCKER_CONFIG_PATH" - $STD sh <(curl -fsSL https://get.docker.com) - msg_ok "Installed Docker" -} - # ============================================================================== # UNINSTALL # ============================================================================== @@ -124,7 +75,7 @@ function update() { # INSTALL # ============================================================================== function install() { - check_or_install_docker + ensure_docker msg_info "Installing dependencies" $STD apt-get update @@ -174,13 +125,9 @@ if [[ "${type:-}" == "update" ]]; then exit 0 fi -if [[ -f /etc/alpine-release ]]; then - msg_error "${APP} does not support Alpine Linux. Please use a Debian or Ubuntu based LXC." - exit 238 -fi - header_info -check_proxmox_host +require_debian_like +confirm_not_pve_host get_lxc_ip # Check if already installed diff --git a/tools/addon/sparkyfitness-garmin.sh b/tools/addon/sparkyfitness-garmin.sh index d62f4b4a44d..6fc4a432221 100644 --- a/tools/addon/sparkyfitness-garmin.sh +++ b/tools/addon/sparkyfitness-garmin.sh @@ -7,8 +7,13 @@ if ! command -v curl &>/dev/null; then printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 - apt-get update >/dev/null 2>&1 - apt-get install -y curl >/dev/null 2>&1 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi fi source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) @@ -20,6 +25,7 @@ declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "sparkyfitness set -Eeuo pipefail trap 'error_handler' ERR load_functions +require_debian_like # ============================================================================== # CONFIGURATION @@ -31,14 +37,6 @@ CONFIG_PATH="/etc/sparkyfitness-garmin/.env" SERVICE_PATH="/etc/systemd/system/sparkyfitness-garmin.service" DEFAULT_PORT=8000 -# ============================================================================== -# OS DETECTION -# ============================================================================== -if ! grep -qE 'ID=debian|ID=ubuntu' /etc/os-release 2>/dev/null; then - echo -e "${CROSS} Unsupported OS detected. This script only supports Debian and Ubuntu." - exit 238 -fi - # ============================================================================== # SparkyFitness LXC DETECTION # ============================================================================== diff --git a/tools/addon/webmin.sh b/tools/addon/webmin.sh index df07d646677..376969e3d61 100644 --- a/tools/addon/webmin.sh +++ b/tools/addon/webmin.sh @@ -5,61 +5,53 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://www.webmin.com/ | Github: https://github.com/webmin/webmin -function header_info { - clear - cat <<"EOF" - _ __ __ _ - | | /| / /__ / / __ _ (_)__ - | |/ |/ / -_) _ \/ ' \/ / _ \ - |__/|__/\__/_.__/_/_/_/_/_//_/ +APP="Webmin" +APP_TYPE="addon" -EOF -} -set -eEuo pipefail -YW=$(echo "\033[33m") -BL=$(echo "\033[36m") -BGN=$(echo "\033[4;92m") -GN=$(echo "\033[1;92m") -DGN=$(echo "\033[32m") -CL=$(echo "\033[m") -CM="${GN}✓${CL}" -BFR="\\r\\033[K" -HOLD="-" - -msg_info() { - local msg="$1" - echo -ne " ${HOLD} ${YW}${msg}..." -} - -msg_ok() { - local msg="$1" - echo -e "${BFR} ${CM} ${GN}${msg}${CL}" -} - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + if [[ -f /etc/alpine-release ]]; then + apk update >/dev/null 2>&1 + apk add --no-cache curl >/dev/null 2>&1 + else + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 + fi +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "webmin" "addon" +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR + +# Initialize all core functions (colors, formatting, icons, STD mode) +load_functions +require_debian_like + header_info -whiptail --backtitle "Proxmox VE Helper Scripts" --title "Webmin Installer" --yesno "This Will Install Webmin on this LXC Container. Proceed?" 10 58 +whiptail --backtitle "Proxmox VE Helper Scripts" --title "${APP} Installer" --yesno "This Will Install ${APP} on this LXC Container. Proceed?" 10 58 msg_info "Installing Prerequisites" -apt update &>/dev/null -apt-get -y install libnet-ssleay-perl libauthen-pam-perl libio-pty-perl unzip shared-mime-info curl &>/dev/null +$STD apt update +$STD apt install -y \ + libnet-ssleay-perl \ + libauthen-pam-perl \ + libio-pty-perl \ + unzip \ + shared-mime-info \ + curl msg_ok "Installed Prerequisites" -LATEST=$(curl -fsSL https://api.github.com/repos/webmin/webmin/releases/latest | grep '"tag_name":' | cut -d'"' -f4) - -msg_info "Downloading Webmin" -curl -fsSL "https://github.com/webmin/webmin/releases/download/$LATEST/webmin_${LATEST}_all.deb" -o $(basename "https://github.com/webmin/webmin/releases/download/$LATEST/webmin_${LATEST}_all.deb") -msg_ok "Downloaded Webmin" - -msg_info "Installing Webmin" -dpkg -i webmin_${LATEST}_all.deb &>/dev/null +msg_info "Installing ${APP}" +fetch_and_deploy_gh_release "webmin" "webmin/webmin" "binary" "latest" "/opt/webmin" "webmin_*_all.deb" /usr/share/webmin/changepass.pl /etc/webmin root root &>/dev/null -rm -rf /root/webmin_${LATEST}_all.deb -msg_ok "Installed Webmin" +msg_ok "Installed ${APP}" + +get_lxc_ip +echo -e "Successfully Installed!! ${APP} should be reachable by going to ${BL}https://${LOCAL_IP}:10000${CL}" -IP=$(hostname -I | cut -f1 -d ' ') -echo -e "Successfully Installed!! Webmin should be reachable by going to ${BL}https://${IP}:10000${CL}"