mirror of
https://github.com/tiennm99/coolify.git
synced 2026-04-18 09:20:46 +00:00
fix: properly handle SERVICE_URL and SERVICE_FQDN for abbreviated service names (#7243)
Parse template variables directly instead of generating from container names. Always create both SERVICE_URL and SERVICE_FQDN pairs together. Properly separate scheme handling (URL has scheme, FQDN doesn't). Add comprehensive test coverage. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -189,65 +189,51 @@ class ServiceApplication extends BaseModel
|
||||
public function getRequiredPort(): ?int
|
||||
{
|
||||
try {
|
||||
// Normalize container name same way as variable creation
|
||||
// (uppercase, replace - and . with _)
|
||||
$normalizedName = str($this->name)
|
||||
->upper()
|
||||
->replace('-', '_')
|
||||
->replace('.', '_')
|
||||
->value();
|
||||
// Get all environment variables from the service
|
||||
$serviceEnvVars = $this->service->environment_variables()->get();
|
||||
// Parse the Docker Compose to find SERVICE_URL/SERVICE_FQDN variables DIRECTLY DECLARED
|
||||
// for this specific service container (not just referenced from other containers)
|
||||
$dockerComposeRaw = data_get($this->service, 'docker_compose_raw');
|
||||
if (! $dockerComposeRaw) {
|
||||
// Fall back to service-level port if no compose file
|
||||
return $this->service->getRequiredPort();
|
||||
}
|
||||
|
||||
// Look for SERVICE_FQDN_* or SERVICE_URL_* variables that match this container
|
||||
foreach ($serviceEnvVars as $envVar) {
|
||||
$key = str($envVar->key);
|
||||
$dockerCompose = \Symfony\Component\Yaml\Yaml::parse($dockerComposeRaw);
|
||||
$serviceConfig = data_get($dockerCompose, "services.{$this->name}");
|
||||
if (! $serviceConfig) {
|
||||
return $this->service->getRequiredPort();
|
||||
}
|
||||
|
||||
// Check if this is a SERVICE_FQDN_* or SERVICE_URL_* variable
|
||||
if (! $key->startsWith('SERVICE_FQDN_') && ! $key->startsWith('SERVICE_URL_')) {
|
||||
continue;
|
||||
}
|
||||
// Extract the part after SERVICE_FQDN_ or SERVICE_URL_
|
||||
if ($key->startsWith('SERVICE_FQDN_')) {
|
||||
$suffix = $key->after('SERVICE_FQDN_');
|
||||
} else {
|
||||
$suffix = $key->after('SERVICE_URL_');
|
||||
}
|
||||
$environment = data_get($serviceConfig, 'environment', []);
|
||||
|
||||
// Check if this variable starts with our normalized container name
|
||||
// Format: {NORMALIZED_NAME}_{PORT} or just {NORMALIZED_NAME}
|
||||
if (! $suffix->startsWith($normalizedName)) {
|
||||
\Log::debug('[ServiceApplication::getRequiredPort] Suffix does not match container', [
|
||||
'expected_start' => $normalizedName,
|
||||
'actual_suffix' => $suffix->value(),
|
||||
]);
|
||||
// Extract SERVICE_URL and SERVICE_FQDN variables DIRECTLY DECLARED in this service's environment
|
||||
// (not variables that are merely referenced with ${VAR} syntax)
|
||||
$portFound = null;
|
||||
foreach ($environment as $envVar) {
|
||||
if (is_string($envVar)) {
|
||||
// Extract variable name (before '=' if present)
|
||||
$envVarName = str($envVar)->before('=')->trim();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if there's a port suffix after the container name
|
||||
// The suffix should be exactly NORMALIZED_NAME or NORMALIZED_NAME_PORT
|
||||
$afterName = $suffix->after($normalizedName)->value();
|
||||
|
||||
// If there's content after the name, it should start with underscore
|
||||
if ($afterName !== '' && str($afterName)->startsWith('_')) {
|
||||
// Extract port: _3210 -> 3210
|
||||
$port = str($afterName)->after('_')->value();
|
||||
// Validate that the extracted port is numeric
|
||||
if (is_numeric($port)) {
|
||||
\Log::debug('[ServiceApplication::getRequiredPort] MATCH FOUND - Returning port', [
|
||||
'port' => (int) $port,
|
||||
]);
|
||||
|
||||
return (int) $port;
|
||||
// Only process direct declarations
|
||||
if ($envVarName->startsWith('SERVICE_FQDN_') || $envVarName->startsWith('SERVICE_URL_')) {
|
||||
// Parse to check if it has a port suffix
|
||||
$parsed = parseServiceEnvironmentVariable($envVarName->value());
|
||||
if ($parsed['has_port'] && $parsed['port']) {
|
||||
// Found a port-specific variable for this service
|
||||
$portFound = (int) $parsed['port'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to service-level port if no port-specific variable is found
|
||||
$fallbackPort = $this->service->getRequiredPort();
|
||||
// If a port was found in the template, return it
|
||||
if ($portFound !== null) {
|
||||
return $portFound;
|
||||
}
|
||||
|
||||
return $fallbackPort;
|
||||
// No port-specific variables found for this service, return null
|
||||
// (DO NOT fall back to service-level port, as that applies to all services)
|
||||
return null;
|
||||
} catch (\Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user