- архив снова tar.gz (сохраняет chmod +x) - wheels для Python 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 - install.sh проверяет Python >= 3.10 перед установкой
314 lines
11 KiB
Bash
Executable File
314 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# Airflow DAG Monitor - Offline Build Script
|
||
#
|
||
# Собирает автономный ZIP-архив со всеми зависимостями (wheel-пакеты),
|
||
# исходным кодом и скриптами установки. Архив можно перенести в закрытый
|
||
# контур без доступа в интернет и развернуть через install.sh.
|
||
#
|
||
# Использование:
|
||
# ./build.sh
|
||
# =============================================================================
|
||
set -euo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
VERSION=$(python3 -c "
|
||
import re, pathlib
|
||
text = pathlib.Path('$SCRIPT_DIR/airflow_monitor/__init__.py').read_text()
|
||
m = re.search(r'__version__\s*=\s*[\\x22\\x27]([^\\x22\\x27]+)', text)
|
||
print(m.group(1) if m else '0.0.0')
|
||
")
|
||
BUILD_DIR="$SCRIPT_DIR/build"
|
||
DIST_DIR="$SCRIPT_DIR/dist"
|
||
WHEELS_DIR="$BUILD_DIR/wheels"
|
||
STAGE_DIR="$BUILD_DIR/airflow-monitor-${VERSION}"
|
||
|
||
echo "=== Airflow DAG Monitor — Offline Build ==="
|
||
echo "Version: ${VERSION}"
|
||
echo "Build dir: ${BUILD_DIR}"
|
||
echo ""
|
||
|
||
# --- Cleanup previous build ---
|
||
rm -rf "$BUILD_DIR"
|
||
mkdir -p "$WHEELS_DIR" "$STAGE_DIR" "$DIST_DIR"
|
||
|
||
# --- Step 1: Download wheel packages ---
|
||
echo "[1/4] Downloading dependencies as wheel packages..."
|
||
|
||
# Download wheels for multiple Python versions to support different servers
|
||
PYTHON_VERSIONS="39 310 311 312 313 314"
|
||
echo " Downloading for Python versions: ${PYTHON_VERSIONS}"
|
||
|
||
for pyver in $PYTHON_VERSIONS; do
|
||
python3 -m pip download \
|
||
-r "$SCRIPT_DIR/requirements.txt" \
|
||
--dest "$WHEELS_DIR" \
|
||
--python-version "$pyver" \
|
||
--only-binary=:all: \
|
||
--quiet 2>/dev/null || true
|
||
done
|
||
|
||
# Also download pure-python wheels (no version constraint)
|
||
python3 -m pip download \
|
||
-r "$SCRIPT_DIR/requirements.txt" \
|
||
--dest "$WHEELS_DIR" \
|
||
--quiet 2>/dev/null || true
|
||
|
||
# Deduplicate (same file may be downloaded multiple times)
|
||
WHEEL_COUNT=$(find "$WHEELS_DIR" -type f | wc -l)
|
||
echo " Downloaded $WHEEL_COUNT packages:"
|
||
find "$WHEELS_DIR" -type f -printf " %f\n" | sort
|
||
|
||
# --- Step 2: Stage project files ---
|
||
echo "[2/4] Staging project files..."
|
||
|
||
# Application code
|
||
cp -r "$SCRIPT_DIR/airflow_monitor" "$STAGE_DIR/airflow_monitor"
|
||
# Remove __pycache__
|
||
find "$STAGE_DIR/airflow_monitor" -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
||
|
||
# Configuration and docs
|
||
cp "$SCRIPT_DIR/config.yaml" "$STAGE_DIR/"
|
||
cp "$SCRIPT_DIR/requirements.txt" "$STAGE_DIR/"
|
||
cp "$SCRIPT_DIR/airflow-monitor.service" "$STAGE_DIR/"
|
||
cp "$SCRIPT_DIR/README.md" "$STAGE_DIR/"
|
||
|
||
# Zabbix agent config
|
||
cp -r "$SCRIPT_DIR/zabbix" "$STAGE_DIR/zabbix"
|
||
|
||
# Wheels directory
|
||
cp -r "$WHEELS_DIR" "$STAGE_DIR/wheels"
|
||
|
||
echo " Staged files:"
|
||
find "$STAGE_DIR" -type f -printf " %P\n" | head -30
|
||
|
||
# --- Step 3: Generate offline install script ---
|
||
echo "[3/4] Generating install.sh..."
|
||
|
||
cat > "$STAGE_DIR/install.sh" << 'INSTALL_SCRIPT'
|
||
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# Airflow DAG Monitor - Offline Installer
|
||
#
|
||
# Устанавливает сервис из автономного архива без доступа в интернет.
|
||
# Все зависимости включены в каталог wheels/.
|
||
#
|
||
# Использование:
|
||
# ./install.sh # установка в /opt/airflow-monitor
|
||
# ./install.sh --prefix /srv/monitor # установка в указанный каталог
|
||
# =============================================================================
|
||
set -euo pipefail
|
||
|
||
# --- Check Python version ---
|
||
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || echo "0.0")
|
||
PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
|
||
PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
|
||
|
||
if [ "$PYTHON_MAJOR" -lt 3 ] || { [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]; }; then
|
||
echo "ERROR: Python 3.10+ required, found Python ${PYTHON_VERSION}" >&2
|
||
echo "" >&2
|
||
echo "Install Python 3.10+:" >&2
|
||
echo " RHEL/CentOS: yum install python3.11" >&2
|
||
echo " ALT Linux: apt-get install python3" >&2
|
||
echo " Debian: apt install python3.11" >&2
|
||
exit 1
|
||
fi
|
||
echo "Python version: ${PYTHON_VERSION} (OK)"
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
INSTALL_DIR="/opt/airflow-monitor"
|
||
SERVICE_USER="$(whoami)"
|
||
SERVICE_NAME="airflow-monitor"
|
||
|
||
# --- Parse arguments ---
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--prefix)
|
||
INSTALL_DIR="$2"
|
||
shift 2
|
||
;;
|
||
--user)
|
||
SERVICE_USER="$2"
|
||
shift 2
|
||
;;
|
||
-h|--help)
|
||
echo "Usage: $0 [--prefix INSTALL_DIR] [--user SERVICE_USER]"
|
||
echo ""
|
||
echo "Options:"
|
||
echo " --prefix Installation directory (default: /opt/airflow-monitor)"
|
||
echo " --user User to run the service as (default: current user)"
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo "Unknown option: $1" >&2
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
VENV_DIR="$INSTALL_DIR/venv"
|
||
|
||
echo "=== Airflow DAG Monitor — Offline Install ==="
|
||
echo "Source: $SCRIPT_DIR"
|
||
echo "Install dir: $INSTALL_DIR"
|
||
echo "Service user: $SERVICE_USER"
|
||
echo ""
|
||
|
||
# --- Step 1: Copy files if installing to a different directory ---
|
||
if [ "$INSTALL_DIR" != "$SCRIPT_DIR" ]; then
|
||
echo "[1/5] Copying files to $INSTALL_DIR..."
|
||
mkdir -p "$INSTALL_DIR"
|
||
cp -r "$SCRIPT_DIR/airflow_monitor" "$INSTALL_DIR/"
|
||
cp -r "$SCRIPT_DIR/wheels" "$INSTALL_DIR/"
|
||
cp -r "$SCRIPT_DIR/zabbix" "$INSTALL_DIR/"
|
||
cp "$SCRIPT_DIR/config.yaml" "$INSTALL_DIR/"
|
||
cp "$SCRIPT_DIR/requirements.txt" "$INSTALL_DIR/"
|
||
cp "$SCRIPT_DIR/airflow-monitor.service" "$INSTALL_DIR/"
|
||
cp "$SCRIPT_DIR/README.md" "$INSTALL_DIR/"
|
||
echo " Done"
|
||
else
|
||
echo "[1/5] Installing in place, skipping copy"
|
||
fi
|
||
|
||
# --- Step 2: Create virtual environment ---
|
||
echo "[2/5] Creating Python virtual environment..."
|
||
if [ -d "$VENV_DIR" ]; then
|
||
rm -rf "$VENV_DIR"
|
||
fi
|
||
python3 -m venv "$VENV_DIR"
|
||
echo " Created: $VENV_DIR"
|
||
|
||
# --- Step 3: Install dependencies from local wheels ---
|
||
echo "[3/5] Installing dependencies from local wheels (offline)..."
|
||
"$VENV_DIR/bin/pip" install \
|
||
--no-index \
|
||
--find-links "$INSTALL_DIR/wheels" \
|
||
-r "$INSTALL_DIR/requirements.txt" \
|
||
--quiet
|
||
echo " Installed packages:"
|
||
"$VENV_DIR/bin/pip" list --format=columns 2>/dev/null | grep -vE '^(Package|---)'
|
||
echo ""
|
||
|
||
# --- Step 4: Create required directories ---
|
||
echo "[4/5] Creating directories..."
|
||
|
||
STATE_DIR="/var/lib/airflow-monitor"
|
||
LOG_DIR="/var/log/airflow-monitor"
|
||
|
||
for dir in "$STATE_DIR" "$LOG_DIR"; do
|
||
if [ ! -d "$dir" ]; then
|
||
sudo mkdir -p "$dir"
|
||
sudo chown "${SERVICE_USER}:$(id -gn "$SERVICE_USER")" "$dir"
|
||
echo " Created: $dir"
|
||
else
|
||
echo " Exists: $dir"
|
||
fi
|
||
done
|
||
|
||
# --- Step 5: Install systemd service ---
|
||
echo "[5/5] Installing systemd service..."
|
||
|
||
# Patch service file with actual paths and user
|
||
SERVICE_FILE="$INSTALL_DIR/airflow-monitor.service"
|
||
if [ -f "$SERVICE_FILE" ]; then
|
||
TEMP_SERVICE=$(mktemp)
|
||
sed \
|
||
-e "s|User=.*|User=${SERVICE_USER}|" \
|
||
-e "s|Group=.*|Group=$(id -gn "$SERVICE_USER")|" \
|
||
-e "s|WorkingDirectory=.*|WorkingDirectory=${INSTALL_DIR}|" \
|
||
-e "s|ExecStart=.*|ExecStart=${VENV_DIR}/bin/python -m airflow_monitor --config ${INSTALL_DIR}/config.yaml|" \
|
||
"$SERVICE_FILE" > "$TEMP_SERVICE"
|
||
|
||
sudo cp "$TEMP_SERVICE" /etc/systemd/system/${SERVICE_NAME}.service
|
||
rm -f "$TEMP_SERVICE"
|
||
sudo systemctl daemon-reload
|
||
echo " Installed: /etc/systemd/system/${SERVICE_NAME}.service"
|
||
else
|
||
echo " WARNING: service file not found, skipping"
|
||
fi
|
||
|
||
# --- Step 6: Install Zabbix agent config ---
|
||
echo "[6/6] Installing Zabbix agent config..."
|
||
ZABBIX_CONF_SRC="$INSTALL_DIR/zabbix/airflow-monitor.conf"
|
||
ZABBIX_CONF_DST="/etc/zabbix/zabbix_agentd.conf.d/airflow-monitor.conf"
|
||
|
||
if [ -f "$ZABBIX_CONF_SRC" ]; then
|
||
if [ -d "/etc/zabbix/zabbix_agentd.conf.d" ]; then
|
||
sudo cp "$ZABBIX_CONF_SRC" "$ZABBIX_CONF_DST"
|
||
sudo chmod 644 "$ZABBIX_CONF_DST"
|
||
echo " Installed: $ZABBIX_CONF_DST"
|
||
if systemctl is-active zabbix-agent >/dev/null 2>&1; then
|
||
sudo systemctl restart zabbix-agent
|
||
echo " Restarted: zabbix-agent"
|
||
elif systemctl is-active zabbix-agent2 >/dev/null 2>&1; then
|
||
sudo systemctl restart zabbix-agent2
|
||
echo " Restarted: zabbix-agent2"
|
||
else
|
||
echo " WARNING: zabbix-agent not running, restart manually"
|
||
fi
|
||
else
|
||
echo " WARNING: /etc/zabbix/zabbix_agentd.conf.d/ not found"
|
||
echo " Copy manually: sudo cp $ZABBIX_CONF_SRC $ZABBIX_CONF_DST"
|
||
fi
|
||
else
|
||
echo " WARNING: zabbix config not found"
|
||
fi
|
||
|
||
# Ensure data dir is readable by zabbix agent
|
||
sudo chmod 755 /var/lib/airflow-monitor 2>/dev/null || true
|
||
|
||
echo ""
|
||
echo "=== Install Complete ==="
|
||
echo ""
|
||
echo "Next steps:"
|
||
echo " 1. Edit config.yaml:"
|
||
echo " vim $INSTALL_DIR/config.yaml"
|
||
echo ""
|
||
echo " 2. Test manually:"
|
||
echo " $VENV_DIR/bin/python -m airflow_monitor --discover -c $INSTALL_DIR/config.yaml"
|
||
echo ""
|
||
echo " 3. Enable and start:"
|
||
echo " sudo systemctl enable --now $SERVICE_NAME"
|
||
echo ""
|
||
echo " 4. Check logs:"
|
||
echo " journalctl -u $SERVICE_NAME -f"
|
||
echo ""
|
||
echo " 5. Verify Zabbix agent reads data:"
|
||
echo " zabbix_agentd -t airflow.monitor.heartbeat"
|
||
echo " zabbix_agentd -t airflow.dag.problems.count"
|
||
INSTALL_SCRIPT
|
||
|
||
chmod +x "$STAGE_DIR/install.sh"
|
||
echo " Generated: install.sh"
|
||
|
||
# --- Step 4: Create archive ---
|
||
echo "[4/4] Creating tar.gz archive..."
|
||
|
||
ARCHIVE_NAME="airflow-monitor-${VERSION}.tar.gz"
|
||
ARCHIVE_PATH="$DIST_DIR/$ARCHIVE_NAME"
|
||
|
||
(cd "$BUILD_DIR" && tar czf "$ARCHIVE_PATH" "airflow-monitor-${VERSION}")
|
||
|
||
ARCHIVE_SIZE=$(du -h "$ARCHIVE_PATH" | cut -f1)
|
||
|
||
echo " Archive: $ARCHIVE_PATH"
|
||
echo " Size: $ARCHIVE_SIZE"
|
||
|
||
# --- Cleanup build directory ---
|
||
rm -rf "$BUILD_DIR"
|
||
|
||
echo ""
|
||
echo "=== Build Complete ==="
|
||
echo ""
|
||
echo "Архив для переноса в закрытый контур:"
|
||
echo " $ARCHIVE_PATH"
|
||
echo ""
|
||
echo "Развёртывание на целевом сервере:"
|
||
echo " 1. Скопировать: scp $ARCHIVE_PATH user@target:/tmp/"
|
||
echo " 2. Распаковать: tar xzf /tmp/$ARCHIVE_NAME -C /tmp/"
|
||
echo " 3. Установить: cd /tmp/airflow-monitor-${VERSION} && ./install.sh"
|
||
echo ""
|
||
echo "По умолчанию устанавливается в /opt/airflow-monitor."
|
||
echo "Для смены каталога или пользователя:"
|
||
echo " ./install.sh --prefix /srv/airflow-monitor --user airflow"
|