diff --git a/web/app/BackupStorage.php b/web/app/BackupStorage.php index 468177a..cf827cf 100644 --- a/web/app/BackupStorage.php +++ b/web/app/BackupStorage.php @@ -9,40 +9,9 @@ use Illuminate\Support\Str; class BackupStorage { - public static function getDomainPath($domainId) - { - $findDomain = Domain::where('id', $domainId)->first(); - if ($findDomain) { - return $findDomain->domain_root . '/backups'; - } - - return false; - } - public static function getDomainInstance($domainId) - { - $domainPath = self::getDomainPath($domainId); - - if ($domainPath) { - $storageBuild = Storage::build([ - 'driver' => 'local', - 'root' => $domainPath, - ]); - $storageBuild->buildTemporaryUrlsUsing(function ($path, $expiration, $options) { - return URL::temporarySignedRoute( - 'backup.download', - $expiration, - array_merge($options, ['path' => $path]) - ); - }); - return $storageBuild; - } - - return false; - } - public static function getPath() { - $rootPath = storage_path('app'); + $rootPath = '/var/lib/phyre/backups/system'; $customBackupPath = setting('general.backup_path'); if (!empty($customBackupPath)) { $rootPath = $customBackupPath; diff --git a/web/app/Console/Commands/CreateDailyFullHostingSubscriptionsBackup.php b/web/app/Console/Commands/CreateDailyFullHostingSubscriptionsBackup.php index b54ca20..0018bad 100644 --- a/web/app/Console/Commands/CreateDailyFullHostingSubscriptionsBackup.php +++ b/web/app/Console/Commands/CreateDailyFullHostingSubscriptionsBackup.php @@ -4,11 +4,16 @@ namespace App\Console\Commands; use App\Models\Backup; use App\Models\HostingSubscription; +use App\Models\HostingSubscriptionBackup; use Carbon\Carbon; use Illuminate\Console\Command; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Migrations\Migration; + + + class CreateDailyFullHostingSubscriptionsBackup extends Command { /** @@ -30,7 +35,27 @@ class CreateDailyFullHostingSubscriptionsBackup extends Command */ public function handle() { + // Find Hosting Subscriptions + $findHostingSubscriptions = HostingSubscription::limit(1)->get(); + if ($findHostingSubscriptions->count() > 0) { + foreach ($findHostingSubscriptions as $hostingSubscription) { + $findBackup = HostingSubscriptionBackup::where('hosting_subscription_id', $hostingSubscription->id) + ->where('backup_type', 'full') + ->where('created_at', '>=', Carbon::now()->subHours(24)) + ->first(); + if (! $findBackup) { + $backup = new HostingSubscriptionBackup(); + $backup->hosting_subscription_id = $hostingSubscription->id; + $backup->backup_type = 'full'; + $backup->save(); + + } else { + $this->error('Backup already exists for ' . $hostingSubscription->domain); + $this->error('Created before: ' . $findBackup->created_at->diffForHumans()); + } + } + } } } diff --git a/web/app/Console/Commands/RunHostingSubscriptionsBackupChecks.php b/web/app/Console/Commands/RunHostingSubscriptionsBackupChecks.php index b4853c3..40ac3aa 100644 --- a/web/app/Console/Commands/RunHostingSubscriptionsBackupChecks.php +++ b/web/app/Console/Commands/RunHostingSubscriptionsBackupChecks.php @@ -37,28 +37,6 @@ class RunHostingSubscriptionsBackupChecks extends Command $backup->delete(); } -// // Find Hosting Subscriptions -// $findHostingSubscriptions = HostingSubscription::all(); -// if ($findHostingSubscriptions->count() > 0) { -// foreach ($findHostingSubscriptions as $hostingSubscription) { -// -// $findBackup = HostingSubscriptionBackup::where('hosting_subscription_id', $hostingSubscription->id) -// ->where('backup_type', 'full') -// ->where('created_at', '>=', Carbon::now()->subHours(24)) -// ->first(); -// if (! $findBackup) { -// $backup = new HostingSubscriptionBackup(); -// $backup->hosting_subscription_id = $hostingSubscription->id; -// $backup->backup_type = 'full'; -// $backup->save(); -// } else { -// $this->error('Backup already exists for ' . $hostingSubscription->domain); -// $this->error('Created before: ' . $findBackup->created_at->diffForHumans()); -// } -// } -// } - - // Check for pending backups $getPendingBackups = HostingSubscriptionBackup::where('status', 'pending') ->get(); diff --git a/web/app/Filament/Resources/BackupResource.php b/web/app/Filament/Resources/BackupResource.php index 268e21b..1e21236 100644 --- a/web/app/Filament/Resources/BackupResource.php +++ b/web/app/Filament/Resources/BackupResource.php @@ -102,6 +102,9 @@ class BackupResource extends Resource ->actions([ Tables\Actions\Action::make('download') ->icon('heroicon-o-arrow-down-tray') + ->hidden(function (Backup $backup) { + return $backup->status !== BackupStatus::Completed; + }) ->action(function (Backup $backup) { $backupStorage = BackupStorage::getInstance($backup->root_path); diff --git a/web/app/Models/HostingSubscriptionBackup.php b/web/app/Models/HostingSubscriptionBackup.php index 4b84d73..557e132 100644 --- a/web/app/Models/HostingSubscriptionBackup.php +++ b/web/app/Models/HostingSubscriptionBackup.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\BackupStorage; use App\Filament\Enums\BackupStatus; use App\Helpers; use Illuminate\Database\Eloquent\Builder; @@ -33,16 +34,16 @@ class HostingSubscriptionBackup extends Model 'status' => BackupStatus::class, ]; - protected static function booted(): void - { - static::addGlobalScope('customer', function (Builder $query) { - if (auth()->check() && auth()->guard()->name == 'web_customer') { - $query->whereHas('hostingSubscription', function ($query) { - $query->where('customer_id', auth()->user()->id); - }); - } - }); - } +// protected static function booted(): void +// { +// static::addGlobalScope('customer', function (Builder $query) { +// if (auth()->check() && auth()->guard()->name == 'web_customer') { +// $query->whereHas('hostingSubscription', function ($query) { +// $query->where('customer_id', auth()->user()->id); +// }); +// } +// }); +// } public static function boot() { parent::boot(); @@ -57,9 +58,9 @@ class HostingSubscriptionBackup extends Model }); static::deleting(function ($model) { - if (is_file($model->filepath)) { - shell_exec('rm -rf ' . $model->filepath); - } +// if (is_file($model->filepath)) { +// shell_exec('rm -rf ' . $model->filepath); +// } }); } @@ -67,6 +68,7 @@ class HostingSubscriptionBackup extends Model { $cronJobCommand = 'phyre-php /usr/local/phyre/web/artisan phyre:run-hosting-subscriptions-backup-checks'; $findCronJob = CronJob::where('command', $cronJobCommand)->first(); + if (! $findCronJob) { $cronJob = new CronJob(); $cronJob->schedule = '*/5 * * * *'; @@ -170,25 +172,20 @@ class HostingSubscriptionBackup extends Model ]; } - $storagePath = storage_path('backups'); - $backupPath = $storagePath.'/hosting_subscriptions/'.$this->backup_type.'/'.$this->id; + $backupStorageRootPath = '/var/lib/phyre/backups/hosting_subscriptions'; + $backupPath = $backupStorageRootPath . '/' . $findHostingSubscription->customer_id; + $backupTempPath = $backupPath.'/temp'; shell_exec('mkdir -p ' . $backupTempPath); + $backupFileName = Str::slug($findHostingSubscription->system_username .'-'. date('Ymd-His')) . '.zip'; + $backupFilePath = $backupStorageRootPath.'/'.$backupFileName; - $backupFileName = Str::slug($findHostingSubscription->system_username .'-'. date('Ymd-His')) . '.tar.gz'; - $backupFilePath = $backupPath.'/'.$backupFileName; - - $backupLogFileName = 'backup.log'; - $backupLogFilePath = $backupPath.'/'.$backupLogFileName; - - $backupTargetPath = $findMainDomain->domain_root . '/backups'; - $backupTargetFilePath = $backupTargetPath.'/'.$backupFileName; + $backupLogFilePath = $backupPath.'/backup.log'; $backupTempScript = '/tmp/backup-script-'.$this->id.'.sh'; $shellFileContent = ''; - $shellFileContent .= 'mkdir -p '. $backupTargetPath.PHP_EOL; - $shellFileContent .= 'echo "Backup up domain: '.$findHostingSubscription->domain .'"'. PHP_EOL; + $shellFileContent .= 'echo "Backup up user: '.$findHostingSubscription->system_username .'"'. PHP_EOL; $shellFileContent .= 'echo "Backup filename: '.$backupFileName.'"' . PHP_EOL; if ($this->backup_type == 'full') { @@ -205,30 +202,23 @@ class HostingSubscriptionBackup extends Model if ($getDatabases->count() > 0) { foreach ($getDatabases as $database) { -// $findDatabaseUser = DatabaseUser::where('database_id', $database->id) -// ->first(); -// if (!$findDatabaseUser) { -// continue; -// } $databaseName = $database->database_name_prefix . $database->database_name; -// $databaseUser = $findDatabaseUser->username_prefix . $findDatabaseUser->username; -// $databaseUserPassword = $findDatabaseUser->password; $shellFileContent .= 'echo "Backup up database: ' . $databaseName .'" '. PHP_EOL; - // $shellFileContent .= 'echo "Backup up database user: ' . $databaseUser .'" '. PHP_EOL; - $databaseBackupPath = $backupTempPath . '/' . $databaseName . '.sql'; + $shellFileContent .= 'mkdir -p '.$backupTempPath . '/databases' . PHP_EOL; + $databaseBackupPath = $backupTempPath . '/databases/' . $databaseName . '.sql'; $shellFileContent .= 'mysqldump -u "'.env('MYSQl_ROOT_USERNAME').'" -p"'.env('MYSQL_ROOT_PASSWORD').'" "'.$databaseName.'" > '.$databaseBackupPath . PHP_EOL; } } } - $shellFileContent .= 'cd '.$backupTempPath .' && tar -czvf '.$backupFilePath.' ./* '. PHP_EOL; + // With find, we can search for all files,directories (including hidden) in the current directory and zip them + $shellFileContent .= 'cd '.$backupTempPath .' && find . -exec zip -r '.$backupFilePath.' {} \;'. PHP_EOL; $shellFileContent .= 'rm -rf '.$backupTempPath.PHP_EOL; $shellFileContent .= 'echo "Backup complete"' . PHP_EOL; - $shellFileContent .= 'touch ' . $backupTargetPath. '/backup-'.$this->id.'.done' . PHP_EOL; - $shellFileContent .= 'mv '.$backupFilePath.' '. $backupTargetFilePath.PHP_EOL; + $shellFileContent .= 'touch ' . $backupPath. '/backup.done' . PHP_EOL; $shellFileContent .= 'rm -rf ' . $backupTempScript . PHP_EOL; file_put_contents($backupTempScript, $shellFileContent); @@ -238,8 +228,12 @@ class HostingSubscriptionBackup extends Model if ($processId > 0 && is_numeric($processId)) { - $this->path = $findMainDomain->domain_root . '/backups'; - $this->filepath = $backupTargetFilePath; + $this->path = $backupPath; + $this->root_path = $backupStorageRootPath; + $this->temp_path = $backupTempPath; + $this->file_path = $backupFilePath; + $this->file_name = $backupFileName; + $this->status = 'processing'; $this->queued = true; $this->queued_at = now(); diff --git a/web/database/migrations/2024_04_25_134711_create_hosting_subscription_backups_table.php b/web/database/migrations/2024_04_25_134711_create_hosting_subscription_backups_table.php index 2ea491e..5571c7b 100644 --- a/web/database/migrations/2024_04_25_134711_create_hosting_subscription_backups_table.php +++ b/web/database/migrations/2024_04_25_134711_create_hosting_subscription_backups_table.php @@ -17,8 +17,13 @@ return new class extends Migration $table->bigInteger('hosting_subscription_id')->nullable(); $table->string('backup_type')->nullable(); $table->string('status')->nullable(); + $table->string('path')->nullable(); - $table->string('filepath')->nullable(); + $table->string('root_path')->nullable(); + $table->string('temp_path')->nullable(); + $table->string('file_path')->nullable(); + $table->string('file_name')->nullable(); + $table->string('size')->nullable(); $table->string('disk')->nullable(); $table->string('process_id')->nullable(); diff --git a/web/tests/Unit/BackupTest.php b/web/tests/Unit/BackupTest.php index 581a483..44809dc 100644 --- a/web/tests/Unit/BackupTest.php +++ b/web/tests/Unit/BackupTest.php @@ -40,8 +40,8 @@ class BackupTest extends ActionTestCase } $this->assertTrue($backupFinished); $this->assertSame($findLastBackup->status, BackupStatus::Completed); - $this->assertNotEmpty($findLastBackup->filepath); - $this->assertTrue(file_exists(Storage::disk('backups')->path($findLastBackup->filepath))); + $this->assertNotEmpty($findLastBackup->file_path); + $this->assertTrue(file_exists($findLastBackup->file_path)); $backup = new Backup(); $checkCronJob = $backup->checkCronJob(); @@ -91,14 +91,14 @@ class BackupTest extends ActionTestCase } $this->assertTrue($backupCompleted); - $this->assertNotEmpty($findBackup->filepath); - $this->assertTrue(file_exists(Storage::disk('backups')->path($findBackup->filepath))); + $this->assertNotEmpty($findBackup->file_path); + $this->assertTrue(file_exists($findBackup->file_path)); - $getFilesize = filesize(Storage::disk('backups')->path($findBackup->filepath)); + $getFilesize = filesize($findBackup->file_path); $this->assertGreaterThan(0, $getFilesize); $this->assertSame($getFilesize, $findBackup->size); - Helpers::extractTar(Storage::disk('backups')->path($findBackup->filepath), $findBackup->path . '/unit-test'); + Helpers::extractTar($findBackup->file_path, $findBackup->path . '/unit-test'); } diff --git a/web/tests/Unit/HostingSubscriptionBackupTest.php b/web/tests/Unit/HostingSubscriptionBackupTest.php index 21956a4..abe4afe 100644 --- a/web/tests/Unit/HostingSubscriptionBackupTest.php +++ b/web/tests/Unit/HostingSubscriptionBackupTest.php @@ -28,7 +28,7 @@ class HostingSubscriptionBackupTest extends ActionTestCase $chs = $this->_createHostingSubscription(); - Artisan::call('phyre:run-hosting-subscriptions-backup'); + Artisan::call('phyre:create-daily-full-hosting-subscriptions-backup'); $findLastBackup = HostingSubscriptionBackup::where('hosting_subscription_id', $chs['hostingSubscriptionId']) ->first(); @@ -51,8 +51,8 @@ class HostingSubscriptionBackupTest extends ActionTestCase $this->assertTrue($backupFinished); $this->assertSame($findLastBackup->status, BackupStatus::Completed); - $this->assertNotEmpty($findLastBackup->filepath); - $this->assertTrue(file_exists($findLastBackup->filepath)); + $this->assertNotEmpty($findLastBackup->file_path); + $this->assertTrue(file_exists($findLastBackup->file_path)); $backup = new HostingSubscriptionBackup(); $checkCronJob = $backup->checkCronJob(); @@ -82,14 +82,14 @@ class HostingSubscriptionBackupTest extends ActionTestCase } $this->assertTrue($backupCompleted); - $this->assertNotEmpty($findBackup->filepath); - $this->assertTrue(file_exists($findBackup->filepath)); + $this->assertNotEmpty($findBackup->file_path); + $this->assertTrue(file_exists($findBackup->file_path)); - $getFilesize = filesize($findBackup->filepath); + $getFilesize = filesize($findBackup->file_path); $this->assertGreaterThan(0, $getFilesize); $this->assertSame(Helpers::checkPathSize($findBackup->path), $findBackup->size); - Helpers::extractTar($findBackup->filepath, $findBackup->path . '/unit-test'); + Helpers::extractTar($findBackup->file_path, $findBackup->path . '/unit-test'); // // dd($chs); $findDatabase = Database::where('id', $chs['databaseId'])->first();