413 lines
13 KiB
Bash
413 lines
13 KiB
Bash
#!/bin/bash
|
|
#
|
|
# Zabbix Agent 2 Deployment Script - Linux ARM (aarch64 / armhf)
|
|
# Installs and configures Zabbix Agent 2 with PSK auto-registration
|
|
# Target server: zabbix.snarfnet.net
|
|
#
|
|
# Usage: sudo bash deploy_zabbix_agent_linux_arm.sh [psk_key]
|
|
# psk_key - (optional) 128-char hex PSK. If omitted, one is generated.
|
|
#
|
|
set -euo pipefail
|
|
|
|
ZABBIX_SERVER="zabbix.snarfnet.net"
|
|
ZABBIX_VERSION="7.0.27"
|
|
PSK_IDENTITY="PSK_autoregister"
|
|
PSK_FILE="/etc/zabbix/zabbix_agent2.psk"
|
|
AGENT_CONF="/etc/zabbix/zabbix_agent2.conf"
|
|
HOST_METADATA="Linux"
|
|
INSTALL_DIR="/opt/zabbix-agent2"
|
|
|
|
# --- Functions ---
|
|
|
|
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
|
|
|
|
detect_arch() {
|
|
ARCH=$(uname -m)
|
|
case "${ARCH}" in
|
|
aarch64|arm64)
|
|
ARCH_LABEL="aarch64"
|
|
TARBALL_ARCH="linux_arm64"
|
|
;;
|
|
armv7l|armhf)
|
|
ARCH_LABEL="armhf"
|
|
TARBALL_ARCH="linux_arm"
|
|
;;
|
|
armv6l)
|
|
ARCH_LABEL="armv6"
|
|
TARBALL_ARCH="linux_arm"
|
|
;;
|
|
*)
|
|
log "ERROR: Unsupported architecture '${ARCH}'."
|
|
log " Use deploy_zabbix_agent_linux.sh for x86_64 systems."
|
|
exit 1
|
|
;;
|
|
esac
|
|
log "Detected architecture: ${ARCH} (${ARCH_LABEL})"
|
|
}
|
|
|
|
detect_os() {
|
|
if [ -f /etc/os-release ]; then
|
|
. /etc/os-release
|
|
OS_ID="${ID}"
|
|
OS_VERSION="${VERSION_ID%%.*}"
|
|
else
|
|
OS_ID="unknown"
|
|
OS_VERSION="0"
|
|
fi
|
|
}
|
|
|
|
install_agent_package_manager() {
|
|
detect_os
|
|
case "${OS_ID}" in
|
|
debian|ubuntu|raspbian)
|
|
log "Installing via apt (Debian/Ubuntu/Raspbian)..."
|
|
local dpkg_arch
|
|
dpkg_arch=$(dpkg --print-architecture)
|
|
|
|
# Zabbix provides separate repos for ARM architectures:
|
|
# - debian-arm64 / ubuntu-arm64 for aarch64 (Bookworm/Trixie+ only)
|
|
# - raspbian for armhf (Raspberry Pi OS)
|
|
# The standard debian/ubuntu repos only carry amd64.
|
|
local repo_distro=""
|
|
case "${dpkg_arch}" in
|
|
arm64)
|
|
if [ "${OS_ID}" = "ubuntu" ]; then
|
|
repo_distro="ubuntu-arm64"
|
|
else
|
|
repo_distro="debian-arm64"
|
|
fi
|
|
;;
|
|
armhf)
|
|
repo_distro="raspbian"
|
|
;;
|
|
*)
|
|
log "Unexpected dpkg arch '${dpkg_arch}' on ARM script. Falling back to binary..."
|
|
install_agent_binary
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
# Determine release codename (e.g. bullseye, bookworm, jammy)
|
|
local codename=""
|
|
if [ -f /etc/os-release ]; then
|
|
codename=$(. /etc/os-release && echo "${VERSION_CODENAME:-}")
|
|
fi
|
|
if [ -z "${codename}" ]; then
|
|
log "Could not determine release codename. Falling back to binary..."
|
|
install_agent_binary
|
|
return 0
|
|
fi
|
|
|
|
# The arm64 Zabbix repos only support Debian 12+ (bookworm, trixie).
|
|
# For older/EOL releases like bullseye, skip directly to binary install.
|
|
case "${codename}" in
|
|
buster|bullseye|stretch|jessie)
|
|
log "Zabbix arm64 apt repo not available for EOL release '${codename}'."
|
|
log "Falling back to binary tarball..."
|
|
install_agent_binary
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
# Disable defunct backports repos to prevent apt-get update 404 errors (Debian EOL releases)
|
|
local backports_list
|
|
backports_list=$(grep -rl 'backports' /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null || true)
|
|
if [ -n "${backports_list}" ]; then
|
|
log "Disabling defunct backports repositories to avoid 404 errors..."
|
|
for f in ${backports_list}; do
|
|
sed -i '/backports/s/^[^#]/#&/' "${f}"
|
|
done
|
|
fi
|
|
|
|
# Download and install the Zabbix release package for the ARM-specific repo
|
|
local release_url="https://repo.zabbix.com/zabbix/7.0/${repo_distro}/pool/main/z/zabbix-release/zabbix-release_latest_7.0+${OS_ID}${OS_VERSION}_all.deb"
|
|
log "Adding Zabbix repository: ${repo_distro} (${codename})"
|
|
log "Release package URL: ${release_url}"
|
|
|
|
if wget -q "${release_url}" -O /tmp/zabbix-release.deb 2>/dev/null || \
|
|
curl -sfL "${release_url}" -o /tmp/zabbix-release.deb 2>/dev/null; then
|
|
|
|
# Verify we actually got a .deb and not an error page
|
|
if ! dpkg-deb --info /tmp/zabbix-release.deb >/dev/null 2>&1; then
|
|
log "Downloaded file is not a valid .deb package. Falling back to binary..."
|
|
rm -f /tmp/zabbix-release.deb
|
|
install_agent_binary
|
|
return 0
|
|
fi
|
|
|
|
dpkg -i /tmp/zabbix-release.deb
|
|
apt-get update
|
|
if apt-get install -y zabbix-agent2; then
|
|
rm -f /tmp/zabbix-release.deb
|
|
log "Package installation successful."
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
log "Package manager install failed, falling back to binary tarball..."
|
|
rm -f /tmp/zabbix-release.deb
|
|
install_agent_binary
|
|
;;
|
|
*)
|
|
log "No ARM package available for '${OS_ID}', using binary tarball..."
|
|
install_agent_binary
|
|
;;
|
|
esac
|
|
}
|
|
|
|
install_agent_binary() {
|
|
log "Installing Zabbix Agent 2 from direct .deb package (bookworm arm64)..."
|
|
|
|
# Zabbix does not publish static binary tarballs for ARM architectures.
|
|
# Instead, we fetch the .deb package directly from the debian-arm64 bookworm pool.
|
|
# Agent 2 is a Go binary with minimal libc dependencies, so installing a bookworm
|
|
# .deb on bullseye works reliably.
|
|
|
|
local deb_path="/tmp/zabbix_agent2.deb"
|
|
local pool_base="https://repo.zabbix.com/zabbix/7.0/debian-arm64/pool/main/z/zabbix"
|
|
|
|
# Try multiple URL patterns for the .deb package
|
|
local deb_urls=(
|
|
"${pool_base}/zabbix-agent2_${ZABBIX_VERSION}-1+debian12_arm64.deb"
|
|
"${pool_base}/zabbix-agent2_${ZABBIX_VERSION}-1%2Bdebian12_arm64.deb"
|
|
)
|
|
|
|
local downloaded=false
|
|
for url in "${deb_urls[@]}"; do
|
|
log "Trying: ${url}"
|
|
if wget -q "${url}" -O "${deb_path}" 2>/dev/null; then
|
|
if dpkg-deb --info "${deb_path}" >/dev/null 2>&1; then
|
|
downloaded=true
|
|
break
|
|
fi
|
|
fi
|
|
if curl -sfL "${url}" -o "${deb_path}" 2>/dev/null; then
|
|
if dpkg-deb --info "${deb_path}" >/dev/null 2>&1; then
|
|
downloaded=true
|
|
break
|
|
fi
|
|
fi
|
|
rm -f "${deb_path}"
|
|
done
|
|
|
|
# Fallback: try the CDN static tarball path (may work for some versions)
|
|
if [ "${downloaded}" = false ]; then
|
|
local tarball_url="https://cdn.zabbix.com/zabbix/binaries/stable/7.0/${ZABBIX_VERSION}/zabbix_agent2-${ZABBIX_VERSION}-${TARBALL_ARCH}-static.tar.gz"
|
|
local tarball_path="/tmp/zabbix_agent2.tar.gz"
|
|
|
|
log "Trying CDN tarball: ${tarball_url}"
|
|
if wget -q "${tarball_url}" -O "${tarball_path}" 2>/dev/null || \
|
|
curl -sfL "${tarball_url}" -o "${tarball_path}" 2>/dev/null; then
|
|
# Verify it's actually a gzip file
|
|
if file "${tarball_path}" 2>/dev/null | grep -q gzip; then
|
|
install_from_tarball "${tarball_path}"
|
|
return 0
|
|
fi
|
|
fi
|
|
rm -f "${tarball_path}"
|
|
|
|
log "ERROR: Failed to download Zabbix Agent 2 for ${ARCH_LABEL}."
|
|
log " No static binary or .deb package found."
|
|
log " Options:"
|
|
log " 1. Upgrade to Debian 12 (Bookworm) and re-run this script"
|
|
log " 2. Manually download from https://www.zabbix.com/download"
|
|
log " 3. Install from Debian's own repos: apt install zabbix-agent2"
|
|
exit 1
|
|
fi
|
|
|
|
# Install the .deb package
|
|
log "Installing .deb package..."
|
|
mkdir -p /etc/zabbix
|
|
mkdir -p /var/log/zabbix
|
|
mkdir -p /var/run/zabbix
|
|
|
|
# Create zabbix user if it doesn't exist
|
|
if ! id -u zabbix &>/dev/null; then
|
|
useradd -r -s /sbin/nologin -d /var/lib/zabbix -M zabbix
|
|
fi
|
|
|
|
# Install with --force-depends to handle minor dependency version mismatches
|
|
# between bookworm and bullseye
|
|
if ! dpkg -i --force-depends "${deb_path}" 2>&1; then
|
|
log "dpkg install had issues, attempting to fix dependencies..."
|
|
apt-get install -f -y 2>/dev/null || true
|
|
fi
|
|
|
|
rm -f "${deb_path}"
|
|
|
|
# Verify the binary is in place
|
|
if command -v zabbix_agent2 >/dev/null 2>&1 || [ -f /usr/sbin/zabbix_agent2 ]; then
|
|
log "Package installation complete."
|
|
chown -R zabbix:zabbix /var/log/zabbix /var/run/zabbix 2>/dev/null || true
|
|
else
|
|
log "ERROR: zabbix_agent2 binary not found after package install."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
install_from_tarball() {
|
|
local tarball_path="$1"
|
|
log "Extracting tarball..."
|
|
|
|
# Create directories
|
|
mkdir -p "${INSTALL_DIR}/bin"
|
|
mkdir -p /etc/zabbix
|
|
mkdir -p /var/log/zabbix
|
|
mkdir -p /var/run/zabbix
|
|
|
|
# Extract
|
|
tar -xzf "${tarball_path}" -C "${INSTALL_DIR}" --strip-components=1 2>/dev/null || \
|
|
tar -xzf "${tarball_path}" -C "${INSTALL_DIR}" 2>/dev/null
|
|
|
|
# Find the binary
|
|
local agent_bin
|
|
agent_bin=$(find "${INSTALL_DIR}" -name "zabbix_agent2" -type f 2>/dev/null | head -1)
|
|
if [ -z "${agent_bin}" ]; then
|
|
log "ERROR: Could not find zabbix_agent2 binary in extracted archive."
|
|
exit 1
|
|
fi
|
|
|
|
# Move binary to expected location
|
|
cp "${agent_bin}" "${INSTALL_DIR}/bin/zabbix_agent2"
|
|
chmod +x "${INSTALL_DIR}/bin/zabbix_agent2"
|
|
ln -sf "${INSTALL_DIR}/bin/zabbix_agent2" /usr/sbin/zabbix_agent2
|
|
|
|
# Create zabbix user if it doesn't exist
|
|
if ! id -u zabbix &>/dev/null; then
|
|
useradd -r -s /sbin/nologin -d /var/lib/zabbix -M zabbix
|
|
fi
|
|
|
|
chown -R zabbix:zabbix /var/log/zabbix /var/run/zabbix
|
|
|
|
# Create systemd service
|
|
create_systemd_service
|
|
|
|
rm -f "${tarball_path}"
|
|
log "Binary installation complete."
|
|
}
|
|
|
|
create_systemd_service() {
|
|
log "Creating systemd service..."
|
|
cat > /etc/systemd/system/zabbix-agent2.service << 'EOF'
|
|
[Unit]
|
|
Description=Zabbix Agent 2
|
|
After=syslog.target
|
|
After=network.target
|
|
|
|
[Service]
|
|
Environment="CONFFILE=/etc/zabbix/zabbix_agent2.conf"
|
|
Type=simple
|
|
Restart=on-failure
|
|
PIDFile=/var/run/zabbix/zabbix_agent2.pid
|
|
KillMode=control-group
|
|
ExecStart=/usr/sbin/zabbix_agent2 -c $CONFFILE
|
|
ExecStop=/bin/kill -SIGTERM $MAINPID
|
|
RestartSec=10s
|
|
User=zabbix
|
|
Group=zabbix
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
}
|
|
|
|
generate_psk() {
|
|
openssl rand -hex 32
|
|
}
|
|
|
|
configure_agent() {
|
|
local psk_key="$1"
|
|
|
|
log "Writing PSK to ${PSK_FILE}..."
|
|
echo "${psk_key}" > "${PSK_FILE}"
|
|
chmod 640 "${PSK_FILE}"
|
|
chown root:zabbix "${PSK_FILE}"
|
|
|
|
log "Writing agent configuration to ${AGENT_CONF}..."
|
|
# Back up existing config if present
|
|
[ -f "${AGENT_CONF}" ] && cp "${AGENT_CONF}" "${AGENT_CONF}.bak.$(date +%s)"
|
|
|
|
cat > "${AGENT_CONF}" << EOF
|
|
# Zabbix Agent 2 Configuration
|
|
# Auto-generated by ARM deployment script on $(date '+%Y-%m-%d %H:%M:%S')
|
|
# Architecture: ${ARCH} (${ARCH_LABEL})
|
|
|
|
Server=${ZABBIX_SERVER}
|
|
ServerActive=${ZABBIX_SERVER}
|
|
HostnameItem=system.hostname
|
|
HostMetadata=${HOST_METADATA}
|
|
|
|
# PSK Encryption
|
|
TLSConnect=psk
|
|
TLSAccept=psk
|
|
TLSPSKIdentity=${PSK_IDENTITY}
|
|
TLSPSKFile=${PSK_FILE}
|
|
|
|
# Logging
|
|
LogFile=/var/log/zabbix/zabbix_agent2.log
|
|
LogFileSize=10
|
|
|
|
# Performance
|
|
BufferSend=5
|
|
BufferSize=100
|
|
EOF
|
|
|
|
chown root:zabbix "${AGENT_CONF}"
|
|
chmod 644 "${AGENT_CONF}"
|
|
}
|
|
|
|
start_agent() {
|
|
log "Enabling and starting zabbix-agent2..."
|
|
systemctl enable zabbix-agent2
|
|
systemctl restart zabbix-agent2
|
|
|
|
sleep 2
|
|
if systemctl is-active --quiet zabbix-agent2; then
|
|
log "Zabbix Agent 2 is running."
|
|
systemctl status zabbix-agent2 --no-pager
|
|
else
|
|
log "WARNING: Agent may not have started. Check logs:"
|
|
log " journalctl -u zabbix-agent2 -n 20"
|
|
log " cat /var/log/zabbix/zabbix_agent2.log"
|
|
fi
|
|
}
|
|
|
|
# --- Main ---
|
|
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
echo "This script must be run as root." >&2
|
|
exit 1
|
|
fi
|
|
|
|
PSK_KEY="${1:-}"
|
|
if [ -z "${PSK_KEY}" ]; then
|
|
PSK_KEY=$(generate_psk)
|
|
log "Generated new PSK key."
|
|
fi
|
|
|
|
# Validate PSK is valid hex and at least 32 chars
|
|
if ! echo "${PSK_KEY}" | grep -qE '^[0-9a-fA-F]{32,128}$'; then
|
|
log "ERROR: PSK must be a 32-128 character hex string."
|
|
exit 1
|
|
fi
|
|
|
|
detect_arch
|
|
|
|
log "=== Zabbix Agent 2 Deployment (ARM) ==="
|
|
log "Server: ${ZABBIX_SERVER}"
|
|
log "PSK Identity: ${PSK_IDENTITY}"
|
|
log "Architecture: ${ARCH_LABEL}"
|
|
|
|
install_agent_package_manager
|
|
configure_agent "${PSK_KEY}"
|
|
start_agent
|
|
|
|
log "=== Deployment Complete ==="
|
|
log "PSK Identity: ${PSK_IDENTITY}"
|
|
log "PSK Key: ${PSK_KEY}"
|
|
log ""
|
|
log "IMPORTANT: Use this same PSK identity and key in your Zabbix server"
|
|
log "auto-registration encryption settings."
|