mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
fix(analytics): regenerate stored Caddy labels when toggling traffic analytics
Caddy logs a site only when its container labels contain the log directives. Deployments reuse the stored custom_labels, so applications whose labels were stored before analytics was enabled never got the log directives, and a redeploy did not help. Toggling traffic analytics on a Caddy server now regenerates the stored labels of applications with read-only labels. The destination uses the current server instance, because the cached server can still have the old analytics setting. Fixes #12117 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
be7369c9cc
commit
44e4566a9b
@@ -101,3 +101,7 @@
|
||||
- In remote commands, use absolute paths (`docker compose -f <dir>/docker-compose.yml`, `--project-directory <dir>`), `echo ... | tee <file> > /dev/null`, and `find` instead of globs. scp also runs as the SSH user; stage files outside `/data/coolify`.
|
||||
- The parsers add sudo only to line starts (and after `&&`, `||`, `|`, `$(`). Put `if`/`else` branches on their own lines. When a redirect or `cd` must stay, make the whole line one `sh -c '...'` script; it runs as `sudo sh -c` without inner sudo or bash.
|
||||
- Tests that replace `DatabaseStartCommandExecutor` or use root servers miss non-root bugs. Test the parsed commands of a non-root server.
|
||||
|
||||
## Cached and stored state
|
||||
- `StandaloneDocker`/`SwarmDocker` `server` uses `Server::findCached()`, a per-process identity map that is flushed only when the `servers` row updates. A `ServerSetting` save does not flush it, so pass the current `Server` instance (`setRelation('server', $server)`) when generated output depends on just-saved settings.
|
||||
- Application deployments use the stored `custom_labels` when they exist. When a server-level setting changes the generated labels, regenerate the stored labels of read-only (`is_container_label_readonly_enabled`) applications, or a redeploy keeps the old labels.
|
||||
|
||||
@@ -4,7 +4,9 @@ namespace App\Actions\Server;
|
||||
|
||||
use App\Actions\Proxy\GetProxyConfiguration;
|
||||
use App\Actions\Proxy\SaveProxyConfiguration;
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Jobs\RestartProxyJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use App\Services\ProxyPortParser;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
@@ -41,6 +43,10 @@ class ConfigureTrafficAnalytics
|
||||
$server->settings->save();
|
||||
$server->refresh();
|
||||
|
||||
if ($server->proxyType() === ProxyTypes::CADDY->value) {
|
||||
$this->regenerateReadonlyApplicationLabels($server);
|
||||
}
|
||||
|
||||
// A proxy the user stopped stays stopped; its next start applies the saved configuration.
|
||||
$restartProxy = $hasProxy && ! $this->proxyIsStopped($server);
|
||||
if ($restartProxy) {
|
||||
@@ -79,6 +85,23 @@ class ConfigureTrafficAnalytics
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caddy logs a site only when its labels contain the log directives. Deployments use the stored labels,
|
||||
* so read-only (Coolify-managed) labels must be regenerated, or a redeploy keeps the old logging state.
|
||||
*/
|
||||
private function regenerateReadonlyApplicationLabels(Server $server): void
|
||||
{
|
||||
$server->applications()
|
||||
->filter(fn (Application $application): bool => (bool) $application->settings?->is_container_label_readonly_enabled
|
||||
&& $application->destination?->server_id === $server->id)
|
||||
->each(function (Application $application) use ($server): void {
|
||||
// The cached server of the destination can still have the old analytics setting.
|
||||
$application->destination->setRelation('server', $server);
|
||||
$application->custom_labels = base64_encode(implode("\n", generateLabelsApplication($application)));
|
||||
$application->save();
|
||||
});
|
||||
}
|
||||
|
||||
private function proxyIsStopped(Server $server): bool
|
||||
{
|
||||
return (bool) $server->proxy->get('force_stop')
|
||||
|
||||
@@ -5,7 +5,11 @@ use App\Actions\Proxy\SaveProxyConfiguration;
|
||||
use App\Actions\Server\ConfigureTrafficAnalytics;
|
||||
use App\Actions\Server\StartSentinel;
|
||||
use App\Jobs\RestartProxyJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\Environment;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
use App\Models\StandaloneDocker;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
@@ -184,3 +188,37 @@ it('restarts a running proxy to apply the configuration', function (string $prox
|
||||
expect($server->fresh()->isTrafficAnalyticsEnabled())->toBeTrue();
|
||||
Queue::assertPushed(RestartProxyJob::class);
|
||||
})->with(['TRAEFIK', 'CADDY']);
|
||||
|
||||
it('regenerates the stored Caddy labels of applications with read-only labels', function () {
|
||||
Queue::fake();
|
||||
StartSentinel::partialMock()->shouldReceive('handle');
|
||||
GetProxyConfiguration::partialMock()->shouldReceive('handle')->andReturn("services:\n caddy:\n volumes: []\n");
|
||||
SaveProxyConfiguration::partialMock()->shouldReceive('handle');
|
||||
|
||||
$server = trafficAnalyticsProxyServer($this, 'CADDY');
|
||||
$environment = Environment::factory()->create(['project_id' => Project::factory()->create(['team_id' => $this->team->id])->id]);
|
||||
$destination = StandaloneDocker::query()->where('server_id', $server->id)->firstOrFail();
|
||||
$createApplication = fn (): Application => Application::factory()->createOne([
|
||||
'environment_id' => $environment->id,
|
||||
'destination_id' => $destination->id,
|
||||
'destination_type' => $destination->getMorphClass(),
|
||||
'fqdn' => 'https://example.com',
|
||||
]);
|
||||
$readonly = $createApplication();
|
||||
$readonly->update(['custom_labels' => base64_encode(implode("\n", generateLabelsApplication($readonly->fresh())))]);
|
||||
$editable = $createApplication();
|
||||
$editable->settings->update(['is_container_label_readonly_enabled' => false]);
|
||||
$editable->update(['custom_labels' => base64_encode('caddy_0=https://custom.example.com')]);
|
||||
$logsTraffic = fn (Application $application): bool => str_contains(base64_decode($application->fresh()->custom_labels), 'log.output=file /traffic/access.log');
|
||||
|
||||
expect($logsTraffic($readonly))->toBeFalse();
|
||||
|
||||
ConfigureTrafficAnalytics::run($server, true);
|
||||
|
||||
expect($logsTraffic($readonly))->toBeTrue()
|
||||
->and(base64_decode($editable->fresh()->custom_labels))->toBe('caddy_0=https://custom.example.com');
|
||||
|
||||
ConfigureTrafficAnalytics::run($server->fresh(), false);
|
||||
|
||||
expect($logsTraffic($readonly))->toBeFalse();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user