mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-27 17:55:59 -04:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -775,8 +775,11 @@ class Domains extends Component
|
||||
|
||||
/**
|
||||
* Persist current domain row DNS results and drop statuses for removed domains.
|
||||
*
|
||||
* @param array<int, string> $startingCheckKeys Status keys whose check is being started by this call.
|
||||
* They are allowed to replace a stored completed result.
|
||||
*/
|
||||
protected function persistDomainDnsStatuses(): void
|
||||
protected function persistDomainDnsStatuses(array $startingCheckKeys = []): void
|
||||
{
|
||||
$statuses = [];
|
||||
|
||||
@@ -808,11 +811,15 @@ class Domains extends Component
|
||||
];
|
||||
}
|
||||
|
||||
DB::transaction(function () use (&$statuses): void {
|
||||
DB::transaction(function () use (&$statuses, $startingCheckKeys): void {
|
||||
$application = Application::query()->lockForUpdate()->findOrFail($this->application->id);
|
||||
$storedStatuses = $application->domain_dns_statuses ?? [];
|
||||
|
||||
foreach ($statuses as $key => $status) {
|
||||
if (in_array($key, $startingCheckKeys, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$localCheckId = $status['check_id'] ?? null;
|
||||
$storedCheckId = $storedStatuses[$key]['check_id'] ?? null;
|
||||
|
||||
@@ -1054,7 +1061,7 @@ class Domains extends Component
|
||||
foreach ($dnsChecks as $dnsCheck) {
|
||||
$this->markUrlsAsChecking([$dnsCheck['url']], $serviceForCheck, $dnsCheck['check_id']);
|
||||
}
|
||||
$this->persistDomainDnsStatuses();
|
||||
$this->persistDomainDnsStatuses($dnsChecks->pluck('status_key')->all());
|
||||
|
||||
$failedDnsChecks = 0;
|
||||
foreach ($dnsChecks as $dnsCheck) {
|
||||
@@ -1207,7 +1214,7 @@ class Domains extends Component
|
||||
foreach ($this->dnsEntriesForUrls($urls, $service) as $statusKey => $url) {
|
||||
$checkId = new_public_id();
|
||||
$this->markUrlsAsChecking([$url], $service, $checkId);
|
||||
$this->persistDomainDnsStatuses();
|
||||
$this->persistDomainDnsStatuses([$statusKey]);
|
||||
|
||||
try {
|
||||
CheckDomainDnsJob::dispatch(
|
||||
|
||||
@@ -339,17 +339,18 @@ class PreviewDomains extends Component
|
||||
}
|
||||
|
||||
$row = $this->domainRows[$index];
|
||||
$statusKey = $this->statusKey($row['url'], $row['service']);
|
||||
$checkId = new_public_id();
|
||||
$this->domainRows[$index]['dns_status'] = 'checking';
|
||||
$this->domainRows[$index]['dns_message'] = 'Checking DNS...';
|
||||
$this->domainRows[$index]['check_id'] = $checkId;
|
||||
$this->persistDnsStatuses();
|
||||
$this->persistDnsStatuses([$statusKey]);
|
||||
|
||||
try {
|
||||
$server = $this->preview->application->destination?->server;
|
||||
CheckDomainDnsJob::dispatch(
|
||||
$this->preview,
|
||||
$this->statusKey($row['url'], $row['service']),
|
||||
$statusKey,
|
||||
$row['url'],
|
||||
$server,
|
||||
$server ? serverDnsTargetIp($server) ?? $server->ip : null,
|
||||
@@ -494,7 +495,11 @@ class PreviewDomains extends Component
|
||||
return true;
|
||||
}
|
||||
|
||||
private function persistDnsStatuses(): void
|
||||
/**
|
||||
* @param array<int, string> $startingCheckKeys Status keys whose check is being started by this call.
|
||||
* They are allowed to replace a stored completed result.
|
||||
*/
|
||||
private function persistDnsStatuses(array $startingCheckKeys = []): void
|
||||
{
|
||||
$statuses = [];
|
||||
foreach ($this->domainRows as $row) {
|
||||
@@ -505,13 +510,13 @@ class PreviewDomains extends Component
|
||||
];
|
||||
}
|
||||
|
||||
DB::transaction(function () use (&$statuses): void {
|
||||
DB::transaction(function () use (&$statuses, $startingCheckKeys): void {
|
||||
$preview = ApplicationPreview::query()->lockForUpdate()->findOrFail($this->preview->id);
|
||||
$storedStatuses = $preview->domain_dns_statuses ?? [];
|
||||
|
||||
foreach ($statuses as $key => $status) {
|
||||
$storedStatus = $storedStatuses[$key] ?? null;
|
||||
if (! is_array($storedStatus)) {
|
||||
if (! is_array($storedStatus) || in_array($key, $startingCheckKeys, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -577,7 +577,11 @@ class Domains extends Component
|
||||
$this->persistAllDomainDnsStatuses();
|
||||
}
|
||||
|
||||
protected function persistAllDomainDnsStatuses(): void
|
||||
/**
|
||||
* @param array<int, string> $startingCheckKeys Status keys whose check is being started by this call.
|
||||
* They are allowed to replace a stored completed result.
|
||||
*/
|
||||
protected function persistAllDomainDnsStatuses(array $startingCheckKeys = []): void
|
||||
{
|
||||
$byApp = [];
|
||||
|
||||
@@ -617,11 +621,15 @@ class Domains extends Component
|
||||
->all();
|
||||
$statuses = array_intersect_key($statuses, array_flip($currentUrls));
|
||||
|
||||
DB::transaction(function () use ($app, &$statuses): void {
|
||||
DB::transaction(function () use ($app, &$statuses, $startingCheckKeys): void {
|
||||
$application = ServiceApplication::query()->lockForUpdate()->findOrFail($app->id);
|
||||
$storedStatuses = $application->domain_dns_statuses ?? [];
|
||||
|
||||
foreach ($statuses as $key => $status) {
|
||||
if (in_array($key, $startingCheckKeys, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$localCheckId = $status['check_id'] ?? null;
|
||||
$storedCheckId = $storedStatuses[$key]['check_id'] ?? null;
|
||||
|
||||
@@ -1096,7 +1104,7 @@ class Domains extends Component
|
||||
foreach ($dnsChecks as $dnsCheck) {
|
||||
$this->markUrlsAsChecking([$dnsCheck['url']], $serviceApplicationId, $dnsCheck['check_id']);
|
||||
}
|
||||
$this->persistAllDomainDnsStatuses();
|
||||
$this->persistAllDomainDnsStatuses($dnsChecks->pluck('url')->all());
|
||||
|
||||
$failedDnsChecks = 0;
|
||||
foreach ($dnsChecks as $dnsCheck) {
|
||||
@@ -1655,7 +1663,7 @@ class Domains extends Component
|
||||
foreach (array_unique($urls) as $url) {
|
||||
$checkId = new_public_id();
|
||||
$this->markUrlsAsChecking([$url], (int) $application->id, $checkId);
|
||||
$this->persistAllDomainDnsStatuses();
|
||||
$this->persistAllDomainDnsStatuses([$url]);
|
||||
|
||||
try {
|
||||
CheckDomainDnsJob::dispatch(
|
||||
|
||||
@@ -3558,3 +3558,120 @@ it('prevents members from cancelling protected application redirect conflict sta
|
||||
->set('showDomainConflictModal', false)
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
it('restarts a dns check when the domain already has a completed result', function () {
|
||||
Queue::fake();
|
||||
|
||||
$url = 'https://dns-recheck.example.com';
|
||||
$this->application->update([
|
||||
'fqdn' => $url,
|
||||
'domain_dns_statuses' => [
|
||||
$url => [
|
||||
'status' => 'failed',
|
||||
'message' => 'Required DNS record type A pointing to 203.0.113.10',
|
||||
'expected_ip' => '203.0.113.10',
|
||||
'checked_at' => now()->subDay()->toIso8601String(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
Livewire::test(Domains::class, ['application' => $this->application->fresh()])
|
||||
->call('checkDomainDns', 0)
|
||||
->assertSet('domainRows.0.dns_status', 'checking');
|
||||
|
||||
expect($this->application->fresh()->domain_dns_statuses[$url]['status'])->toBe('checking');
|
||||
|
||||
Queue::assertPushed(CheckDomainDnsJob::class);
|
||||
});
|
||||
|
||||
it('does not overwrite a completed dns result with stale checking state', function () {
|
||||
$url = 'https://dns-stale.example.com';
|
||||
$this->application->update([
|
||||
'fqdn' => $url,
|
||||
'domain_dns_statuses' => [
|
||||
$url => [
|
||||
'status' => 'checking',
|
||||
'message' => 'Checking DNS...',
|
||||
'check_id' => 'stale-check',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$component = Livewire::test(Domains::class, ['application' => $this->application->fresh()]);
|
||||
|
||||
$this->application->update([
|
||||
'domain_dns_statuses' => [
|
||||
$url => [
|
||||
'status' => 'ok',
|
||||
'message' => 'DNS looks correct.',
|
||||
'check_id' => 'completed-check',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$method = new ReflectionMethod($component->instance(), 'persistDomainDnsStatuses');
|
||||
$method->invoke($component->instance());
|
||||
|
||||
expect($this->application->fresh()->domain_dns_statuses[$url])
|
||||
->toMatchArray([
|
||||
'status' => 'ok',
|
||||
'message' => 'DNS looks correct.',
|
||||
'check_id' => 'completed-check',
|
||||
]);
|
||||
});
|
||||
|
||||
it('replaces a completed dns result when the domain is checked again', function () {
|
||||
$settings = InstanceSettings::get();
|
||||
$settings->is_dns_validation_enabled = true;
|
||||
$settings->save();
|
||||
|
||||
$url = 'https://this-domain-should-not-resolve-for-coolify-tests.invalid';
|
||||
$checkedAt = now()->subDays(12)->toIso8601String();
|
||||
$this->application->update([
|
||||
'fqdn' => $url,
|
||||
'domain_dns_statuses' => [
|
||||
$url => [
|
||||
'status' => 'ok',
|
||||
'message' => 'DNS looks correct.',
|
||||
'expected_ip' => '203.0.113.10',
|
||||
'checked_at' => $checkedAt,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
Livewire::test(Domains::class, ['application' => $this->application->fresh()])
|
||||
->call('checkDomainDns', 0)
|
||||
->call('pollDnsChecks')
|
||||
->assertSet('domainRows.0.dns_status', 'failed');
|
||||
|
||||
expect($this->application->fresh()->domain_dns_statuses[$url])
|
||||
->status->toBe('failed')
|
||||
->checked_at->not->toBe($checkedAt);
|
||||
});
|
||||
|
||||
it('restarts a preview dns check when the domain already has a completed result', function () {
|
||||
Queue::fake();
|
||||
|
||||
$url = 'https://preview-recheck.example.com';
|
||||
$statusKey = hash('sha256', $url.'|');
|
||||
$preview = ApplicationPreview::create([
|
||||
'application_id' => $this->application->id,
|
||||
'pull_request_id' => 54,
|
||||
'pull_request_html_url' => 'https://github.com/coollabsio/coolify/pull/54',
|
||||
'fqdn' => $url,
|
||||
'domain_dns_statuses' => [
|
||||
$statusKey => [
|
||||
'status' => 'failed',
|
||||
'message' => 'Required DNS record type A pointing to 203.0.113.10',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
Livewire::test(PreviewDomains::class, ['preview' => $preview])
|
||||
->call('checkDomainDns', 0)
|
||||
->assertSet('domainRows.0.dns_status', 'checking');
|
||||
|
||||
expect($preview->fresh()->domain_dns_statuses[$statusKey]['status'])->toBe('checking');
|
||||
|
||||
Queue::assertPushed(CheckDomainDnsJob::class);
|
||||
});
|
||||
|
||||
@@ -1319,3 +1319,31 @@ it('lays out the domain settings dropdowns in responsive columns', function () {
|
||||
expect($view)->toContain('mt-4 grid grid-cols-1 gap-4 border-t border-neutral-200 pt-4 sm:grid-cols-2')
|
||||
->toContain('flex flex-wrap items-center justify-between gap-2');
|
||||
});
|
||||
|
||||
it('restarts a service dns check when the domain already has a completed result', function () {
|
||||
Queue::fake();
|
||||
|
||||
$domain = 'https://api.example.com';
|
||||
$this->apiApp->update([
|
||||
'domain_dns_statuses' => [
|
||||
$domain => [
|
||||
'status' => 'failed',
|
||||
'message' => 'Required DNS record type A pointing to 203.0.113.10',
|
||||
'expected_ip' => '203.0.113.10',
|
||||
'checked_at' => now()->subDay()->toIso8601String(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$component = Livewire::test(Domains::class, ['service' => $this->service->fresh(['applications', 'server'])]);
|
||||
$index = collect($component->get('domainRows'))->search(fn (array $row): bool => $row['url'] === $domain);
|
||||
|
||||
expect($index)->not->toBeFalse();
|
||||
|
||||
$component->call('checkDomainDns', $index)
|
||||
->assertSet("domainRows.{$index}.dns_status", 'checking');
|
||||
|
||||
expect($this->apiApp->fresh()->domain_dns_statuses[$domain]['status'])->toBe('checking');
|
||||
|
||||
Queue::assertPushed(CheckDomainDnsJob::class);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user