149 lines
6.7 KiB
Bash
Executable File
149 lines
6.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# install-zabbix-agent2-ubuntu.sh — one-shot Zabbix agent2 (ACTIVE checks)
|
|
# installer for Ubuntu. Public-safe: nothing about any specific environment
|
|
# is baked in; the server address comes from the required --server flag.
|
|
#
|
|
# Idempotent — safe to re-run. What it does:
|
|
# 1. Installs Zabbix agent2 from the official Zabbix apt repo
|
|
# 2. Writes an ACTIVE-check config (agent connects OUT to the server;
|
|
# no inbound ports, no firewall changes needed — works behind NAT):
|
|
# ServerActive=<server from --server>
|
|
# Server=127.0.0.1,<server host>
|
|
# Hostname=<--hostname, else the short system hostname>
|
|
# 3. Enables + restarts the service and sanity-checks the connection.
|
|
#
|
|
# Usage:
|
|
# sudo ./install-zabbix-agent2-ubuntu.sh --server 203.0.113.10
|
|
# sudo ./install-zabbix-agent2-ubuntu.sh --server 203.0.113.10:10051 --hostname web01
|
|
# sudo ./install-zabbix-agent2-ubuntu.sh web01 --server 203.0.113.10 # positional hostname
|
|
#
|
|
# One-liner (no local copy needed):
|
|
# curl -fsSL <repo-url>/install-zabbix-agent2-ubuntu.sh | sudo bash -s -- --server 203.0.113.10
|
|
#
|
|
# After it succeeds, the host must exist on the Zabbix server with the EXACT
|
|
# same technical name (an active-agent template, e.g. "Linux by Zabbix agent
|
|
# active"). The script warns if the agent cannot fetch its config yet — that
|
|
# warning clears by itself within ~a minute of the host being created.
|
|
|
|
set -euo pipefail
|
|
|
|
ZABBIX_MAJOR="7.4"
|
|
CONF="/etc/zabbix/zabbix_agent2.conf"
|
|
LOG="/var/log/zabbix/zabbix_agent2.log"
|
|
|
|
say() { echo "[zabbix-agent2] $*"; }
|
|
die() { echo "[zabbix-agent2] ERROR: $*" >&2; exit 1; }
|
|
usage() {
|
|
cat <<EOF
|
|
usage: sudo $0 --server HOST[:PORT] [--hostname NAME] [--major X.Y]
|
|
|
|
--server HOST[:PORT] required — Zabbix server/proxy for active checks
|
|
(IP or DNS name; port defaults to 10051)
|
|
--hostname NAME Zabbix host name (default: short system hostname;
|
|
MUST equal the technical host name on the server)
|
|
--major X.Y Zabbix major version from the official repo
|
|
(default: ${ZABBIX_MAJOR}; use your server's version)
|
|
NAME (positional) shorthand for --hostname NAME
|
|
EOF
|
|
}
|
|
|
|
# ---- args --------------------------------------------------------------------
|
|
SERVER_RAW=""
|
|
HOSTNAME_ARG=""
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--server) SERVER_RAW="${2:?}"; shift 2 ;;
|
|
-n|--hostname) HOSTNAME_ARG="${2:?}"; shift 2 ;;
|
|
--major) ZABBIX_MAJOR="${2:?}"; shift 2 ;;
|
|
-h|--help) tail -n +2 "$0" | grep '^#' | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
*) HOSTNAME_ARG="$1"; shift ;;
|
|
esac
|
|
done
|
|
|
|
[ -n "$SERVER_RAW" ] || { usage; die "--server is required"; }
|
|
[[ "$ZABBIX_MAJOR" =~ ^[0-9]+\.[0-9]+$ ]] || die "--major must look like 7.4, not '${ZABBIX_MAJOR}'"
|
|
|
|
# server HOST[:PORT] -> SA_HOST / SA_PORT (plain IPv4 or DNS name)
|
|
case "$SERVER_RAW" in
|
|
*:*) SA_HOST="${SERVER_RAW%%:*}"; SA_PORT="${SERVER_RAW##*:}" ;;
|
|
*) SA_HOST="$SERVER_RAW"; SA_PORT="10051" ;;
|
|
esac
|
|
[[ "$SA_PORT" =~ ^[0-9]+$ ]] || die "bad port in --server '${SERVER_RAW}' (IPv6 literals: give a DNS name instead)"
|
|
[ -n "$SA_HOST" ] && [ "$SA_HOST" != "$SA_PORT" ] || die "bad --server '${SERVER_RAW}'"
|
|
SA_ADDR="$SA_HOST"; [ "$SA_PORT" = "10051" ] || SA_ADDR="${SA_HOST}:${SA_PORT}"
|
|
|
|
ZBX_HOSTNAME="${HOSTNAME_ARG:-$(hostname -s)}"
|
|
case "$ZBX_HOSTNAME" in
|
|
*[!A-Za-z0-9._-]*) die "hostname '${ZBX_HOSTNAME}' has odd chars — pass --hostname <exact Zabbix technical name>" ;;
|
|
esac
|
|
|
|
[ "$(id -u)" -eq 0 ] || die "run as root (sudo)"
|
|
|
|
# ---- platform ----------------------------------------------------------------
|
|
. /etc/os-release
|
|
[ "${ID:-}" = "ubuntu" ] || die "Ubuntu only (found '${ID:-unknown}'); for Debian, swap 'ubuntu' for 'debian' in the repo URL below"
|
|
say "Ubuntu ${VERSION_ID} (${PRETTY_NAME:-ubuntu}) → server ${SA_ADDR}, hostname '${ZBX_HOSTNAME}'"
|
|
|
|
# ---- 1. repo + package ---------------------------------------------------------
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
APT_OPTS="-y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold"
|
|
|
|
apt-get update -qq
|
|
apt-get install -qq $APT_OPTS ca-certificates curl >/dev/null
|
|
|
|
DEB_URL="https://repo.zabbix.com/zabbix/${ZABBIX_MAJOR}/release/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_${ZABBIX_MAJOR}+ubuntu${VERSION_ID}_all.deb"
|
|
curl -fsSI -o /dev/null "$DEB_URL" || die "no zabbix-release for Ubuntu ${VERSION_ID} (check --major); looked at ${DEB_URL}"
|
|
curl -fsS -o /tmp/zabbix-release.deb "$DEB_URL"
|
|
dpkg -i /tmp/zabbix-release.deb || apt-get -f install -qq $APT_OPTS
|
|
rm -f /tmp/zabbix-release.deb
|
|
apt-get update -qq
|
|
apt-get install -qq $APT_OPTS zabbix-agent2
|
|
say "installed: $(zabbix_agent2 -V | head -1)"
|
|
|
|
# ---- 2. config (replace-or-append: one authoritative line per key) -------------
|
|
if [ -f "$CONF" ] && [ ! -f "${CONF}.pre-install.bak" ]; then
|
|
cp -a "$CONF" "${CONF}.pre-install.bak"
|
|
say "backed up stock config to ${CONF}.pre-install.bak"
|
|
fi
|
|
|
|
set_conf() { # file key value — drop every existing (commented) line, append ours
|
|
sed -i -E "/^[[:space:]]*#?[[:space:]]*${2}=/d" "$1"
|
|
echo "${2}=${3}" >> "$1"
|
|
}
|
|
[ -f "$CONF" ] || die "expected ${CONF} to exist after install"
|
|
|
|
set_conf "$CONF" ServerActive "$SA_ADDR"
|
|
set_conf "$CONF" Server "127.0.0.1,${SA_HOST}"
|
|
set_conf "$CONF" Hostname "$ZBX_HOSTNAME"
|
|
|
|
# ---- 3. service + sanity -------------------------------------------------------
|
|
systemctl enable zabbix-agent2 >/dev/null
|
|
systemctl restart zabbix-agent2
|
|
sleep 3
|
|
systemctl is-active --quiet zabbix-agent2 || { journalctl -u zabbix-agent2 -n 20 --no-pager; die "service not active"; }
|
|
zabbix_agent2 -t agent.version >/dev/null 2>&1 || die "agent fails to parse config / answer local test"
|
|
|
|
# Active-check reachability: give the agent ~20s to fetch its first config.
|
|
loggrep() { # pattern — agent log file, else the journal
|
|
if [ -r "$LOG" ]; then grep -Eqi "$1" "$LOG"; else journalctl -u zabbix-agent2 --since '-2 min' | grep -Eqi "$1"; fi
|
|
}
|
|
WARN=""
|
|
for _ in $(seq 1 10); do
|
|
if loggrep 'started to fail|cannot obtain|no active checks|host not found'; then WARN=1; break; fi
|
|
sleep 2
|
|
done
|
|
|
|
echo
|
|
say "done. config:"
|
|
grep -E '^(Server|ServerActive|Hostname)=' "$CONF" | sed 's/^/ /'
|
|
if [ -n "$WARN" ]; then
|
|
say "WARNING: agent cannot fetch its config yet:"
|
|
if [ -r "$LOG" ]; then tail -n 4 "$LOG" | sed 's/^/ /'
|
|
else journalctl -u zabbix-agent2 -n 4 --no-pager | sed 's/^/ /'; fi
|
|
say "expected if the host doesn't exist on the Zabbix server yet — create it"
|
|
say "with the EXACT technical name '${ZBX_HOSTNAME}' and an active-agent"
|
|
say "template; the warning clears by itself within a minute."
|
|
else
|
|
say "active checks OK (no connection errors in the agent log)."
|
|
fi
|