Files
coolify/app/Actions/Server/ConfigureTrafficAnalytics.php
T
6b07f03107 feat(terminal): interactive console mode for containers (docker attach) (#11538)
Co-authored-by: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com>
Co-authored-by: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rosslh <ross@rosshill.ca>
2026-10-14 14:32:02 +02:00

111 lines
4.3 KiB
PHP

<?php
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;
use RuntimeException;
use Throwable;
class ConfigureTrafficAnalytics
{
use AsAction;
private const STOPPED_PROXY_STATUSES = ['exited', 'stopped', 'stopping', 'dead'];
/**
* Turn traffic analytics on or off. The proxy configuration is saved before the setting,
* so a failure leaves both unchanged.
*
* @return bool Whether a proxy restart was queued to apply the new configuration.
*/
public function handle(Server $server, bool $enable): bool
{
if ($enable && ($reason = $server->trafficAnalyticsUnsupportedReason()) !== null) {
throw new RuntimeException($reason);
}
$sentinelWasEnabled = (bool) $server->settings->is_sentinel_enabled;
// Disabling must still work after the proxy was removed, so there may be no proxy configuration to update.
$hasProxy = $server->hasTrafficAnalyticsProxy();
if ($hasProxy) {
$this->saveProxyConfiguration($server, $enable);
}
$server->settings->is_traffic_analytics_enabled = $enable;
$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) {
RestartProxyJob::dispatch($server);
}
// Recreate Sentinel so it picks up (enabling) or drops (disabling) the traffic env + proxy-log mount.
// Enabling analytics needs Sentinel running; when disabling, only restart if Sentinel was already
// enabled so we never turn Sentinel on as a side effect of disabling analytics.
if ($enable || $sentinelWasEnabled) {
StartSentinel::run($server, restart: true);
}
return $restartProxy;
}
private function saveProxyConfiguration(Server $server, bool $enable): void
{
$previousEnabled = (bool) $server->settings->is_traffic_analytics_enabled;
$previousProxy = $server->proxy->all();
try {
$configuration = GetProxyConfiguration::run($server);
ProxyPortParser::fromConfiguration($configuration);
// The configuration is built from the in-memory setting; it is persisted only after the save succeeds.
$server->settings->is_traffic_analytics_enabled = $enable;
$configuration = applyTrafficAnalyticsToProxyConfiguration($server, $configuration);
SaveProxyConfiguration::run($server, $configuration);
} catch (Throwable $exception) {
$server->settings->is_traffic_analytics_enabled = $previousEnabled;
$server->proxy = $previousProxy;
$server->save();
throw $exception;
}
}
/**
* 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')
|| in_array($server->proxy->get('status'), self::STOPPED_PROXY_STATUSES, true);
}
}