refactor: streamline required port retrieval in EditDomain and ServiceApplicationView; add environment_variables method in ServiceApplication
This commit is contained in:
parent
2e85ca8a57
commit
6decad2e96
4 changed files with 118 additions and 11 deletions
|
|
@ -39,7 +39,7 @@ public function mount()
|
|||
{
|
||||
$this->application = ServiceApplication::ownedByCurrentTeam()->findOrFail($this->applicationId);
|
||||
$this->authorize('view', $this->application);
|
||||
$this->requiredPort = $this->application->service->getRequiredPort();
|
||||
$this->requiredPort = $this->application->getRequiredPort();
|
||||
$this->syncData();
|
||||
}
|
||||
|
||||
|
|
@ -113,8 +113,7 @@ public function submit()
|
|||
|
||||
// Check for required port
|
||||
if (! $this->forceRemovePort) {
|
||||
$service = $this->application->service;
|
||||
$requiredPort = $service->getRequiredPort();
|
||||
$requiredPort = $this->application->getRequiredPort();
|
||||
|
||||
if ($requiredPort !== null) {
|
||||
// Check if all FQDNs have a port
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ public function mount()
|
|||
try {
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->authorize('view', $this->application);
|
||||
$this->requiredPort = $this->application->service->getRequiredPort();
|
||||
$this->requiredPort = $this->application->getRequiredPort();
|
||||
$this->syncData();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
|
@ -268,8 +268,7 @@ public function submit()
|
|||
|
||||
// Check for required port
|
||||
if (! $this->forceRemovePort) {
|
||||
$service = $this->application->service;
|
||||
$requiredPort = $service->getRequiredPort();
|
||||
$requiredPort = $this->application->getRequiredPort();
|
||||
|
||||
if ($requiredPort !== null) {
|
||||
// Check if all FQDNs have a port
|
||||
|
|
|
|||
|
|
@ -109,6 +109,11 @@ public function fileStorages()
|
|||
return $this->morphMany(LocalFileVolume::class, 'resource');
|
||||
}
|
||||
|
||||
public function environment_variables()
|
||||
{
|
||||
return $this->morphMany(EnvironmentVariable::class, 'resourceable');
|
||||
}
|
||||
|
||||
public function fqdns(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
|
|
@ -174,4 +179,77 @@ public function isBackupSolutionAvailable()
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the required port for this service application.
|
||||
* Extracts port from SERVICE_URL_* or SERVICE_FQDN_* environment variables
|
||||
* stored at the Service level, filtering by normalized container name.
|
||||
* Falls back to service-level port if no port-specific variable is found.
|
||||
*/
|
||||
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();
|
||||
|
||||
// Look for SERVICE_FQDN_* or SERVICE_URL_* variables that match this container
|
||||
foreach ($serviceEnvVars as $envVar) {
|
||||
$key = str($envVar->key);
|
||||
|
||||
// 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_');
|
||||
}
|
||||
|
||||
// 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(),
|
||||
]);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to service-level port if no port-specific variable is found
|
||||
$fallbackPort = $this->service->getRequiredPort();
|
||||
|
||||
return $fallbackPort;
|
||||
} catch (\Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -563,12 +563,25 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
|
|||
}
|
||||
}
|
||||
} elseif ($command->value() === 'URL') {
|
||||
$urlFor = $key->after('SERVICE_URL_')->lower()->value();
|
||||
// SERVICE_URL_APP or SERVICE_URL_APP_3000
|
||||
// Detect if there's a port suffix
|
||||
if (substr_count(str($key)->value(), '_') === 3) {
|
||||
$urlFor = $key->after('SERVICE_URL_')->beforeLast('_')->lower()->value();
|
||||
$port = $key->afterLast('_')->value();
|
||||
} else {
|
||||
$urlFor = $key->after('SERVICE_URL_')->lower()->value();
|
||||
$port = null;
|
||||
}
|
||||
$originalUrlFor = str($urlFor)->replace('_', '-');
|
||||
if (str($urlFor)->contains('-')) {
|
||||
$urlFor = str($urlFor)->replace('-', '_')->replace('.', '_');
|
||||
}
|
||||
$url = generateUrl(server: $server, random: "$originalUrlFor-$uuid");
|
||||
// Append port if specified
|
||||
$urlWithPort = $url;
|
||||
if ($port && is_numeric($port)) {
|
||||
$urlWithPort = "$url:$port";
|
||||
}
|
||||
$resource->environment_variables()->firstOrCreate([
|
||||
'key' => $key->value(),
|
||||
'resourceable_type' => get_class($resource),
|
||||
|
|
@ -595,12 +608,12 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
|
|||
$envExists = $resource->environment_variables()->where('key', $key->value())->first();
|
||||
if ($domainExists !== $envExists->value) {
|
||||
$envExists->update([
|
||||
'value' => $url,
|
||||
'value' => $urlWithPort,
|
||||
]);
|
||||
}
|
||||
if (is_null($domainExists)) {
|
||||
$domains->put((string) $urlFor, [
|
||||
'domain' => $url,
|
||||
'domain' => $urlWithPort,
|
||||
]);
|
||||
$resource->docker_compose_domains = $domains->toJson();
|
||||
$resource->save();
|
||||
|
|
@ -1642,8 +1655,17 @@ function serviceParser(Service $resource): Collection
|
|||
$url = generateUrl(server: $server, random: str($fqdnFor)->replace('_', '-')->value()."-$uuid");
|
||||
|
||||
$envExists = $resource->environment_variables()->where('key', $key->value())->first();
|
||||
// Also check if a port-suffixed version exists (e.g., SERVICE_FQDN_UMAMI_3000)
|
||||
$portSuffixedExists = $resource->environment_variables()
|
||||
->where('key', 'LIKE', $key->value().'_%')
|
||||
->whereRaw('key ~ ?', ['^'.$key->value().'_[0-9]+$'])
|
||||
->exists();
|
||||
$serviceExists = ServiceApplication::where('name', str($fqdnFor)->replace('_', '-')->value())->where('service_id', $resource->id)->first();
|
||||
if (! $envExists && (data_get($serviceExists, 'name') === str($fqdnFor)->replace('_', '-')->value())) {
|
||||
// Check if FQDN already has a port set (contains ':' after the domain)
|
||||
$fqdnHasPort = $serviceExists && str($serviceExists->fqdn)->contains(':') && str($serviceExists->fqdn)->afterLast(':')->isMatch('/^\d+$/');
|
||||
// Only set FQDN if it's for the current service being processed (prevent race conditions)
|
||||
$isCurrentService = $serviceExists && $serviceExists->id === $savedService->id;
|
||||
if (! $envExists && ! $portSuffixedExists && ! $fqdnHasPort && $isCurrentService && (data_get($serviceExists, 'name') === str($fqdnFor)->replace('_', '-')->value())) {
|
||||
// Save URL otherwise it won't work.
|
||||
$serviceExists->fqdn = $url;
|
||||
$serviceExists->save();
|
||||
|
|
@ -1662,8 +1684,17 @@ function serviceParser(Service $resource): Collection
|
|||
$url = generateUrl(server: $server, random: str($urlFor)->replace('_', '-')->value()."-$uuid");
|
||||
|
||||
$envExists = $resource->environment_variables()->where('key', $key->value())->first();
|
||||
// Also check if a port-suffixed version exists (e.g., SERVICE_URL_DASHBOARD_6791)
|
||||
$portSuffixedExists = $resource->environment_variables()
|
||||
->where('key', 'LIKE', $key->value().'_%')
|
||||
->whereRaw('key ~ ?', ['^'.$key->value().'_[0-9]+$'])
|
||||
->exists();
|
||||
$serviceExists = ServiceApplication::where('name', str($urlFor)->replace('_', '-')->value())->where('service_id', $resource->id)->first();
|
||||
if (! $envExists && (data_get($serviceExists, 'name') === str($urlFor)->replace('_', '-')->value())) {
|
||||
// Check if FQDN already has a port set (contains ':' after the domain)
|
||||
$fqdnHasPort = $serviceExists && str($serviceExists->fqdn)->contains(':') && str($serviceExists->fqdn)->afterLast(':')->isMatch('/^\d+$/');
|
||||
// Only set FQDN if it's for the current service being processed (prevent race conditions)
|
||||
$isCurrentService = $serviceExists && $serviceExists->id === $savedService->id;
|
||||
if (! $envExists && ! $portSuffixedExists && ! $fqdnHasPort && $isCurrentService && (data_get($serviceExists, 'name') === str($urlFor)->replace('_', '-')->value())) {
|
||||
$serviceExists->fqdn = $url;
|
||||
$serviceExists->save();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue