CluPilotCloud/app/Provisioning/Steps/Customer/ConfigureDnsAndTls.php

66 lines
2.2 KiB
PHP

<?php
namespace App\Provisioning\Steps\Customer;
use App\Models\ProvisioningRun;
use App\Provisioning\StepResult;
use App\Services\Dns\HetznerDnsClient;
use App\Services\Traefik\TraefikWriter;
class ConfigureDnsAndTls extends CustomerStep
{
public function __construct(
private HetznerDnsClient $dns,
private TraefikWriter $traefik,
) {}
public function key(): string
{
return 'configure_dns_and_tls';
}
public function maxDuration(): int
{
// Above the 840s cert own-deadline below, so the step's own fail fires first.
return 960;
}
public function execute(ProvisioningRun $run): StepResult
{
$instance = $this->instance($run);
$host = $instance->host;
$fqdn = $instance->subdomain.'.'.config('provisioning.dns.zone');
// DNS — persist the record id [E] before anything downstream.
if (! $this->hasResource($run, 'dns_record_id')) {
$recordId = $this->dns->upsertRecord($fqdn, 'A', $host->public_ip);
$instance->dnsRecords()->create([
'provider' => 'hetzner', 'record_id' => $recordId,
'fqdn' => $fqdn, 'type' => 'A', 'value' => $host->public_ip,
]);
$this->recordResource($run, $host, 'dns_record_id', $recordId);
}
// Traefik file-provider route → the guest VM (fall back to the host only
// if the guest address wasn't captured).
if (! $instance->route_written) {
$target = $instance->guest_ip ?: ($host->wg_ip ?? $host->public_ip);
$this->traefik->write($instance->subdomain, $target);
$instance->update(['route_written' => true]);
}
// TLS via HTTP-01 — poll until the certificate is served.
if (! $instance->cert_ok) {
if ($this->traefik->certReachable($fqdn)) {
$instance->update(['cert_ok' => true]);
} elseif ($run->started_at !== null && $run->started_at->copy()->addSeconds(840)->isPast()) {
return StepResult::fail('cert_timeout');
} else {
return StepResult::poll(20, 'waiting for certificate');
}
}
return StepResult::advance();
}
}