One-shot Ubuntu agent2 installer (active checks)
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
# zabbix-agent
|
||||||
|
|
||||||
|
One-shot [Zabbix agent2](https://www.zabbix.com/) installer for Ubuntu,
|
||||||
|
using **active checks** — the agent connects *out* to the server, so it
|
||||||
|
works behind NAT/firewalls and needs no inbound ports.
|
||||||
|
|
||||||
|
- Idempotent — safe to re-run
|
||||||
|
- Installs from the official Zabbix apt repo (agent2)
|
||||||
|
- Config: `ServerActive=<server>`, `Server=127.0.0.1,<server>`,
|
||||||
|
`Hostname=<name>` (defaults to the short system hostname)
|
||||||
|
|
||||||
|
## Use
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# clone once, then git pull for updates:
|
||||||
|
git clone https://gitea.noctools.nz/noctools/zabbix-agent.git
|
||||||
|
sudo ./install-zabbix-agent2-ubuntu.sh --server <server-ip-or-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with no local copy at all:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://gitea.noctools.nz/noctools/zabbix-agent/raw/branch/main/install-zabbix-agent2-ubuntu.sh \
|
||||||
|
| sudo bash -s -- --server <server-ip-or-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flags
|
||||||
|
|
||||||
|
| flag | meaning | default |
|
||||||
|
|---|---|---|
|
||||||
|
| `--server HOST[:PORT]` | Zabbix server/proxy for active checks (**required**) | — |
|
||||||
|
| `--hostname NAME` | Zabbix host name — must equal the technical name on the server | short system hostname |
|
||||||
|
| `--major X.Y` | Zabbix repo series | `7.4` |
|
||||||
|
|
||||||
|
After installing, create the host on the Zabbix server with the **exact same
|
||||||
|
technical name** and an active-agent template (e.g. "Linux by Zabbix agent
|
||||||
|
active"). The script reports whether the agent reached the server and warns
|
||||||
|
if the host doesn't exist yet — the warning clears by itself once it does.
|
||||||
Executable
+148
@@ -0,0 +1,148 @@
|
|||||||
|
#!/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
|
||||||
Reference in New Issue
Block a user