#!/usr/bin/env bash # ============================================================================== # db_log_exporter — 安装部署脚本 # ============================================================================== # 用法: # sudo ./setup.sh [install | uninstall | status] # # 支持: CentOS 7/8, RHEL, Fedora, Debian, Ubuntu # ============================================================================== set -euo pipefail APP_NAME="db_log_exporter" INSTALL_DIR="/opt/${APP_NAME}" CONFIG_DIR="/etc/${APP_NAME}" SYSTEMD_UNIT="${APP_NAME}.service" LOG_DIR="/var/log/${APP_NAME}" DATA_DIR="/var/lib/${APP_NAME}" RUN_DIR="/var/run/${APP_NAME}" CHECKPOINT_DIR="${DATA_DIR}/checkpoints" # 颜色 RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*" >&2; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } need_root() { [ "$(id -u)" -eq 0 ] || error "请用 root 权限运行: sudo $0 $*"; } # --------------------------------------------------------------------------- # 检查依赖 # --------------------------------------------------------------------------- check_deps() { info "检查依赖..." local missing=() if ! command -v python3 &>/dev/null; then missing+=("python3") fi if ! python3 -c "import pymysql" 2>/dev/null; then missing+=("PyMySQL (pip3 install pymysql)") fi if ! python3 -c "import psycopg2" 2>/dev/null; then missing+=("psycopg2-binary (pip3 install psycopg2-binary)") fi if ! python3 -c "import yaml" 2>/dev/null; then missing+=("PyYAML (pip3 install pyyaml)") fi if [ ${#missing[@]} -gt 0 ]; then error "缺少依赖: ${missing[*]} \n请先安装: pip3 install PyMySQL psycopg2-binary PyYAML" fi # 检查 MySQL / PostgreSQL 客户端(仅检查命令是否存在,不强制要求服务运行) if command -v mysql &>/dev/null || command -v psql &>/dev/null; then info "数据库客户端已找到" else warn "未找到 mysql/psql 客户端(程序使用 Python DB 驱动,不影响运行)" fi info "依赖检查通过 ✓" } # --------------------------------------------------------------------------- # 安装 # --------------------------------------------------------------------------- do_install() { need_root "$@" check_deps info "开始安装 ${APP_NAME}..." # 1. 创建目录 for d in "${INSTALL_DIR}" "${CONFIG_DIR}" "${LOG_DIR}" "${DATA_DIR}" "${CHECKPOINT_DIR}" "${RUN_DIR}"; do mkdir -p "$d" echo " 创建: $d" done # 2. 复制文件 cp "$(dirname "$0")/db_log_exporter.py" "${INSTALL_DIR}/" cp "$(dirname "$0")/config.yaml" "${CONFIG_DIR}/config.yaml.example" [ -f "$(dirname "$0")/requirements.txt" ] && \ cp "$(dirname "$0")/requirements.txt" "${INSTALL_DIR}/" info "文件已复制到 ${INSTALL_DIR} 和 ${CONFIG_DIR}" # 3. 创建 config.yaml(如果不存在) if [ ! -f "${CONFIG_DIR}/config.yaml" ]; then if [ -f "${CONFIG_DIR}/config.yaml.example" ]; then cp "${CONFIG_DIR}/config.yaml.example" "${CONFIG_DIR}/config.yaml" warn "已创建默认配置: ${CONFIG_DIR}/config.yaml" warn "请编辑配置文件,填入数据库连接信息后再启动服务!" fi fi # 4. 安装 systemd 服务 local systemd_dir="/etc/systemd/system" cp "$(dirname "$0")/${SYSTEMD_UNIT}" "${systemd_dir}/" chmod 644 "${systemd_dir}/${SYSTEMD_UNIT}" systemctl daemon-reload info "systemd 服务已安装 ✓" info "" info "=== 后续步骤 ===" info "1. 编辑配置: nano ${CONFIG_DIR}/config.yaml" info "2. 检查连接: python3 ${INSTALL_DIR}/${APP_NAME}.py -c ${CONFIG_DIR}/config.yaml --dry-run" info "3. 启动服务: systemctl start ${APP_NAME}" info "4. 开机自启: systemctl enable ${APP_NAME}" info "5. 查看日志: journalctl -u ${APP_NAME} -f" info "" info "安装完成 ✓" } # --------------------------------------------------------------------------- # 卸载 # --------------------------------------------------------------------------- do_uninstall() { need_root "$@" info "停止并禁用服务..." systemctl stop "${APP_NAME}" 2>/dev/null || true systemctl disable "${APP_NAME}" 2>/dev/null || true info "删除 systemd unit..." rm -f "/etc/systemd/system/${SYSTEMD_UNIT}" systemctl daemon-reload info "删除安装目录(确认不再需要)..." read -rp "是否删除 ${INSTALL_DIR} 和 ${CONFIG_DIR}?[y/N]: " confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then rm -rf "${INSTALL_DIR}" "${CONFIG_DIR}" "${LOG_DIR}" "${DATA_DIR}" "${RUN_DIR}" info "已删除所有文件 ✓" else warn "保留文件,手动清理: rm -rf ${INSTALL_DIR} ${CONFIG_DIR}" fi } # --------------------------------------------------------------------------- # 状态 # --------------------------------------------------------------------------- do_status() { if systemctl is-active --quiet "${APP_NAME}"; then info "服务状态: 运行中 ✓" systemctl status "${APP_NAME}" --no-pager elif systemctl is-enabled --quiet "${APP_NAME}"; then warn "服务状态: 未运行(已开机自启)" else warn "服务状态: 未安装或未启用" fi if [ -d "${CHECKPOINT_DIR}" ]; then echo "" info "断点文件:" ls -la "${CHECKPOINT_DIR}" 2>/dev/null | grep -v "^total" || echo " (空)" fi if [ -d "${LOG_DIR}" ]; then echo "" info "日志文件:" ls -lh "${LOG_DIR}" 2>/dev/null || echo " (空)" fi } # --------------------------------------------------------------------------- # 主入口 # --------------------------------------------------------------------------- ACTION="${1:-install}" case "$ACTION" in install) do_install "$@" ;; uninstall) do_uninstall "$@" ;; status) do_status "$@" ;; *) error "未知操作: $ACTION(支持: install | uninstall | status)" ;; esac