mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-12 15:53:46 -04:00
fix(backups): accept tar exit code 1 in volume backups
GNU tar exits with 1 when a file changes while it is read. The archive is still valid, so only exit codes above 1 fail the backup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
44774f7b93
commit
449d099bd3
@@ -92,8 +92,7 @@ class VolumeBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
? 'docker volume inspect '.escapeshellarg($source).' >/dev/null'
|
||||
: 'test -d '.escapeshellarg($source);
|
||||
|
||||
$compressorCommand = BackupCompression::compressorCommand($compressionCpuPercentage);
|
||||
$archiveScript = "compressor=\$({$compressorCommand}); tar -I \"\$compressor\" -cf - -C /volume .";
|
||||
$archiveScript = self::archiveScript($compressionCpuPercentage);
|
||||
if ($streamToS3) {
|
||||
$this->execution->update(['local_storage_deleted' => true]);
|
||||
$archiveCommand = $this->streamToS3Command($archiveScript, $backupLocation, $source, $containerName, $image);
|
||||
@@ -289,8 +288,16 @@ class VolumeBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
* GNU tar exits with 1 when a file changes while it is read (for example, an app that writes to the volume
|
||||
* during a live backup). The archive is still valid, so only exit codes above 1 fail the backup.
|
||||
*/
|
||||
public static function archiveScript(int $compressionCpuPercentage): string
|
||||
{
|
||||
$compressorCommand = BackupCompression::compressorCommand($compressionCpuPercentage);
|
||||
|
||||
return "compressor=\$({$compressorCommand}); { tar -I \"\$compressor\" -cf - -C /volume . || { status=\$?; [ \$status -eq 1 ] || exit \$status; }; }";
|
||||
}
|
||||
|
||||
/**
|
||||
* Containers can exit and be removed (e.g. `--rm` backup helpers) between `docker ps` and
|
||||
* `docker inspect`. Skip those, but still fail when an existing container cannot be inspected.
|
||||
|
||||
@@ -2969,3 +2969,22 @@ it('records a missed volume backup that is too old to run late as a failed execu
|
||||
Notification::assertSentToTimes($team, BackupFailed::class, 1);
|
||||
Notification::assertSentTo($team, BackupFailed::class, fn (BackupFailed $notification) => $notification->output === 'Skipped: the queued job did not start within 60 minutes.');
|
||||
});
|
||||
|
||||
it('fails the volume archive only on fatal tar errors', function (int $tarExitCode, int $expectedExitCode) {
|
||||
$bin = sys_get_temp_dir().'/volume-backup-tar-'.uniqid();
|
||||
mkdir($bin);
|
||||
file_put_contents($bin.'/tar', "#!/bin/sh\nexit {$tarExitCode}\n");
|
||||
chmod($bin.'/tar', 0755);
|
||||
|
||||
$result = Process::env(['PATH' => $bin.':/usr/bin:/bin'])
|
||||
->run(['sh', '-c', VolumeBackupJob::archiveScript(50)]);
|
||||
|
||||
unlink($bin.'/tar');
|
||||
rmdir($bin);
|
||||
|
||||
expect($result->exitCode())->toBe($expectedExitCode);
|
||||
})->with([
|
||||
'success' => [0, 0],
|
||||
'file changed as we read it' => [1, 0],
|
||||
'fatal error' => [2, 2],
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user