VPS and dedicated server ordering, managed panels, SSO, billing, and launcher integration — forked from hosting infrastructure with server-focused routes and dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
108 lines
3.3 KiB
PHP
108 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\HostingAccount;
|
|
use App\Services\Hosting\Providers\SharedNodeProvider;
|
|
use Illuminate\Console\Command;
|
|
|
|
class AuditHostingPhpFpmPoolsCommand extends Command
|
|
{
|
|
protected $signature = 'hosting:audit-php-fpm-pools
|
|
{--account= : Limit to one hosting account id}
|
|
{--repair : Remove duplicate pools and keep the account PHP version}';
|
|
|
|
protected $description = 'Scan shared hosting accounts for duplicate PHP-FPM pool configs across PHP versions.';
|
|
|
|
public function handle(SharedNodeProvider $provider): int
|
|
{
|
|
$accounts = HostingAccount::query()
|
|
->with('node')
|
|
->where('type', HostingAccount::TYPE_SHARED)
|
|
->when($this->option('account'), fn ($query, $accountId) => $query->whereKey($accountId))
|
|
->orderBy('id')
|
|
->get();
|
|
|
|
if ($accounts->isEmpty()) {
|
|
$this->info('No hosting accounts matched.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$issues = 0;
|
|
$repaired = 0;
|
|
$failures = 0;
|
|
|
|
foreach ($accounts as $account) {
|
|
if (! $account->node) {
|
|
$this->warn("[{$account->id}] {$account->username}: no node assigned");
|
|
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$versions = $provider->findPhpFpmPoolVersions($account);
|
|
} catch (\Throwable $e) {
|
|
$failures++;
|
|
$this->error("[{$account->id}] {$account->username}: {$e->getMessage()}");
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($versions === []) {
|
|
$this->line("[{$account->id}] {$account->username}: no pool configs found");
|
|
|
|
continue;
|
|
}
|
|
|
|
$targetVersion = $account->php_version ?? '8.4';
|
|
$status = count($versions) === 1 && $versions[0] === $targetVersion
|
|
? 'ok'
|
|
: 'duplicate';
|
|
|
|
$this->line(sprintf(
|
|
'[%d] %s: pools=%s target=%s (%s)',
|
|
$account->id,
|
|
$account->username,
|
|
implode(', ', $versions),
|
|
$targetVersion,
|
|
$status,
|
|
));
|
|
|
|
if ($status === 'ok') {
|
|
continue;
|
|
}
|
|
|
|
$issues++;
|
|
|
|
if (! $this->option('repair')) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
if ($provider->changeAccountPhpVersion($account, $targetVersion)) {
|
|
$repaired++;
|
|
$this->info(" repaired {$account->username}");
|
|
} else {
|
|
$failures++;
|
|
$this->error(" failed to repair {$account->username}");
|
|
}
|
|
} catch (\Throwable $e) {
|
|
$failures++;
|
|
$this->error(" failed to repair {$account->username}: {$e->getMessage()}");
|
|
}
|
|
}
|
|
|
|
$this->newLine();
|
|
$this->info("Accounts scanned: {$accounts->count()}");
|
|
$this->info("Issues found: {$issues}");
|
|
|
|
if ($this->option('repair')) {
|
|
$this->info("Repaired: {$repaired}");
|
|
$this->info("Failures: {$failures}");
|
|
}
|
|
|
|
return $failures > 0 ? self::FAILURE : ($issues > 0 && ! $this->option('repair') ? self::FAILURE : self::SUCCESS);
|
|
}
|
|
}
|