chore: 可以实现应用补丁及回滚操作

This commit is contained in:
2025-11-17 18:18:23 +08:00
parent 1426da2f8a
commit f76320f732
5 changed files with 1007 additions and 154 deletions

View File

@@ -89,7 +89,6 @@ install_dependencies() {
"jq"
"gpg"
"bc"
"gnupg"
)
for dep in "${dependencies[@]}"; do

View File

@@ -7,7 +7,9 @@ shopt -s nullglob extglob
# 脚本目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/patch_config.sh"
LOG_FILE="/var/log/patch_system/apply_$(date +%Y%m%d_%H%M%S).log"
LOCK_FILE="/tmp/patch_apply.lock"
ROLLBACK_INFO_DIR="/var/lib/patch_system/rollback_info"
# 颜色定义
RED='\033[0;31m'
@@ -53,21 +55,25 @@ load_config() {
# 设置默认值
: ${LOG_LEVEL:="INFO"}
: ${LOG_FILE:="/tmp/patch_apply_$(date +%Y%m%d_%H%M%S).log"}
: ${BACKUP_DIR:="/var/backups/patch"}
: ${TEMP_DIR:="/tmp/patch_apply_$$"}
: ${ROLLBACK_ENABLED:="true"}
: ${ROLLBACK_INFO_DIR:="/var/lib/patch_system/rollback_info"}
: ${VALIDATION_ENABLED:="true"}
: ${NOTIFICATIONS_ENABLED:="true"}
: ${ATOMIC_OPERATIONS:="true"}
: ${MAX_BACKUP_COUNT:=10}
: ${PATCH_STAGING_DIR:="/tmp/patch_staging"}
}
setup_environment() {
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$BACKUP_DIR"
mkdir -p "$TEMP_DIR"
mkdir -p "$ROLLBACK_INFO_DIR"
mkdir -p "$PATCH_STAGING_DIR"
info "环境设置完成"
info "日志文件: $LOG_FILE"
info "备份目录: $BACKUP_DIR"
info "临时目录: $TEMP_DIR"
@@ -127,7 +133,7 @@ trap cleanup EXIT INT TERM
# 依赖检查
check_dependencies() {
local deps=("tar" "gzip" "sha256sum" "cp" "mkdir" "find")
local deps=("tar" "gzip" "find" "stat" "sha256sum" "date" "mkdir" "cp" "jq")
local missing=()
for dep in "${deps[@]}"; do
@@ -639,6 +645,7 @@ create_rollback_point() {
local patch_file="$1"
local backup_file="$2"
local extract_dir="$3"
local changes_file="$4"
if [[ "$ROLLBACK_ENABLED" != "true" ]]; then
info "回滚功能已禁用"
@@ -647,31 +654,94 @@ create_rollback_point() {
info "🔄 创建回滚点..."
local rollback_info_file="$BACKUP_DIR/rollback_info.json"
local patch_name=$(basename "$patch_file")
local patch_name=$(basename "$patch_file" .tar.gz)
local timestamp=$(date +%Y%m%d_%H%M%S)
local rollback_info_file="$ROLLBACK_INFO_DIR/${patch_name}_${timestamp}.json"
# 读取清单信息
local manifest_file="$extract_dir/MANIFEST.MF"
local patch_info=""
if [[ -f "$manifest_file" ]]; then
patch_info=$(grep -E "^(名称|版本|描述):" "$manifest_file" | head -3)
patch_info=$(grep -E "^(名称|版本|描述):" "$manifest_file" | head -3 | tr '\n' ';')
fi
# 统计变更类型
local added_count=$(grep -c "^ADDED" "$changes_file")
local modified_count=$(grep -c "^MODIFIED" "$changes_file")
local deleted_count=$(grep -c "^DELETED" "$changes_file")
# 创建回滚信息JSON
local rollback_info=$(cat << EOF
{
"patch_name": "$patch_name",
"apply_time": "$(date -Iseconds)",
"backup_path": "$backup_file",
"rollback_dir": "$BACKUP_DIR/rollback_$timestamp",
"manifest_info": "$(echo "$patch_info" | tr '\n' ';')",
"status": "applied"
"manifest_info": "$patch_info",
"status": "applied",
"changes": {
"added": $added_count,
"modified": $modified_count,
"deleted": $deleted_count,
"total": $((added_count + modified_count + deleted_count))
},
"system_info": {
"hostname": "$(hostname)",
"user": "$(whoami)",
"working_directory": "$PWD"
}
}
EOF
)
echo "$rollback_info" > "$rollback_info_file"
info "✅ 回滚点创建完成: $rollback_info_file"
# 清理旧回滚点
cleanup_old_rollback_points
}
# 清理旧回滚点
cleanup_old_rollback_points() {
local max_points="${1:-$MAX_BACKUP_COUNT}"
info "🧹 清理旧回滚点 (保留最近 $max_points 个)"
if [[ ! -d "$ROLLBACK_INFO_DIR" ]]; then
return 0
fi
# 获取所有回滚点并按时间排序
local points=($(find "$ROLLBACK_INFO_DIR" -name "*.json" -type f -printf "%T@|%p\n" | sort -rn | cut -d'|' -f2))
local total_points=${#points[@]}
local points_to_remove=$((total_points - max_points))
if [[ $points_to_remove -le 0 ]]; then
debug "无需清理,当前 $total_points 个回滚点"
return 0
fi
info "清理 $points_to_remove 个旧回滚点"
for ((i=max_points; i<total_points; i++)); do
local old_file="${points[$i]}"
if [[ -f "$old_file" ]]; then
# 获取备份文件路径
local backup_path=$(jq -r '.backup_path // ""' "$old_file")
# 删除备份文件
if [[ -n "$backup_path" && -f "$backup_path" ]]; then
rm -f "$backup_path"
debug "删除备份文件: $(basename "$backup_path")"
fi
# 删除回滚信息文件
rm -f "$old_file"
info "🗑️ 清理回滚点: $(basename "$old_file")"
fi
done
info "✅ 回滚点清理完成"
}
# 发送通知
@@ -806,7 +876,7 @@ apply_patch() {
return 0
fi
# 创建备份
# 创建备份文件(非干跑模式)
local backup_file=""
if [[ "$dry_run" != "true" ]]; then
info ">>创建备份..."
@@ -834,7 +904,7 @@ apply_patch() {
# 创建回滚点
info ">>创建回滚点..."
create_rollback_point "$patch_file" "$backup_file" "$extract_dir"
create_rollback_point "$patch_file" "$backup_file" "$extract_dir" "$changes_file"
fi
send_notification "success" "$patch_file" "补丁应用成功"
@@ -854,6 +924,7 @@ usage() {
-v, --verbose 详细输出
-q, --quiet 安静模式
-h, --help 显示此帮助
-V, --version 显示版本
示例:
$0 patch.tar.gz # 应用补丁
@@ -870,6 +941,13 @@ usage() {
EOF
}
# 显示版本信息
show_version() {
echo "patch_applier.sh v2.0.0"
echo "企业级补丁应用系统"
echo "支持原子性操作、完整验证、智能回滚点创建"
}
# 主函数
main() {
local patch_file=""
@@ -910,6 +988,10 @@ main() {
usage
exit 0
;;
-V|--version)
show_version
exit 0
;;
-*)
error "未知选项: $1"
usage

View File

@@ -121,6 +121,7 @@ ENCRYPTION_IV="/etc/patch/keys/encryption.iv" # 加密初始化向量文件路
BACKUP_ENABLED=true # 是否启用备份
BACKUP_STRATEGY="full" # 备份策略full, incremental, differential
BACKUP_RETENTION_DAYS=30 # 备份保留天数
BACKUP_DIR="/var/backups/patch" # 备份目录
# ==============================================================================
# 回滚配置 - 定义是否启用自动回滚和回滚策略
@@ -130,6 +131,7 @@ BACKUP_RETENTION_DAYS=30 # 备份保留天数
ROLLBACK_ENABLED=true # 是否启用自动回滚
ROLLBACK_AUTO_GENERATE=true # 是否自动生成回滚脚本
ROLLBACK_STRATEGY="snapshot" # 回滚策略snapshot, restore
ROLLBACK_INFO_DIR="/var/lib/patch_system/rollback_info"
# ==============================================================================
# 通知配置 - 定义是否启用通知和通知渠道

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
<?php
use think\facade\Env;
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
return [
// 默认缓存驱动
'default' => Env::get('cache.driver', 'file'),
// 缓存连接方式配置
'stores' => [
'file' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => '',
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制 例如 ['serialize', 'unserialize']
'serialize' => [],
],
// redis缓存
'redis' => [
// 驱动方式
'type' => 'redis',
// 服务器地址
'host' => '127.0.0.1',
// redis密码
'password' => 'luckyshop123!@#',
// 缓存有效期 0表示永久缓存
'expire' => 604800,
],
// 更多的缓存连接
],
];