Deploy Ladill Hosting / deploy (push) Failing after 17s
Shared web hosting extracted from the platform monolith, with CI deploy to /var/www/ladill-hosting matching Bird/Domains/Email. Co-authored-by: Cursor <cursoragent@cursor.com>
116 lines
3.5 KiB
PHP
116 lines
3.5 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs;
|
|
|
|
use App\Models\Domain;
|
|
use App\Models\DomainDkimKey;
|
|
use App\Models\DomainNsCheck;
|
|
use App\Jobs\ProvisionDomainSlaveZoneJob;
|
|
use App\Services\Dns\PowerDnsClient;
|
|
use Illuminate\Bus\Queueable;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
use Illuminate\Http\Client\RequestException;
|
|
use Illuminate\Queue\InteractsWithQueue;
|
|
use Illuminate\Queue\SerializesModels;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Str;
|
|
|
|
class ProvisionDomainZoneJob implements ShouldQueue
|
|
{
|
|
use Dispatchable;
|
|
use InteractsWithQueue;
|
|
use Queueable;
|
|
use SerializesModels;
|
|
|
|
public int $tries = 5;
|
|
|
|
public int $backoff = 60;
|
|
|
|
public function __construct(public int $domainId)
|
|
{
|
|
}
|
|
|
|
public function handle(PowerDnsClient $client): void
|
|
{
|
|
$domain = Domain::query()->find($this->domainId);
|
|
if (! $domain) {
|
|
return;
|
|
}
|
|
|
|
// Ensure DKIM keys exist before provisioning zone
|
|
$this->ensureDkimKeys($domain);
|
|
|
|
try {
|
|
$client->ensureZone($domain);
|
|
$this->logCheck($domain, 'success', 'PDNS zone provisioned successfully.');
|
|
ProvisionDomainSlaveZoneJob::dispatch($domain->id);
|
|
} catch (RequestException $exception) {
|
|
$this->logCheck($domain, 'failed', $exception->getMessage());
|
|
throw $exception;
|
|
}
|
|
}
|
|
|
|
private function ensureDkimKeys(Domain $domain): void
|
|
{
|
|
$existing = DomainDkimKey::query()
|
|
->where('domain_id', $domain->id)
|
|
->where('status', 'active')
|
|
->latest('id')
|
|
->first();
|
|
|
|
if ($existing) {
|
|
return;
|
|
}
|
|
|
|
$prefix = (string) config('mailinfra.dkim_selector_prefix', 'ladill');
|
|
$selector = Str::lower(trim($prefix)) ?: 'ladill';
|
|
$selector .= '1';
|
|
|
|
$config = [
|
|
'digest_alg' => 'sha512',
|
|
'private_key_bits' => 2048,
|
|
'private_key_type' => OPENSSL_KEYTYPE_RSA,
|
|
];
|
|
|
|
$res = openssl_pkey_new($config);
|
|
openssl_pkey_export($res, $privateKey);
|
|
$details = openssl_pkey_get_details($res);
|
|
$publicKey = $details['key'] ?? '';
|
|
|
|
$publicKey = preg_replace('/-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\s/', '', $publicKey);
|
|
|
|
$privatePath = null;
|
|
if (is_string($privateKey) && trim($privateKey) !== '') {
|
|
$safeHost = Str::slug($domain->host, '_');
|
|
$directory = storage_path('app/mail/dkim');
|
|
File::ensureDirectoryExists($directory);
|
|
$privatePath = $directory.'/'.$safeHost.'_'.$selector.'.key';
|
|
File::put($privatePath, $privateKey);
|
|
}
|
|
|
|
DomainDkimKey::query()->create([
|
|
'domain_id' => $domain->id,
|
|
'selector' => $selector,
|
|
'public_key_txt' => $publicKey,
|
|
'private_key_path' => $privatePath,
|
|
'status' => 'active',
|
|
]);
|
|
}
|
|
|
|
private function logCheck(Domain $domain, string $result, string $notes): void
|
|
{
|
|
DomainNsCheck::create([
|
|
'domain_id' => $domain->id,
|
|
'check_type' => 'pdns_provision',
|
|
'result' => $result,
|
|
'status_before' => (string) $domain->status,
|
|
'status_after' => (string) $domain->status,
|
|
'state_before' => (string) ($domain->onboarding_state ?? ''),
|
|
'state_after' => (string) ($domain->onboarding_state ?? ''),
|
|
'notes' => $notes,
|
|
'checked_at' => now(),
|
|
]);
|
|
}
|
|
}
|