Files
patch-system-tools/install_patch_system.sh
2025-11-18 10:38:19 +08:00

298 lines
7.9 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# install_patch_system.sh - 补丁管理系统安装脚本
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INSTALL_DIR="/opt/patch-management"
CONFIG_FILE="${SCRIPT_DIR}/patch_config.sh"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"; }
info() { log "INFO: $1"; }
error() { log "ERROR: $1"; exit 1; }
warn() { log "WARNING: $1"; }
# 检测是否在Docker容器中运行
is_docker_environment() {
# 检查多种Docker环境标识
if [[ -f /.dockerenv ]]; then
return 0
fi
if grep -q docker /proc/1/cgroup 2>/dev/null; then
return 0
fi
if grep -q lxc /proc/1/cgroup 2>/dev/null; then
return 0
fi
if [[ -n "${container:-}" ]]; then
return 0
fi
if [[ -n "${DOCKER_CONTAINER:-}" ]]; then
return 0
fi
# 检查容器相关的环境变量组合
local env_vars=(
"HOSTNAME"
"HOME"
"USER"
)
for var in "${env_vars[@]}"; do
if [[ -n "${!var:-}" ]] && [[ "${!var}" =~ ^[a-f0-9]{12,}$ ]]; then
# 检查环境变量值是否像容器ID
if [[ ${!var} =~ ^[a-f0-9]{12,64}$ ]]; then
return 0
fi
fi
done
return 1
}
# 获取适当的命令前缀在Docker中使用空前缀否则使用sudo
get_cmd_prefix() {
if is_docker_environment; then
echo ""
else
echo "sudo"
fi
}
# 配置加载
load_config() {
if [[ ! -f "$CONFIG_FILE" ]]; then
error "配置文件不存在: $CONFIG_FILE"
exit 1
fi
source "$CONFIG_FILE"
info "配置文件加载完成"
}
install_dependencies() {
info "安装系统依赖..."
local sudo_prefix
sudo_prefix=$(get_cmd_prefix)
local will_install_dependencies=false
local dependencies=(
"tar"
"gzip"
"bzip2"
"jq"
"gpg"
"bc"
)
for dep in "${dependencies[@]}"; do
if command -v "$dep" >/dev/null 2>&1; then
info "系统依赖 $dep 已安装"
else
warn "系统依赖 $dep 未安装"
will_install_dependencies=true
fi
done
if ! $will_install_dependencies; then
info "系统依赖已安装"
return 0
fi
# 关键依赖
local keys_deps=(
"coreutils"
"findutils"
"util-linux"
)
if command -v apt-get >/dev/null 2>&1; then
# Debian/Ubuntu
$sudo_prefix apt-get update
$sudo_prefix apt-get install -y $(printf "%s " "${keys_deps[@]}") $(printf "%s " "${dependencies[@]}")
elif command -v yum >/dev/null 2>&1; then
# CentOS/RHEL
$sudo_prefix yum install -y $(printf "%s " "${keys_deps[@]}") $(printf "%s " "${dependencies[@]}")
else
warn "无法自动安装依赖,请手动安装: $(printf "%s " "${keys_deps[@]}") $(printf "%s " "${dependencies[@]}")"
fi
# 安装GPG用于签名验证
if command -v apt-get >/dev/null 2>&1; then
$sudo_prefix apt-get install -y gnupg
elif command -v yum >/dev/null 2>&1; then
$sudo_prefix yum install -y gnupg
fi
}
create_directories() {
info "创建目录结构..."
local sudo_prefix
sudo_prefix=$(get_cmd_prefix)
$sudo_prefix mkdir -p "$INSTALL_DIR"
$sudo_prefix mkdir -p "/var/backups/patch"
$sudo_prefix mkdir -p "/var/log/patch_system"
$sudo_prefix mkdir -p "/etc/patch/keys"
# 设置权限
$sudo_prefix chmod 755 "$INSTALL_DIR"
$sudo_prefix chmod 755 "/var/backups/patch"
$sudo_prefix chmod 755 "/var/log/patch_system"
$sudo_prefix chmod 700 "/etc/patch/keys"
}
install_scripts() {
info "安装脚本文件..."
local sudo_prefix
sudo_prefix=$(get_cmd_prefix)
# 复制脚本文件, 存在则覆盖
$sudo_prefix cp --force "$SCRIPT_DIR/patch_generator.sh" "$INSTALL_DIR/"
$sudo_prefix cp --force "$SCRIPT_DIR/patch_fnc.sh" "$INSTALL_DIR/"
$sudo_prefix cp --force "$SCRIPT_DIR/patch_applier.sh" "$INSTALL_DIR/"
$sudo_prefix cp --force "$SCRIPT_DIR/patch_rollback.sh" "$INSTALL_DIR/"
$sudo_prefix cp --force "$SCRIPT_DIR/patch_verifier.sh" "$INSTALL_DIR/"
$sudo_prefix cp --force "$SCRIPT_DIR/patch_workflow.sh" "$INSTALL_DIR/"
$sudo_prefix cp --force "$SCRIPT_DIR/patch_config.sh" "$INSTALL_DIR/"
info "脚本文件已安装在: $INSTALL_DIR/"
# 设置执行权限
$sudo_prefix chmod +x "$INSTALL_DIR"/*.sh
# 创建符号链接
$sudo_prefix ln -sf "$INSTALL_DIR/patch_workflow.sh" "/usr/local/bin/patch-mgmt"
info "符号链接已创建: /usr/local/bin/patch-mgmt"
}
setup_cron() {
info "设置定时任务..."
if is_docker_environment; then
info "Docker环境跳过系统定时任务设置"
info "如需定时任务请考虑使用宿主机的crontab或Docker运行参数"
return 0
fi
local sudo_prefix
sudo_prefix=$(get_cmd_prefix)
local cron_job="0 2 * * * $INSTALL_DIR/patch_verifier.sh /opt/patches batch > /var/log/patch_system/batch_verify.log 2>&1"
if ! crontab -l 2>/dev/null | grep -q "patch_verifier.sh"; then
(crontab -l 2>/dev/null; echo "$cron_job") | crontab -
info "定时任务已添加"
else
info "定时任务已存在"
fi
}
generate_gpg_key() {
local name="${1:-John Doe}"
local email="${2:-johndoe@example.com}"
local key_type="${3:-RSA}"
local key_length="${4:-4096}"
cat > /tmp/gpg_batch << EOF
Key-Type: $key_type
Key-Length: $key_length
Subkey-Type: $key_type
Subkey-Length: $key_length
Name-Real: $name
Name-Email: $email
Expire-Date: 0
%commit
EOF
gpg --batch --generate-key /tmp/gpg_batch
rm -f /tmp/gpg_batch
echo "✅ 密钥生成完成"
gpg --list-secret-keys --keyid-format LONG "$email"
}
generate_keys() {
info "生成签名密钥..."
local key_dir="/etc/patch/keys"
local sudo_prefix
sudo_prefix=$(get_cmd_prefix)
if [[ ! -f "$key_dir/private.pem" ]]; then
$sudo_prefix mkdir -p "$key_dir"
# 生成GPG密钥对
generate_gpg_key "$PATCH_AUTHOR" "$PATCH_EMAIL" "RSA" "4096"
# 生成RSA密钥对
openssl genrsa -out "$key_dir/private.pem" 4096
openssl rsa -in "$key_dir/private.pem" -pubout -out "$key_dir/public.pem"
$sudo_prefix chmod 600 "$key_dir/private.pem"
$sudo_prefix chmod 644 "$key_dir/public.pem"
info "密钥对已生成: $key_dir/"
else
info "密钥对已存在"
fi
}
main() {
info "开始安装企业级补丁管理系统"
echo "========================================"
echo "📋 安装配置文件: $INSTALL_DIR/patch_config.sh"
# 加载配置
load_config
# 检查运行环境
if is_docker_environment; then
info "检测到Docker容器环境将以root权限执行不适用sudo"
SUDO_CMD=""
else
info "检测到主机环境将使用sudo执行管理员操作"
SUDO_CMD="sudo"
# 在非Docker环境中建议非root用户运行
if [[ $EUID -eq 0 ]]; then
warn "检测到以root用户运行建议在非Docker环境中使用具备sudo权限的普通用户"
fi
fi
# 安装依赖
install_dependencies
# 创建目录
create_directories
# 安装脚本
install_scripts
# 设置定时任务
setup_cron
# 生成密钥
generate_keys
info "🎉 补丁管理系统安装完成!"
echo ""
echo "📁 安装目录: $INSTALL_DIR"
echo "🔧 使用命令: patch-mgmt"
echo "📋 配置文件: $INSTALL_DIR/patch_config.sh"
echo ""
echo "💡 下一步操作:"
echo " 1. 编辑配置文件: $INSTALL_DIR/patch_config.sh"
echo " 2. 测试系统: patch-mgmt --help"
echo " 3. 配置通知: 修改SLACK_WEBHOOK等设置"
}
main "$@"