feat: backup all databases for mysql,mariadb,postgresql

This commit is contained in:
Andras Bacsai
2024-10-03 12:39:45 +02:00
parent bb6cb8edc9
commit 1c7ca56756
4 changed files with 88 additions and 25 deletions

View File

@@ -243,6 +243,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
try { try {
if (str($databaseType)->contains('postgres')) { if (str($databaseType)->contains('postgres')) {
$this->backup_file = "/pg-dump-$database-".Carbon::now()->timestamp.'.dmp'; $this->backup_file = "/pg-dump-$database-".Carbon::now()->timestamp.'.dmp';
if ($this->backup->dump_all) {
$this->backup_file = '/pg-dump-all-'.Carbon::now()->timestamp.'.gz';
}
$this->backup_location = $this->backup_dir.$this->backup_file; $this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([ $this->backup_log = ScheduledDatabaseBackupExecution::create([
'database_name' => $database, 'database_name' => $database,
@@ -271,6 +274,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$this->backup_standalone_mongodb($database); $this->backup_standalone_mongodb($database);
} elseif (str($databaseType)->contains('mysql')) { } elseif (str($databaseType)->contains('mysql')) {
$this->backup_file = "/mysql-dump-$database-".Carbon::now()->timestamp.'.dmp'; $this->backup_file = "/mysql-dump-$database-".Carbon::now()->timestamp.'.dmp';
if ($this->backup->dump_all) {
$this->backup_file = '/mysql-dump-all-'.Carbon::now()->timestamp.'.gz';
}
$this->backup_location = $this->backup_dir.$this->backup_file; $this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([ $this->backup_log = ScheduledDatabaseBackupExecution::create([
'database_name' => $database, 'database_name' => $database,
@@ -280,6 +286,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$this->backup_standalone_mysql($database); $this->backup_standalone_mysql($database);
} elseif (str($databaseType)->contains('mariadb')) { } elseif (str($databaseType)->contains('mariadb')) {
$this->backup_file = "/mariadb-dump-$database-".Carbon::now()->timestamp.'.dmp'; $this->backup_file = "/mariadb-dump-$database-".Carbon::now()->timestamp.'.dmp';
if ($this->backup->dump_all) {
$this->backup_file = '/mariadb-dump-all-'.Carbon::now()->timestamp.'.gz';
}
$this->backup_location = $this->backup_dir.$this->backup_file; $this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([ $this->backup_log = ScheduledDatabaseBackupExecution::create([
'database_name' => $database, 'database_name' => $database,
@@ -379,7 +388,11 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
if ($this->postgres_password) { if ($this->postgres_password) {
$backupCommand .= " -e PGPASSWORD=$this->postgres_password"; $backupCommand .= " -e PGPASSWORD=$this->postgres_password";
} }
$backupCommand .= " $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location"; if ($this->backup->dump_all) {
$backupCommand .= " $this->container_name pg_dumpall --username {$this->database->postgres_user} | gzip > $this->backup_location";
} else {
$backupCommand .= " $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location";
}
$commands[] = $backupCommand; $commands[] = $backupCommand;
ray($commands); ray($commands);
@@ -400,8 +413,11 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
{ {
try { try {
$commands[] = 'mkdir -p '.$this->backup_dir; $commands[] = 'mkdir -p '.$this->backup_dir;
$commands[] = "docker exec $this->container_name mysqldump -u root -p{$this->database->mysql_root_password} $database > $this->backup_location"; if ($this->backup->dump_all) {
ray($commands); $commands[] = "docker exec $this->container_name mysqldump -u root -p{$this->database->mysql_root_password} --all-databases --single-transaction --quick --lock-tables=false --compress | gzip > $this->backup_location";
} else {
$commands[] = "docker exec $this->container_name mysqldump -u root -p{$this->database->mysql_root_password} $database > $this->backup_location";
}
$this->backup_output = instant_remote_process($commands, $this->server); $this->backup_output = instant_remote_process($commands, $this->server);
$this->backup_output = trim($this->backup_output); $this->backup_output = trim($this->backup_output);
if ($this->backup_output === '') { if ($this->backup_output === '') {
@@ -419,7 +435,11 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
{ {
try { try {
$commands[] = 'mkdir -p '.$this->backup_dir; $commands[] = 'mkdir -p '.$this->backup_dir;
$commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} $database > $this->backup_location"; if ($this->backup->dump_all) {
$commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} --all-databases --single-transaction --quick --lock-tables=false --compress > $this->backup_location";
} else {
$commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} $database > $this->backup_location";
}
ray($commands); ray($commands);
$this->backup_output = instant_remote_process($commands, $this->server); $this->backup_output = instant_remote_process($commands, $this->server);
$this->backup_output = trim($this->backup_output); $this->backup_output = trim($this->backup_output);

View File

@@ -31,6 +31,7 @@ class BackupEdit extends Component
'backup.save_s3' => 'required|boolean', 'backup.save_s3' => 'required|boolean',
'backup.s3_storage_id' => 'nullable|integer', 'backup.s3_storage_id' => 'nullable|integer',
'backup.databases_to_backup' => 'nullable', 'backup.databases_to_backup' => 'nullable',
'backup.dump_all' => 'required|boolean',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@@ -40,6 +41,7 @@ class BackupEdit extends Component
'backup.save_s3' => 'Save to S3', 'backup.save_s3' => 'Save to S3',
'backup.s3_storage_id' => 'S3 Storage', 'backup.s3_storage_id' => 'S3 Storage',
'backup.databases_to_backup' => 'Databases to Backup', 'backup.databases_to_backup' => 'Databases to Backup',
'backup.dump_all' => 'Backup All Databases',
]; ];
protected $messages = [ protected $messages = [

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('scheduled_database_backups', function (Blueprint $table) {
$table->boolean('dump_all')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('scheduled_database_backups', function (Blueprint $table) {
$table->dropColumn('dump_all');
});
}
};

View File

@@ -8,17 +8,14 @@
<livewire:project.database.backup-now :backup="$backup" /> <livewire:project.database.backup-now :backup="$backup" />
@endif @endif
@if ($backup->database_id !== 0) @if ($backup->database_id !== 0)
<x-modal-confirmation <x-modal-confirmation title="Confirm Backup Schedule Deletion?" buttonTitle="Delete Backups and Schedule"
title="Confirm Backup Schedule Deletion?" isErrorButton submitAction="delete" :checkboxes="$checkboxes" :actions="[
buttonTitle="Delete Backups and Schedule" 'The selected backup schedule will be deleted.',
isErrorButton 'Scheduled backups for this database will be stopped (if this is the only backup schedule for this database).',
submitAction="delete" ]"
:checkboxes="$checkboxes" confirmationText="{{ $backup->database->name }}"
:actions="['The selected backup schedule will be deleted.', 'Scheduled backups for this database will be stopped (if this is the only backup schedule for this database).']" confirmationLabel="Please confirm the execution of the actions by entering the Database Name of the scheduled backups below"
confirmationText="{{ $backup->database->name }}" shortConfirmationLabel="Database Name" />
confirmationLabel="Please confirm the execution of the actions by entering the Database Name of the scheduled backups below"
shortConfirmationLabel="Database Name"
/>
@endif @endif
</div> </div>
<div class="w-48 pb-2"> <div class="w-48 pb-2">
@@ -36,23 +33,39 @@
</div> </div>
@endif @endif
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<div class="flex gap-2"> <h3>Settings</h3>
<div class="flex gap-2 flex-col ">
@if ($backup->database_type === 'App\Models\StandalonePostgresql') @if ($backup->database_type === 'App\Models\StandalonePostgresql')
<x-forms.input label="Databases To Backup" <div class="w-48">
helper="Comma separated list of databases to backup. Empty will include the default one." <x-forms.checkbox label="Backup All Databases" id="backup.dump_all" instantSave />
id="backup.databases_to_backup" /> </div>
@if (!$backup->dump_all)
<x-forms.input label="Databases To Backup"
helper="Comma separated list of databases to backup. Empty will include the default one."
id="backup.databases_to_backup" />
@endif
@elseif($backup->database_type === 'App\Models\StandaloneMongodb') @elseif($backup->database_type === 'App\Models\StandaloneMongodb')
<x-forms.input label="Databases To Include" <x-forms.input label="Databases To Include"
helper="A list of databases to backup. You can specify which collection(s) per database to exclude from the backup. Empty will include all databases and collections.<br><br>Example:<br><br>database1:collection1,collection2|database2:collection3,collection4<br><br> database1 will include all collections except collection1 and collection2. <br>database2 will include all collections except collection3 and collection4.<br><br>Another Example:<br><br>database1:collection1|database2<br><br> database1 will include all collections except collection1.<br>database2 will include ALL collections." helper="A list of databases to backup. You can specify which collection(s) per database to exclude from the backup. Empty will include all databases and collections.<br><br>Example:<br><br>database1:collection1,collection2|database2:collection3,collection4<br><br> database1 will include all collections except collection1 and collection2. <br>database2 will include all collections except collection3 and collection4.<br><br>Another Example:<br><br>database1:collection1|database2<br><br> database1 will include all collections except collection1.<br>database2 will include ALL collections."
id="backup.databases_to_backup" /> id="backup.databases_to_backup" />
@elseif($backup->database_type === 'App\Models\StandaloneMysql') @elseif($backup->database_type === 'App\Models\StandaloneMysql')
<x-forms.input label="Databases To Backup" <div class="w-48">
helper="Comma separated list of databases to backup. Empty will include the default one." <x-forms.checkbox label="Backup All Databases" id="backup.dump_all" instantSave />
id="backup.databases_to_backup" /> </div>
@if (!$backup->dump_all)
<x-forms.input label="Databases To Backup"
helper="Comma separated list of databases to backup. Empty will include the default one."
id="backup.databases_to_backup" />
@endif
@elseif($backup->database_type === 'App\Models\StandaloneMariadb') @elseif($backup->database_type === 'App\Models\StandaloneMariadb')
<x-forms.input label="Databases To Backup" <div class="w-48">
helper="Comma separated list of databases to backup. Empty will include the default one." <x-forms.checkbox label="Backup All Databases" id="backup.dump_all" instantSave />
id="backup.databases_to_backup" /> </div>
@if (!$backup->dump_all)
<x-forms.input label="Databases To Backup"
helper="Comma separated list of databases to backup. Empty will include the default one."
id="backup.databases_to_backup" />
@endif
@endif @endif
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">