#!/bin/bash set -euo pipefail CONFIG_DIR="${CONFIG_DIR:-/opt/monok8s/config}" NODE_ENV="${NODE_ENV:-$CONFIG_DIR/node.env}" log() { echo "[monok8s-node] $*" } fail() { echo "[monok8s-node] ERROR: $*" >&2 exit 1 } need_cmd() { command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1" } require_file() { [ -f "$1" ] || fail "required file not found: $1" } load_config() { require_file "$NODE_ENV" # shellcheck disable=SC1090 . "$NODE_ENV" HOSTNAME="${HOSTNAME:-}" MGMT_IFACE="${MGMT_IFACE:-}" MGMT_ADDRESS="${MGMT_ADDRESS:-}" MGMT_GATEWAY="${MGMT_GATEWAY:-}" DNS_NAMESERVERS="${DNS_NAMESERVERS:-}" DNS_SEARCH_DOMAINS="${DNS_SEARCH_DOMAINS:-}" } validate_config() { [ -n "$HOSTNAME" ] || fail "HOSTNAME is required" [ -n "$MGMT_IFACE" ] || fail "MGMT_IFACE is required" [ -n "$MGMT_ADDRESS" ] || fail "MGMT_ADDRESS is required" case "$MGMT_ADDRESS" in */*) ;; *) fail "MGMT_ADDRESS must include a CIDR prefix, example: 10.0.0.13/24" ;; esac if [ -n "$DNS_NAMESERVERS" ]; then for ns in $DNS_NAMESERVERS; do case "$ns" in 10.96.0.10) fail "DNS_NAMESERVERS must not contain cluster DNS service IP (10.96.0.10)" ;; esac done fi } check_prereqs() { # only the special one, coreutils should not be checked need_cmd ip need_cmd hostname need_cmd grep } configure_mgmt_interface() { local addr_ip ip link show "$MGMT_IFACE" >/dev/null 2>&1 || fail "interface not found: $MGMT_IFACE" log "bringing up interface: $MGMT_IFACE" ip link set "$MGMT_IFACE" up addr_ip="${MGMT_ADDRESS%/*}" if ip -o addr show dev "$MGMT_IFACE" | awk '{print $4}' | cut -d/ -f1 | grep -Fx "$addr_ip" >/dev/null 2>&1; then log "address already present on $MGMT_IFACE: $MGMT_ADDRESS" else log "assigning $MGMT_ADDRESS to $MGMT_IFACE" ip addr add "$MGMT_ADDRESS" dev "$MGMT_IFACE" fi if [ -n "${MGMT_GATEWAY:-}" ]; then log "ensuring default route via $MGMT_GATEWAY" ip route replace default via "$MGMT_GATEWAY" dev "$MGMT_IFACE" fi } set_hostname_if_needed() { local current_hostname current_hostname="$(hostname 2>/dev/null || true)" if [ "$current_hostname" != "$HOSTNAME" ]; then log "setting hostname to $HOSTNAME" hostname "$HOSTNAME" mkdir -p /etc printf '%s\n' "$HOSTNAME" > /etc/hostname if [ -f /etc/hosts ]; then if ! grep -Eq "[[:space:]]$HOSTNAME([[:space:]]|$)" /etc/hosts; then printf '127.0.0.1\tlocalhost %s\n' "$HOSTNAME" >> /etc/hosts fi else cat > /etc/hosts < /proc/sys/net/ipv4/ip_forward fi mkdir -p /etc/sysctl.d cat > /etc/sysctl.d/99-monok8s.conf <<'EOF' net.ipv4.ip_forward = 1 EOF } configure_dns() { local tmpfile local ns_count=0 if [ -z "$DNS_NAMESERVERS" ]; then log "DNS_NAMESERVERS not set; leaving /etc/resolv.conf unchanged" return fi mkdir -p /etc tmpfile="/etc/resolv.conf.monok8s.tmp" : > "$tmpfile" if [ -n "$DNS_SEARCH_DOMAINS" ]; then printf 'search %s\n' "$DNS_SEARCH_DOMAINS" >> "$tmpfile" fi for ns in $DNS_NAMESERVERS; do printf 'nameserver %s\n' "$ns" >> "$tmpfile" ns_count=$((ns_count + 1)) done [ "$ns_count" -gt 0 ] || fail "DNS_NAMESERVERS is set but no valid nameservers were parsed" printf 'options timeout:2 attempts:3\n' >> "$tmpfile" mv "$tmpfile" /etc/resolv.conf log "configured /etc/resolv.conf from DNS_NAMESERVERS" } print_summary() { log "node configuration applied" log "hostname: $HOSTNAME" log "interface: $MGMT_IFACE" log "address: $MGMT_ADDRESS" if [ -n "${MGMT_GATEWAY:-}" ]; then log "gateway: $MGMT_GATEWAY" else log "gateway: " fi if [ -n "${DNS_NAMESERVERS:-}" ]; then log "dns nameservers: $DNS_NAMESERVERS" else log "dns nameservers: " fi if [ -n "${DNS_SEARCH_DOMAINS:-}" ]; then log "dns search: $DNS_SEARCH_DOMAINS" else log "dns search: " fi } main() { load_config validate_config check_prereqs ensure_ip_forward configure_mgmt_interface configure_dns set_hostname_if_needed print_summary } main "$@"