mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-14 06:17:36 +00:00
fix(compose): normalize service-name keys for domains and env vars (#11040)
This commit is contained in:
1 parent
7b18777f06
commit
0b843bb07c
18 files changed
+1443
-220
No files matched your search
@@ -301,12 +301,7 @@ class General extends Component
|
||||
}
|
||||
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
|
||||
// Convert service names with dots and dashes to use underscores for HTML form binding
|
||||
$sanitizedDomains = [];
|
||||
foreach ($this->parsedServiceDomains as $serviceName => $domain) {
|
||||
$sanitizedKey = str($serviceName)->replace('-', '_')->replace('.', '_')->toString();
|
||||
$sanitizedDomains[$sanitizedKey] = $domain;
|
||||
}
|
||||
$this->parsedServiceDomains = $sanitizedDomains;
|
||||
$this->parsedServiceDomains = $this->sanitizeParsedServiceDomainsForForm($this->parsedServiceDomains);
|
||||
|
||||
$this->customLabels = $this->application->parseContainerLabels();
|
||||
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && $this->application->settings->is_container_label_readonly_enabled === true) {
|
||||
@@ -520,12 +515,7 @@ class General extends Component
|
||||
|
||||
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
|
||||
// Convert service names with dots and dashes to use underscores for HTML form binding
|
||||
$sanitizedDomains = [];
|
||||
foreach ($this->parsedServiceDomains as $serviceName => $domain) {
|
||||
$sanitizedKey = str($serviceName)->replace('-', '_')->replace('.', '_')->toString();
|
||||
$sanitizedDomains[$sanitizedKey] = $domain;
|
||||
}
|
||||
$this->parsedServiceDomains = $sanitizedDomains;
|
||||
$this->parsedServiceDomains = $this->sanitizeParsedServiceDomainsForForm($this->parsedServiceDomains);
|
||||
|
||||
$showToast && $this->dispatch('success', 'Docker compose file loaded.');
|
||||
$this->dispatch('compose_loaded');
|
||||
@@ -551,22 +541,14 @@ class General extends Component
|
||||
|
||||
$uuid = new_public_id();
|
||||
$domain = generateUrl(server: $this->application->destination->server, random: $uuid);
|
||||
$sanitizedKey = str($serviceName)->replace('-', '_')->replace('.', '_')->toString();
|
||||
$sanitizedKey = normalizeComposeServiceName($serviceName);
|
||||
$this->parsedServiceDomains[$sanitizedKey]['domain'] = $domain;
|
||||
|
||||
// Convert back to original service names for storage
|
||||
$originalDomains = [];
|
||||
$composeServiceNames = collect(data_get($this->parsedServices, 'services', []))->keys()->map(fn ($name) => (string) $name)->values()->all();
|
||||
foreach ($this->parsedServiceDomains as $key => $value) {
|
||||
// Find the original service name by checking parsed services
|
||||
$originalServiceName = $key;
|
||||
if (isset($this->parsedServices['services'])) {
|
||||
foreach ($this->parsedServices['services'] as $originalName => $service) {
|
||||
if (str($originalName)->replace('-', '_')->replace('.', '_')->toString() === $key) {
|
||||
$originalServiceName = $originalName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$originalServiceName = findComposeServiceName((string) $key, $composeServiceNames) ?? (string) $key;
|
||||
$originalDomains[$originalServiceName] = $value;
|
||||
}
|
||||
|
||||
@@ -858,9 +840,10 @@ class General extends Component
|
||||
foreach ($this->parsedServiceDomains as $serviceName => $service) {
|
||||
$this->parsedServiceDomains[$serviceName]['domain'] = ValidationPatterns::normalizeApplicationDomains(data_get($service, 'domain'));
|
||||
}
|
||||
$this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
|
||||
$originalDomains = $this->composeDomainsForStorage();
|
||||
$this->application->docker_compose_domains = json_encode($originalDomains);
|
||||
if ($this->application->isDirty('docker_compose_domains')) {
|
||||
foreach ($this->parsedServiceDomains as $service) {
|
||||
foreach ($originalDomains as $service) {
|
||||
$domain = data_get($service, 'domain');
|
||||
if ($domain) {
|
||||
if (! validateDNSEntry($domain, $this->application->destination->server)) {
|
||||
@@ -985,4 +968,58 @@ class General extends Component
|
||||
'{workdir}/.env'
|
||||
);
|
||||
}
|
||||
|
||||
private function composeDomainsForStorage(): array
|
||||
{
|
||||
return rekeyComposeDomainsToServiceNames(
|
||||
$this->parsedServiceDomains,
|
||||
collect(data_get($this->parsedServices, 'services', []))->keys(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse domain map keys to underscore form keys for Livewire/HTML binding.
|
||||
* When twin keys exist, prefer a filled domain over a blank one.
|
||||
*
|
||||
* @param array<string, mixed> $domains
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function sanitizeParsedServiceDomainsForForm(array $domains): array
|
||||
{
|
||||
$sanitizedDomains = [];
|
||||
|
||||
foreach ($domains as $serviceName => $domain) {
|
||||
$sanitizedKey = normalizeComposeServiceName((string) $serviceName);
|
||||
if (! array_key_exists($sanitizedKey, $sanitizedDomains)) {
|
||||
$sanitizedDomains[$sanitizedKey] = $domain;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$existing = $sanitizedDomains[$sanitizedKey];
|
||||
if (is_object($existing)) {
|
||||
$existing = (array) $existing;
|
||||
}
|
||||
if (is_object($domain)) {
|
||||
$domain = (array) $domain;
|
||||
}
|
||||
if (! is_array($existing)) {
|
||||
$existing = ['domain' => $existing];
|
||||
}
|
||||
if (! is_array($domain)) {
|
||||
$domain = ['domain' => $domain];
|
||||
}
|
||||
|
||||
$merged = array_merge($existing, $domain);
|
||||
$merged['domain'] = preferComposeDomainValue(
|
||||
$existing['domain'] ?? null,
|
||||
false,
|
||||
$domain['domain'] ?? null,
|
||||
false,
|
||||
);
|
||||
$sanitizedDomains[$sanitizedKey] = $merged;
|
||||
}
|
||||
|
||||
return $sanitizedDomains;
|
||||
}
|
||||
}
|
||||
@@ -39,13 +39,7 @@ class PreviewsCompose extends Component
|
||||
]);
|
||||
|
||||
$this->domain = ValidationPatterns::normalizeApplicationDomains($this->domain);
|
||||
|
||||
$docker_compose_domains = data_get($this->preview, 'docker_compose_domains');
|
||||
$docker_compose_domains = json_decode($docker_compose_domains, true) ?: [];
|
||||
$docker_compose_domains[$this->serviceName] = $docker_compose_domains[$this->serviceName] ?? [];
|
||||
$docker_compose_domains[$this->serviceName]['domain'] = $this->domain;
|
||||
$this->preview->docker_compose_domains = json_encode($docker_compose_domains);
|
||||
$this->preview->save();
|
||||
$this->persistPreviewDomain($this->domain);
|
||||
$this->dispatch('update_links');
|
||||
$this->dispatch('success', 'Domain saved.');
|
||||
} catch (\Throwable $e) {
|
||||
@@ -58,12 +52,8 @@ class PreviewsCompose extends Component
|
||||
try {
|
||||
$this->authorize('update', $this->preview->application);
|
||||
|
||||
$domains = collect(json_decode($this->preview->application->docker_compose_domains, true) ?: []);
|
||||
$domain = $domains->first(function ($_, $key) {
|
||||
return $key === $this->serviceName;
|
||||
});
|
||||
|
||||
$domain_string = data_get($domain, 'domain');
|
||||
$applicationDomains = json_decode($this->preview->application->docker_compose_domains ?: '[]', true) ?: [];
|
||||
$domain_string = getComposeServiceDomainString($applicationDomains, (string) $this->serviceName);
|
||||
|
||||
// If no domain is set in the main application, generate a default domain
|
||||
if (empty($domain_string)) {
|
||||
@@ -111,14 +101,8 @@ class PreviewsCompose extends Component
|
||||
$preview_fqdn = implode(',', $preview_fqdns);
|
||||
}
|
||||
|
||||
// Save the generated domain
|
||||
$this->domain = $preview_fqdn;
|
||||
$docker_compose_domains = data_get($this->preview, 'docker_compose_domains');
|
||||
$docker_compose_domains = json_decode($docker_compose_domains, true) ?: [];
|
||||
$docker_compose_domains[$this->serviceName] = $docker_compose_domains[$this->serviceName] ?? [];
|
||||
$docker_compose_domains[$this->serviceName]['domain'] = $this->domain;
|
||||
$this->preview->docker_compose_domains = json_encode($docker_compose_domains);
|
||||
$this->preview->save();
|
||||
$this->persistPreviewDomain($this->domain);
|
||||
|
||||
$this->dispatch('update_links');
|
||||
$this->dispatch('success', 'Domain generated.');
|
||||
@@ -126,4 +110,56 @@ class PreviewsCompose extends Component
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
private function persistPreviewDomain(?string $domain): void
|
||||
{
|
||||
$docker_compose_domains = json_decode(data_get($this->preview, 'docker_compose_domains') ?: '[]', true) ?: [];
|
||||
$serviceNames = $this->previewServiceNames($docker_compose_domains);
|
||||
$storageKey = findComposeServiceName((string) $this->serviceName, $serviceNames)
|
||||
?? (string) $this->serviceName;
|
||||
|
||||
$docker_compose_domains = putComposeServiceDomain(
|
||||
$docker_compose_domains,
|
||||
$storageKey,
|
||||
$domain,
|
||||
$serviceNames,
|
||||
);
|
||||
$docker_compose_domains = rekeyComposeDomainsToServiceNames($docker_compose_domains, $serviceNames);
|
||||
|
||||
$this->serviceName = $storageKey;
|
||||
$this->preview->docker_compose_domains = json_encode($docker_compose_domains);
|
||||
$this->preview->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $previewDomains
|
||||
* @return list<string>
|
||||
*/
|
||||
private function previewServiceNames(array $previewDomains): array
|
||||
{
|
||||
$parsedServices = $this->preview->application->parse(pull_request_id: $this->preview->pull_request_id);
|
||||
$fromCompose = collect(data_get($parsedServices, 'services', []))
|
||||
->keys()
|
||||
->map(function ($serviceName) {
|
||||
return str((string) $serviceName)
|
||||
->replaceLast('-pr-'.$this->preview->pull_request_id, '')
|
||||
->toString();
|
||||
})
|
||||
->all();
|
||||
|
||||
$domainKeys = collect(array_keys($previewDomains))
|
||||
->merge(array_keys(json_decode($this->preview->application->docker_compose_domains ?: '[]', true) ?: []))
|
||||
->map(fn ($name) => (string) $name);
|
||||
$unmapped = $domainKeys
|
||||
->reject(fn (string $key) => findComposeServiceName($key, $fromCompose) !== null)
|
||||
->all();
|
||||
|
||||
return collect($fromCompose)
|
||||
->merge(preferredComposeServiceNamesFromDomainKeys(
|
||||
$fromCompose === [] ? $domainKeys->all() : $unmapped
|
||||
))
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user