Problem: Backups accumulated on DR (73 files, 4 days) instead of keeping only 2 days - transfer_incremental.ps1 had no cleanup function (ran 2x/day without cleanup) - transfer_to_dr.ps1 cleanup had poor logging - oracle-backup-monitor-proxmox.sh couldn't detect new L0/L1 backup format Changes: - Add cleanup to transfer_incremental.ps1 (delete backups older than 2 days) - Improve cleanup logging in transfer_to_dr.ps1 (shows count before/after) - Update oracle-backup-monitor-proxmox.sh to detect both naming conventions: * Old: *FULL*.BKP, *INCR*.BKP * New: L0_*.BKP (Level 0), L1_*.BKP (Level 1) - Remove temporary files from /input/ directory Result: Monitor now correctly reports backup age, cleanup runs after each transfer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
214 lines
7.2 KiB
PowerShell
214 lines
7.2 KiB
PowerShell
# Transfer Oracle RMAN Backup towards DR Server
|
|
# Rulează după backup RMAN (03:00 AM)
|
|
# Copiază backup-uri de pe PRIMARY (10.0.20.36) către DR (10.0.20.37)
|
|
|
|
param(
|
|
[string]$SourceFRA = "C:\Users\Oracle\recovery_area\ROA",
|
|
[string]$DRHost = "10.0.20.202",
|
|
[int]$DRPort = 22,
|
|
[string]$DRUser = "root",
|
|
[string]$DRPath = "/mnt/pve/oracle-backups/ROA/autobackup",
|
|
[string]$SSHKeyPath = "$env:USERPROFILE\.ssh\id_rsa",
|
|
[int]$RetentionDays = 2,
|
|
[string]$LogFile = "D:\rman_backup\logs\transfer_$(Get-Date -Format 'yyyyMMdd').log"
|
|
)
|
|
|
|
$ErrorActionPreference = "Continue"
|
|
|
|
function Write-Log {
|
|
param([string]$Message, [string]$Level = "INFO")
|
|
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
$logLine = "[$timestamp] [$Level] $Message"
|
|
Write-Host $logLine
|
|
Add-Content -Path $LogFile -Value $logLine -Encoding UTF8 -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
function Test-SSHConnection {
|
|
Write-Log "Testing SSH connection to $DRHost`:$DRPort..."
|
|
|
|
try {
|
|
# Folosește -n pentru a nu citi din stdin (fix pentru blocare)
|
|
$null = & ssh -n -p $DRPort -i $SSHKeyPath -o StrictHostKeyChecking=no -o ConnectTimeout=10 "${DRUser}@${DRHost}" "exit 0" 2>&1
|
|
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Log "SSH connection successful" "SUCCESS"
|
|
return $true
|
|
} else {
|
|
Write-Log "SSH connection failed with exit code: $LASTEXITCODE" "ERROR"
|
|
return $false
|
|
}
|
|
} catch {
|
|
Write-Log "SSH connection error: $_" "ERROR"
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Get-TodaysBackups {
|
|
Write-Log "Searching for today's backup files..."
|
|
|
|
$today = Get-Date
|
|
$cutoffDate = $today.Date # Only today (after midnight)
|
|
$backupFiles = @()
|
|
|
|
$searchPaths = @(
|
|
"$SourceFRA\BACKUPSET",
|
|
"$SourceFRA\AUTOBACKUP"
|
|
)
|
|
|
|
foreach ($path in $searchPaths) {
|
|
if (Test-Path $path) {
|
|
# Get files created TODAY only (exclude old backups)
|
|
$files = Get-ChildItem -Path $path -Recurse -File -ErrorAction SilentlyContinue |
|
|
Where-Object {
|
|
$_.LastWriteTime -gt $cutoffDate -and
|
|
$_.Name -notlike "*__TAG_*" # Exclude old uncompressed backups
|
|
} |
|
|
Sort-Object LastWriteTime -Descending
|
|
|
|
$backupFiles += $files
|
|
}
|
|
}
|
|
|
|
if ($backupFiles.Count -eq 0) {
|
|
Write-Log "No backup files found for today!" "WARNING"
|
|
return @()
|
|
}
|
|
|
|
$totalSizeGB = ($backupFiles | Measure-Object -Property Length -Sum).Sum / 1GB
|
|
Write-Log "Found $($backupFiles.Count) files, total size: $([math]::Round($totalSizeGB, 2)) GB"
|
|
|
|
return $backupFiles
|
|
}
|
|
|
|
function Transfer-FileToDR {
|
|
param([System.IO.FileInfo]$File, [string]$DestPath)
|
|
|
|
$fileName = $File.Name
|
|
$fileSizeMB = [math]::Round($File.Length / 1MB, 2)
|
|
|
|
try {
|
|
# Check dacă fișierul există deja pe DR (skip duplicates) - Linux bash command
|
|
$checkCmd = "test -f '$DestPath/$fileName' && echo 'True' || echo 'False'"
|
|
$checkResult = & ssh -n -p $DRPort -i $SSHKeyPath "${DRUser}@${DRHost}" $checkCmd 2>&1
|
|
|
|
if ($checkResult -match "True") {
|
|
Write-Log "Skipping (already on DR): $fileName" "INFO"
|
|
return $true
|
|
}
|
|
|
|
Write-Log "Transferring: $fileName ($fileSizeMB MB)"
|
|
|
|
# SCP transfer - NO compression (files already compressed by RMAN)
|
|
# Use cipher aes128-gcm for better performance
|
|
$null = & scp -P $DRPort -i $SSHKeyPath -o StrictHostKeyChecking=no -o Compression=no -o Cipher=aes128-gcm@openssh.com $File.FullName "${DRUser}@${DRHost}:${DestPath}/" 2>&1
|
|
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Log "Transferred: $fileName" "SUCCESS"
|
|
return $true
|
|
} else {
|
|
Write-Log "Failed to transfer: $fileName (exit code: $LASTEXITCODE)" "ERROR"
|
|
return $false
|
|
}
|
|
} catch {
|
|
Write-Log "Transfer error for $fileName : $_" "ERROR"
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Cleanup-OldBackupsOnDR {
|
|
Write-Log "Cleaning up old backups on DR (keeping last $RetentionDays days)..."
|
|
|
|
try {
|
|
# Count fișiere înainte de cleanup
|
|
$countBefore = & ssh -n -p $DRPort -i $SSHKeyPath "${DRUser}@${DRHost}" "find '$DRPath' -name '*.BKP' -type f | wc -l" 2>&1
|
|
Write-Log "Backups before cleanup: $countBefore"
|
|
|
|
# Cleanup: șterge fișiere mai vechi de $RetentionDays zile - Linux find command
|
|
$cleanupCmd = "find '$DRPath' -name '*.BKP' -type f -mtime +$RetentionDays -delete 2>&1"
|
|
$result = & ssh -n -p $DRPort -i $SSHKeyPath "${DRUser}@${DRHost}" $cleanupCmd 2>&1
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Log "Cleanup warning: $result" "WARNING"
|
|
}
|
|
|
|
# Count fișiere după cleanup
|
|
$countAfter = & ssh -n -p $DRPort -i $SSHKeyPath "${DRUser}@${DRHost}" "find '$DRPath' -name '*.BKP' -type f | wc -l" 2>&1
|
|
$deleted = [int]$countBefore - [int]$countAfter
|
|
|
|
Write-Log "Cleanup completed: Deleted $deleted old backup files, $countAfter remaining"
|
|
} catch {
|
|
Write-Log "Cleanup error: $_" "WARNING"
|
|
}
|
|
}
|
|
|
|
# ==================== MAIN ====================
|
|
|
|
try {
|
|
Write-Log "========================================="
|
|
Write-Log "Oracle DR Backup Transfer Started"
|
|
Write-Log "========================================="
|
|
Write-Log "Source FRA: $SourceFRA"
|
|
Write-Log "DR Server: $DRHost"
|
|
Write-Log "DR Path: $DRPath"
|
|
|
|
# Verificare prerequisite
|
|
if (-not (Test-Path $SourceFRA)) {
|
|
throw "Source FRA path not found: $SourceFRA"
|
|
}
|
|
|
|
if (-not (Test-Path $SSHKeyPath)) {
|
|
throw "SSH key not found: $SSHKeyPath"
|
|
}
|
|
|
|
# Test SSH connection
|
|
if (-not (Test-SSHConnection)) {
|
|
throw "Cannot connect to DR server via SSH"
|
|
}
|
|
|
|
# Creare director pe DR - Linux mkdir command
|
|
Write-Log "Ensuring DR directory exists..."
|
|
$null = & ssh -n -p $DRPort -i $SSHKeyPath "${DRUser}@${DRHost}" "mkdir -p '$DRPath'" 2>&1
|
|
|
|
# Găsește backup-uri
|
|
$backupFiles = Get-TodaysBackups
|
|
|
|
if ($backupFiles.Count -eq 0) {
|
|
throw "No backup files to transfer!"
|
|
}
|
|
|
|
# Transfer fișiere
|
|
Write-Log "Starting file transfer..."
|
|
$successCount = 0
|
|
$failCount = 0
|
|
|
|
foreach ($file in $backupFiles) {
|
|
if (Transfer-FileToDR -File $file -DestPath $DRPath) {
|
|
$successCount++
|
|
} else {
|
|
$failCount++
|
|
}
|
|
}
|
|
|
|
Write-Log "Transfer summary: $successCount succeeded, $failCount failed"
|
|
|
|
if ($failCount -gt 0) {
|
|
Write-Log "Some transfers failed!" "WARNING"
|
|
}
|
|
|
|
# Cleanup old backups pe DR
|
|
Cleanup-OldBackupsOnDR
|
|
|
|
Write-Log "========================================="
|
|
Write-Log "DR Backup Transfer Completed Successfully"
|
|
Write-Log "========================================="
|
|
Write-Log "Files transferred: $successCount/$($backupFiles.Count)"
|
|
Write-Log "DR Server: ${DRHost}:${DRPath}"
|
|
|
|
exit 0
|
|
|
|
} catch {
|
|
Write-Log "CRITICAL ERROR: $($_.Exception.Message)" "ERROR"
|
|
Write-Log "Stack trace: $($_.ScriptStackTrace)" "ERROR"
|
|
exit 1
|
|
}
|