svn 部署与备份

一、 部署 SVN

1.1 安装

yum install subversion httpd mod_dav_svn

1.2 创建仓库

创建test测试仓库
mkdir -p /var/svn/repos/test
svnadmin create /var/svn/repos/test

二、 配置 SVN

2.1. 配置httpd

创建文件 /etc/httpd/conf.d/subversion.conf 添加如下内容;

<Location /svn>
DAV svn
SVNParentPath /var/svn/repos
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/svn-auth-users
Require valid-user
</Location>

2.2 配置身份验证

htpasswd -cm /etc/svn-auth-users username

后续添加用户: htpasswd -m /etc/svn-auth-users anotheruser

2.3 开启服务

firewall-cmd --permanent --add-service=http
firewall-cmd --reload
systemtcl enable svnserve --now
systemctl enable httpd --now

2.4 访问SVN

http://your_server_ip/svn/your_svn_repos

2.5 svn目录权限修改

/var/svn/repos/test 的权限需要修改成 httpd的用户apache, 否则svn客户端无法上传文件

chown -R apache:apache /var/svn/repos/test

三、 全量备份

#!/bin/bash

#===============================================================================
# Script Name: svn_backup_full.sh
# Description: svn repos full backup
# keep recent 3 backups
#
#
# Author: Wang Huaizhuang
# Email: [email protected]
# Created Date: 2024-12-12
# Last Modified: 2024-12-17
# Version: 1.0
#
# Usage: ./svn_backup_full.sh
#
#
# Requirements: - pigz
# - gzip
#
# Notes: Special considerations or limitations of the script
# - Make sure there is enough space on your servers
# - A temp dir will be created during the backup process
#
#
# License: GPL
#===============================================================================

SVN_REPOS_PATH="/var/svn/repos"
BACKUP_BASE_DIR="/var/svn_backup"
LOG_DIR="/var/log/svnbackup"
BACKUP_TMP_DIR="/var/svn_backup/tmp"
DATE=$(date +"%Y%m%d")
LOGFILE="$LOG_DIR/svn_backup_${DATE}.log"

# Create necessary directories
if [ ! -d "$BACKUP_BASE_DIR" ]; then mkdir -p $BACKUP_BASE_DIR; fi
if [ ! -d "$BACKUP_TMP_DIR" ]; then mkdir -p $BACKUP_TMP_DIR; fi
if [ ! -d "$LOG_DIR" ]; then mkdir -p $LOG_DIR; fi

# Initialize statistics variables
TOTAL_REPOS=0
SUCCESSFUL_BACKUPS=0
FAILED_BACKUPS=0
NOT_UPDATE=0

# Logging function with timestamp
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOGFILE"
}

# Make sure backup is required
should_backup() {
local repo="$1"
local curr_version
curr_version=$(svnlook youngest "$SVN_REPOS_PATH/$repo")

local recent_backups
recent_backups=$(find "$BACKUP_BASE_DIR/$repo" -name "${repo}-*-full-*.tar.gz" | sort -r)

# Check if any of these backups contain the current revision
for backup_file in $recent_backups; do
if [[ "$backup_file" == *"full-${curr_version}"* ]]; then ((NOT_UPDATE++))
return 1 # No backup needed
fi
done

return 0 # Backup needed
}

# SVN full backup function
full_backup() {
# Get list of SVN repos
mapfile -t REPOS < <(ls "$SVN_REPOS_PATH")
TOTAL_REPOS=${#REPOS[@]}

log "============ STARTING BACKUP ==============="
log "Total number of SVN repositories: $TOTAL_REPOS"

# For each SVN repos
for repo in "${REPOS[@]}"; do
if ! should_backup "$repo"; then
log "Repository: $repo - No updates, skipping backup"
continue
fi

mkdir -p "$BACKUP_TMP_DIR/$repo"
mkdir -p "$BACKUP_BASE_DIR/$repo"
latest_revision=$(svnlook youngest "$SVN_REPOS_PATH/$repo")
backup_filename="${repo}-${DATE}-full-${latest_revision}.tar.gz"

log "Starting backup for repository: $repo"

if (
svnadmin hotcopy "$SVN_REPOS_PATH/$repo" "$BACKUP_TMP_DIR/$repo" &&
tar -c "$BACKUP_TMP_DIR/$repo" | pigz -9 -p 8 > "$BACKUP_BASE_DIR/$repo/$backup_filename" &&
# Delete temp file
rm -rf "$BACKUP_TMP_DIR/$repo"
); then
((SUCCESSFUL_BACKUPS++))
log "Repository: $repo - Backup Succeeded: $backup_filename (Revision: $latest_revision)"
else
((FAILED_BACKUPS++))
log "ERROR: Repository: $repo - Backup Failed!"
svnlook youngest "$SVN_REPOS_PATH/$repo" || log "Cannot retrieve revision"
fi
done
}

# Cleanup old backups
cleanup_old_backups() {
log "============ STARTING CLEATUP =============="

# Check backup dir
[[ -d "$BACKUP_BASE_DIR" ]] || {
log "Backup directory $BACKUP_BASE_DIR does not exist"
return 1
}

# For each SVN repos
for repo_dir in "$BACKUP_BASE_DIR"/*; do
# make sure dir exsit and not empty
[[ -d "$repo_dir" && -n "$(ls -A "$repo_dir")" ]] || continue

# get all backups, sort by time
local repo_name=$(basename "$repo_dir")
local -a full_backups=()

while IFS= read -r -d '' backup; do
full_backups+=("$backup")
done < <(find "$repo_dir" -maxdepth 1 -type f -name "*-full-*.tar.gz" -print0 | sort -zr)

# keep 3 backups
local backup_count=${#full_backups[@]}
if [[ $backup_count -gt 3 ]]; then
for ((i=3; i<backup_count; i++)); do
log "Removing old backup for $repo_name: ${full_backups[i]}"
rm -f "${full_backups[i]}"
done
log "Removed $((backup_count - 3)) old backups for $repo_name"
else
log "Keeping all $backup_count backups for $repo_name"
fi
done

log "Old backups cleanup completed"
}

# Generate backup summary
generate_backup_report() {

log "============ BACKUP SUMMARY ================="
log "Total repositories: $TOTAL_REPOS"
log "Not update repositories: $NOT_UPDATE"
log "Successful backups: $SUCCESSFUL_BACKUPS"
log "Failed backups: $FAILED_BACKUPS"

# Optional: Add alert mechanism for failed backups
if [ $FAILED_BACKUPS -gt 0 ]; then
log "WARNING: Some backups failed. Please check repositories."
# Uncomment and implement your alert mechanism if needed
# send_alert "SVN backup partial failure: $FAILED_BACKUPS / $TOTAL_REPOS"
fi
}

main() {
log "SVN Full Backup Starting"
full_backup
cleanup_old_backups
generate_backup_report
log "SVN Full Backup Completed"
}

# Execute backup
main