mirror of
https://github.com/tiennm99/coolify.git
synced 2026-04-17 17:21:04 +00:00
Fix: Traefik proxy startup issues - handle null versions and filter predefined networks
Fixes two critical issues preventing Traefik proxy startup: 1. TypeError when restarting proxy: Handle null return from get_traefik_versions() - Add null check before dispatching CheckTraefikVersionForServerJob - Log warning when version data is unavailable - Prevents: "Argument #2 must be of type array, null given" 2. Docker network error: Filter out predefined Docker networks - Add isDockerPredefinedNetwork() helper to centralize network filtering - Apply filtering in collectDockerNetworksByServer() before operations - Apply filtering in generateDefaultProxyConfiguration() - Prevents: "operation is not permitted on predefined default network" Also: Move $cachedVersionsFile assignment after null check in Proxy.php Tests: Added 7 new unit tests for network filtering function All existing tests pass with no regressions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ use App\Jobs\CheckTraefikVersionForServerJob;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Services\ProxyDashboardCacheService;
|
use App\Services\ProxyDashboardCacheService;
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Navbar extends Component
|
class Navbar extends Component
|
||||||
@@ -72,7 +73,15 @@ class Navbar extends Component
|
|||||||
|
|
||||||
// Check Traefik version after restart to provide immediate feedback
|
// Check Traefik version after restart to provide immediate feedback
|
||||||
if ($this->server->proxyType() === ProxyTypes::TRAEFIK->value) {
|
if ($this->server->proxyType() === ProxyTypes::TRAEFIK->value) {
|
||||||
CheckTraefikVersionForServerJob::dispatch($this->server, get_traefik_versions());
|
$traefikVersions = get_traefik_versions();
|
||||||
|
if ($traefikVersions !== null) {
|
||||||
|
CheckTraefikVersionForServerJob::dispatch($this->server, $traefikVersions);
|
||||||
|
} else {
|
||||||
|
Log::warning('Traefik version check skipped: versions.json data unavailable', [
|
||||||
|
'server_id' => $this->server->id,
|
||||||
|
'server_name' => $this->server->name,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
|
|||||||
@@ -79,12 +79,11 @@ class Proxy extends Component
|
|||||||
|
|
||||||
// Load from global cached helper (Redis + filesystem)
|
// Load from global cached helper (Redis + filesystem)
|
||||||
$versionsData = get_versions_data();
|
$versionsData = get_versions_data();
|
||||||
$this->cachedVersionsFile = $versionsData;
|
|
||||||
|
|
||||||
if (! $versionsData) {
|
if (! $versionsData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->cachedVersionsFile = $versionsData;
|
||||||
$traefikVersions = data_get($versionsData, 'traefik');
|
$traefikVersions = data_get($versionsData, 'traefik');
|
||||||
|
|
||||||
return is_array($traefikVersions) ? $traefikVersions : null;
|
return is_array($traefikVersions) ? $traefikVersions : null;
|
||||||
|
|||||||
@@ -6,6 +6,20 @@ use App\Models\Application;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a network name is a Docker predefined system network.
|
||||||
|
* These networks cannot be created, modified, or managed by docker network commands.
|
||||||
|
*
|
||||||
|
* @param string $network Network name to check
|
||||||
|
* @return bool True if it's a predefined network that should be skipped
|
||||||
|
*/
|
||||||
|
function isDockerPredefinedNetwork(string $network): bool
|
||||||
|
{
|
||||||
|
// Only filter 'default' and 'host' to match existing codebase patterns
|
||||||
|
// See: bootstrap/helpers/parsers.php:891, bootstrap/helpers/shared.php:689,748
|
||||||
|
return in_array($network, ['default', 'host'], true);
|
||||||
|
}
|
||||||
|
|
||||||
function collectProxyDockerNetworksByServer(Server $server)
|
function collectProxyDockerNetworksByServer(Server $server)
|
||||||
{
|
{
|
||||||
if (! $server->isFunctional()) {
|
if (! $server->isFunctional()) {
|
||||||
@@ -66,8 +80,12 @@ function collectDockerNetworksByServer(Server $server)
|
|||||||
$networks->push($network);
|
$networks->push($network);
|
||||||
$allNetworks->push($network);
|
$allNetworks->push($network);
|
||||||
}
|
}
|
||||||
$networks = collect($networks)->flatten()->unique();
|
$networks = collect($networks)->flatten()->unique()->filter(function ($network) {
|
||||||
$allNetworks = $allNetworks->flatten()->unique();
|
return ! isDockerPredefinedNetwork($network);
|
||||||
|
});
|
||||||
|
$allNetworks = $allNetworks->flatten()->unique()->filter(function ($network) {
|
||||||
|
return ! isDockerPredefinedNetwork($network);
|
||||||
|
});
|
||||||
if ($server->isSwarm()) {
|
if ($server->isSwarm()) {
|
||||||
if ($networks->count() === 0) {
|
if ($networks->count() === 0) {
|
||||||
$networks = collect(['coolify-overlay']);
|
$networks = collect(['coolify-overlay']);
|
||||||
@@ -219,8 +237,8 @@ function generateDefaultProxyConfiguration(Server $server, array $custom_command
|
|||||||
$array_of_networks = collect([]);
|
$array_of_networks = collect([]);
|
||||||
$filtered_networks = collect([]);
|
$filtered_networks = collect([]);
|
||||||
$networks->map(function ($network) use ($array_of_networks, $filtered_networks) {
|
$networks->map(function ($network) use ($array_of_networks, $filtered_networks) {
|
||||||
if ($network === 'host') {
|
if (isDockerPredefinedNetwork($network)) {
|
||||||
return; // network-scoped alias is supported only for containers in user defined networks
|
return; // Predefined networks cannot be used in network configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
$array_of_networks[$network] = [
|
$array_of_networks[$network] = [
|
||||||
|
|||||||
@@ -153,3 +153,39 @@ it('compares branches for minor upgrades', function () {
|
|||||||
|
|
||||||
expect($result)->toBeTrue();
|
expect($result)->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('identifies default as predefined network', function () {
|
||||||
|
expect(isDockerPredefinedNetwork('default'))->toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('identifies host as predefined network', function () {
|
||||||
|
expect(isDockerPredefinedNetwork('host'))->toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('identifies coolify as not predefined network', function () {
|
||||||
|
expect(isDockerPredefinedNetwork('coolify'))->toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('identifies coolify-overlay as not predefined network', function () {
|
||||||
|
expect(isDockerPredefinedNetwork('coolify-overlay'))->toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('identifies custom networks as not predefined', function () {
|
||||||
|
$customNetworks = ['my-network', 'app-network', 'custom-123'];
|
||||||
|
|
||||||
|
foreach ($customNetworks as $network) {
|
||||||
|
expect(isDockerPredefinedNetwork($network))->toBeFalse();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('identifies bridge as not predefined (per codebase pattern)', function () {
|
||||||
|
// 'bridge' is technically a Docker predefined network, but existing codebase
|
||||||
|
// only filters 'default' and 'host', so we maintain consistency
|
||||||
|
expect(isDockerPredefinedNetwork('bridge'))->toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('identifies none as not predefined (per codebase pattern)', function () {
|
||||||
|
// 'none' is technically a Docker predefined network, but existing codebase
|
||||||
|
// only filters 'default' and 'host', so we maintain consistency
|
||||||
|
expect(isDockerPredefinedNetwork('none'))->toBeFalse();
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user