This commit is contained in:
2025-10-29 10:17:11 +00:00
parent fa20c5484e
commit a87f09d8d9

View File

@@ -16,13 +16,12 @@ param(
# Each job will automatically share the database load using DatabasesInParallel=Y # Each job will automatically share the database load using DatabasesInParallel=Y
# TODO: Log file management (don't just overwrite existing logs) # TODO: Log file management (don't just overwrite existing logs)
# TODO: Dynmically figure out MV channels and paths using Rubrik API
# TODO: See if there is way to query QueueDatabase during backup to monitor progress # TODO: See if there is way to query QueueDatabase during backup to monitor progress
$fullBackupDay = 'Thursday' $fullBackupDay = 'Thursday'
$fullBackupOverdueDays = 7 $fullBackupOverdueDays = 7
$instanceName = $SqlInstance.Split('\')[1] $instanceName = $SqlInstance.Split('\')[1]
$logFile = "C:\Rubrik\backup-multi-$instanceName.log" $logFile = "C:\Rubrik\logs\backup_$instanceName.log"
$SAFile = "C:\Rubrik\scripts\rbksql.xml" $SAFile = "C:\Rubrik\scripts\rbksql.xml"
function Write-Log($message, $jobId = "") { function Write-Log($message, $jobId = "") {
@@ -101,7 +100,13 @@ if ($clusterInstance) {
$query.var.filter = @(Get-RscType -Name Filter) $query.var.filter = @(Get-RscType -Name Filter)
$query.var.filter[0].field = "NAME_EXACT_MATCH" $query.var.filter[0].field = "NAME_EXACT_MATCH"
$query.var.filter[0].Texts = $mvName $query.var.filter[0].Texts = $mvName
$mvDetail = $query.Invoke().nodes[0] $mvResult = $query.Invoke()
if (-not $mvResult.nodes -or $mvResult.nodes.Count -eq 0) {
Write-Log "ERROR: Managed Volume '$mvName' not found. This may be due to insufficient permissions or the volume not existing."
Disconnect-Rsc
exit 1
}
$mvDetail = $mvResult.nodes[0]
Write-Log "Found Managed Volume: $($mvDetail.Name) (ID: $($mvDetail.Id), Status: $($mvDetail.hostDetail.Status), HostDetail Name: $($mvDetail.hostDetail.Name))" Write-Log "Found Managed Volume: $($mvDetail.Name) (ID: $($mvDetail.Id), Status: $($mvDetail.hostDetail.Status), HostDetail Name: $($mvDetail.hostDetail.Name))"
@@ -119,12 +124,19 @@ if ($clusterInstance) {
$query.Var.input.update.slaClientConfig.clientHostId = $newHost.Id $query.Var.input.update.slaClientConfig.clientHostId = $newHost.Id
$query.Var.input.update.slaClientConfig.channelHostMountPaths = $mvDetail.ClientConfig.ChannelHostMountPaths $query.Var.input.update.slaClientConfig.channelHostMountPaths = $mvDetail.ClientConfig.ChannelHostMountPaths
$query.Var.input.update.slaClientConfig.backupScriptCommand = $mvDetail.ClientConfig.BackupScript.ScriptCommand $query.Var.input.update.slaClientConfig.backupScriptCommand = $mvDetail.ClientConfig.BackupScript.ScriptCommand
$query.Var.input.update.slaClientConfig.preBackupScriptCommand = $mvDetail.ClientConfig.PreBackupScript.ScriptCommand
$query.Var.input.update.slaClientConfig.preBackupScriptTimeout = $mvDetail.ClientConfig.PreBackupScript.Timeout # Only set pre-backup script fields if a pre-backup script was configured
if ($mvDetail.ClientConfig.PreBackupScript.ScriptCommand) {
$query.Var.input.update.slaClientConfig.preBackupScriptCommand = $mvDetail.ClientConfig.PreBackupScript.ScriptCommand
$query.Var.input.update.slaClientConfig.preBackupScriptTimeout = $mvDetail.ClientConfig.PreBackupScript.Timeout
$query.Var.input.update.slaClientConfig.shouldCancelBackupOnPreBackupScriptFailure = $mvDetail.ClientConfig.ShouldCancelBackupOnPreBackupScriptFailure
$query.Var.input.update.slaClientConfig.shouldDisablePreBackupScript = $false
} else {
$query.Var.input.update.slaClientConfig.shouldDisablePreBackupScript = $true
}
$query.Var.input.update.slaClientConfig.shouldDisablePostBackupScriptOnBackupFailure = $true $query.Var.input.update.slaClientConfig.shouldDisablePostBackupScriptOnBackupFailure = $true
$query.Var.input.update.slaClientConfig.shouldDisablePostBackupScriptOnBackupSuccess = $true $query.Var.input.update.slaClientConfig.shouldDisablePostBackupScriptOnBackupSuccess = $true
$query.Var.input.update.slaClientConfig.shouldDisablePreBackupScript = $false
$query.Var.input.update.slaClientConfig.shouldCancelBackupOnPreBackupScriptFailure = $mvDetail.ClientConfig.ShouldCancelBackupOnPreBackupScriptFailure
$query.gqlRequest().Variables $query.gqlRequest().Variables
@@ -155,9 +167,14 @@ try {
$query.var.filter = @(Get-RscType -Name Filter) $query.var.filter = @(Get-RscType -Name Filter)
$query.var.filter[0].field = "NAME_EXACT_MATCH" $query.var.filter[0].field = "NAME_EXACT_MATCH"
$query.var.filter[0].Texts = $MvName $query.var.filter[0].Texts = $MvName
$mvDetail = $query.Invoke().nodes[0] $mvDetail = $query.Invoke()
$paths = $mvDetail.ClientConfig.ChannelHostMountPaths if (-not $mvDetail.nodes -or $mvDetail.nodes.Count -eq 0) {
Write-Log "ERROR: Managed Volume '$MvName' not found. This may be due to insufficient permissions or the volume not existing."
exit 1
}
$paths = $mvDetail.nodes[0].ClientConfig.ChannelHostMountPaths
Write-Log "INFO: Retrieved paths: $($paths -join ', ')" Write-Log "INFO: Retrieved paths: $($paths -join ', ')"
} catch { } catch {
Write-Log "ERROR: Failed to retrieve paths from Rubrik. $($_.Exception.Message)" Write-Log "ERROR: Failed to retrieve paths from Rubrik. $($_.Exception.Message)"
@@ -208,7 +225,13 @@ function Get-BackupType($directoryParam) {
if (-not (Test-Path $flagDir)) { if (-not (Test-Path $flagDir)) {
New-Item -ItemType Directory -Path $flagDir -Force | Out-Null New-Item -ItemType Directory -Path $flagDir -Force | Out-Null
} }
Set-Content $fullFlag $today.ToString("yyyy-MM-dd") -Encoding UTF8 try {
Set-Content $fullFlag $today.ToString("yyyy-MM-dd") -Encoding UTF8
Write-Log "INFO: Created full backup flag file: $fullFlag"
} catch {
Write-Log "ERROR: Failed to create full backup flag file: $fullFlag. $($_.Exception.Message)"
# Continue with backup but flag won't be set
}
$reason = if($isFullBackupOverdue) { "overdue" } else { "scheduled" } $reason = if($isFullBackupOverdue) { "overdue" } else { "scheduled" }
return @{ Type = "FULL"; CleanupTime = 168; Reason = $reason } return @{ Type = "FULL"; CleanupTime = 168; Reason = $reason }
} else { } else {
@@ -221,7 +244,13 @@ function Get-BackupType($directoryParam) {
if (-not (Test-Path $flagDir)) { if (-not (Test-Path $flagDir)) {
New-Item -ItemType Directory -Path $flagDir -Force | Out-Null New-Item -ItemType Directory -Path $flagDir -Force | Out-Null
} }
Set-Content $diffFlag $today.ToString("yyyy-MM-dd") -Encoding UTF8 try {
Set-Content $diffFlag $today.ToString("yyyy-MM-dd") -Encoding UTF8
Write-Log "INFO: Created diff backup flag file: $diffFlag"
} catch {
Write-Log "ERROR: Failed to create diff backup flag file: $diffFlag. $($_.Exception.Message)"
# Continue with backup but flag won't be set
}
return @{ Type = "DIFF"; CleanupTime = 168; Reason = "differential scheduled" } return @{ Type = "DIFF"; CleanupTime = 168; Reason = "differential scheduled" }
} else { } else {
return @{ Type = "LOG"; CleanupTime = 24; Reason = "diff already taken today" } return @{ Type = "LOG"; CleanupTime = 24; Reason = "diff already taken today" }
@@ -425,7 +454,7 @@ for ($i = 1; $i -le $Jobs; $i++) {
$job = Start-BackupJob -jobId $i -sqlInstance $SqlInstance -query $query -baseLogFile $logFile $job = Start-BackupJob -jobId $i -sqlInstance $SqlInstance -query $query -baseLogFile $logFile
$null = $jobList.Add($job) $null = $jobList.Add($job)
Write-Log "Started backup job $i (Job ID: $($job.Id))" Write-Log "Started backup job $i (Job ID: $($job.Id))"
Start-Sleep -Milliseconds 100 # Small delay to stagger job starts Start-Sleep -Milliseconds 4000 # Delay to stagger job starts
} }
# Monitor jobs and capture output # Monitor jobs and capture output
@@ -520,26 +549,26 @@ foreach ($job in $jobList) {
} }
# Consolidate job logs into main log file # Consolidate job logs into main log file
Write-Log "Consolidating job logs..." #Write-Log "Consolidating job logs..."
for ($i = 1; $i -le $Jobs; $i++) { #for ($i = 1; $i -le $Jobs; $i++) {
$jobLogFile = $logFile -replace '\.log$', "-job$i.log" # $jobLogFile = $logFile -replace '\.log$', "-job$i.log"
Write-Log "Checking for job log file: $jobLogFile" # Write-Log "Checking for job log file: $jobLogFile"
if (Test-Path $jobLogFile) { # if (Test-Path $jobLogFile) {
try { # try {
$jobContent = Get-Content $jobLogFile -ErrorAction Stop # $jobContent = Get-Content $jobLogFile -ErrorAction Stop
Write-Log "Found $($jobContent.Count) lines in job $i log" # Write-Log "Found $($jobContent.Count) lines in job $i log"
foreach ($line in $jobContent) { # foreach ($line in $jobContent) {
Add-Content -Path $logFile -Value $line -Encoding UTF8 # Add-Content -Path $logFile -Value $line -Encoding UTF8
} # }
Remove-Item $jobLogFile -Force # # Remove-Item $jobLogFile -Force
Write-Log "Consolidated log from job $i" # Write-Log "Consolidated log from job $i"
} catch { # } catch {
Write-Log "WARNING: Could not consolidate log from job $i : $($_.Exception.Message)" # Write-Log "WARNING: Could not consolidate log from job $i : $($_.Exception.Message)"
} # }
} else { # } else {
Write-Log "WARNING: Job log file not found for job $i" # Write-Log "WARNING: Job log file not found for job $i"
} # }
} #}
# Final status check using job output analysis # Final status check using job output analysis
$failedJobIds = $jobResults.Keys | Where-Object { $jobResults[$_].Failed -eq $true } $failedJobIds = $jobResults.Keys | Where-Object { $jobResults[$_].Failed -eq $true }