mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
Merge remote-tracking branch 'origin/main' into next
This commit is contained in:
@@ -116,9 +116,15 @@ function queue_application_deployment(Application $application, string $deployme
|
||||
}
|
||||
|
||||
if ($admission['started']) {
|
||||
ApplicationDeploymentJob::dispatch(
|
||||
application_deployment_queue_id: $deployment->id,
|
||||
);
|
||||
try {
|
||||
ApplicationDeploymentJob::dispatch(
|
||||
application_deployment_queue_id: $deployment->id,
|
||||
);
|
||||
} catch (Throwable $exception) {
|
||||
fail_undispatchable_deployment($deployment, $exception);
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -136,10 +142,23 @@ function force_start_deployment(ApplicationDeploymentQueue $deployment): bool
|
||||
{
|
||||
return start_queued_deployment($deployment, force: true);
|
||||
}
|
||||
function queue_next_deployment(Application $application)
|
||||
/**
|
||||
* Start the queued deployments that can run now on the application's primary server, on the
|
||||
* server of the deployment that just ended (an additional server), and on every other server
|
||||
* with a queued deployment of this application, because those waited for this one to end.
|
||||
*/
|
||||
function queue_next_deployment(Application $application, ?int $finished_deployment_server_id = null)
|
||||
{
|
||||
$server_id = $application->destination->server_id;
|
||||
$queued_deployments = ApplicationDeploymentQueue::where('server_id', $server_id)
|
||||
$application_queued_server_ids = ApplicationDeploymentQueue::where('application_id', $application->id)
|
||||
->where('status', ApplicationDeploymentStatus::QUEUED)
|
||||
->distinct()
|
||||
->pluck('server_id');
|
||||
$server_ids = collect([$application->destination->server_id, $finished_deployment_server_id])
|
||||
->merge($application_queued_server_ids)
|
||||
->filter(fn ($server_id) => $server_id !== null)
|
||||
->unique()
|
||||
->values();
|
||||
$queued_deployments = ApplicationDeploymentQueue::whereIn('server_id', $server_ids)
|
||||
->where('status', ApplicationDeploymentStatus::QUEUED)
|
||||
->get()
|
||||
->sortBy('created_at');
|
||||
|
||||
@@ -342,8 +342,9 @@ function isComposeExternalVolume(mixed $declaration): bool
|
||||
/**
|
||||
* Returns the top-level declaration of a volume source when the Compose file declares it as
|
||||
* external, and null for all other sources. The parsers use an external volume as written: no
|
||||
* "{uuid}_" prefix, no preview suffix and no LocalPersistentVolume row, so that Coolify never
|
||||
* removes a volume that it does not own.
|
||||
* "{uuid}_" prefix and no LocalPersistentVolume row, so that Coolify never removes a volume that it
|
||||
* does not own. A preview deployment never uses an external volume; it gets its own volume
|
||||
* "{uuid}_{volume}-pr-{id}" like any other named volume.
|
||||
*
|
||||
* @param iterable<array-key, mixed> $topLevelVolumes
|
||||
* @return array<string, mixed>|null
|
||||
@@ -364,9 +365,11 @@ function composeExternalVolumeDeclaration(iterable $topLevelVolumes, string $sou
|
||||
/**
|
||||
* Tells if a parser uses the volume source as written because it is an external volume.
|
||||
*
|
||||
* Only for production deployments: a preview deployment always gets its own volume.
|
||||
*
|
||||
* Before Coolify used external volumes as written, the parsers renamed them like all other
|
||||
* volumes (the old name, for example "{uuid}_{volume}" or "{uuid}_{volume}-pr-{id}"), so the
|
||||
* resource wrote its data into the renamed volume. When the owner still has the storage entry
|
||||
* volumes (the old name, for example "{uuid}_{volume}"), so the resource wrote its data into the
|
||||
* renamed volume. When the owner still has the storage entry
|
||||
* with the old name, the parser must keep the old name, or the resource loses its data. Then
|
||||
* this function records a warning on the resource and returns false. When the user deletes that
|
||||
* storage entry, the next parse uses the external volume.
|
||||
@@ -431,7 +434,8 @@ function legacyApplicationRenamedVolumeDeclaration(string $name): array
|
||||
* Records a warning when a legacy Compose application (parser version 1 or 2) does not use an
|
||||
* external volume as written. These parsers keep the old volume name (see
|
||||
* legacyApplicationComposeVolumeName()), so the resource keeps its data. The parser version 1 keeps
|
||||
* the name of a production volume, so it uses the external volume and gets no warning.
|
||||
* the name of a production volume, so it uses the external volume and gets no warning. A preview
|
||||
* always uses its own volume, so it gets no warning either.
|
||||
*
|
||||
* The volume names are not validated here, so that the legacy parsers keep their old behavior. The
|
||||
* warning shows the Docker volume name only when it is a literal, valid Docker volume name.
|
||||
@@ -440,6 +444,9 @@ function legacyApplicationRenamedVolumeDeclaration(string $name): array
|
||||
*/
|
||||
function warnLegacyApplicationComposeExternalVolume(Application $resource, iterable $topLevelVolumes, string $source, int $pull_request_id): void
|
||||
{
|
||||
if ($pull_request_id !== 0) {
|
||||
return;
|
||||
}
|
||||
$declaration = collect($topLevelVolumes)->get($source);
|
||||
if (! isComposeExternalVolume($declaration)) {
|
||||
return;
|
||||
@@ -1331,6 +1338,7 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
|
||||
}
|
||||
|
||||
// Parse the rest of the services
|
||||
$previewOwnExternalVolumes = collect([]);
|
||||
foreach ($services as $serviceName => $service) {
|
||||
$image = data_get_str($service, 'image');
|
||||
$restart = data_get_str($service, 'restart', RESTART_MODE);
|
||||
@@ -1481,16 +1489,21 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
|
||||
}
|
||||
}
|
||||
} elseif ($type->value() === 'volume') {
|
||||
$legacyName = "{$uuid}_".Str::slug($source, '-');
|
||||
if ($isPullRequest) {
|
||||
$legacyName = addPreviewDeploymentSuffix($legacyName, $pull_request_id);
|
||||
}
|
||||
if (useComposeExternalVolumeAsWritten($resource, $originalResource, $topLevel->get('volumes'), $source->value(), $legacyName)) {
|
||||
// Previews share the external volume. It gets no row, so Coolify never removes it.
|
||||
// A preview never mounts an external volume: two deployments that write into the same
|
||||
// data directory (for example two databases) can corrupt it. The preview gets its own
|
||||
// volume with the name that older Coolify versions gave it, so it keeps its data, and
|
||||
// the preview cleanup removes it.
|
||||
$isPreviewOwnExternalVolume = $isPullRequest
|
||||
&& composeExternalVolumeDeclaration($topLevel->get('volumes'), $source->value()) !== null;
|
||||
if (! $isPullRequest && useComposeExternalVolumeAsWritten($resource, $originalResource, $topLevel->get('volumes'), $source->value(), "{$uuid}_".Str::slug($source, '-'))) {
|
||||
// The external volume gets no row, so Coolify never removes it.
|
||||
$volumesParsed->put($index, $volume);
|
||||
|
||||
continue;
|
||||
}
|
||||
if ($isPreviewOwnExternalVolume) {
|
||||
$previewOwnExternalVolumes->put($source->value(), true);
|
||||
}
|
||||
$declaration = $topLevel->get('volumes')->get($source->value());
|
||||
if (in_array(data_get($declaration, 'driver_opts.type'), ['cifs', 'nfs'], true)) {
|
||||
// Network volumes are used as written.
|
||||
@@ -1529,7 +1542,9 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
|
||||
'resource_type' => get_class($originalResource),
|
||||
]
|
||||
);
|
||||
$topLevel->get('volumes')->put($name, composeRenamedVolumeDeclarationFor($declaration, $name, $persistentVolume, $isPullRequest));
|
||||
$topLevel->get('volumes')->put($name, $isPreviewOwnExternalVolume
|
||||
? ['name' => $name]
|
||||
: composeRenamedVolumeDeclarationFor($declaration, $name, $persistentVolume, $isPullRequest));
|
||||
}
|
||||
dispatch(new ServerFilesFromServerJob($originalResource));
|
||||
$volumesParsed->put($index, $volume);
|
||||
@@ -2134,6 +2149,8 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
|
||||
|
||||
$parsedServices->put($serviceName, $payload);
|
||||
}
|
||||
// The preview mounts its own volumes instead of these external volumes (see above), so it does not declare them.
|
||||
$topLevel->put('volumes', $topLevel->get('volumes')->except($previewOwnExternalVolumes->keys()->all()));
|
||||
$topLevel->put('services', $parsedServices);
|
||||
|
||||
$customOrder = ['services', 'volumes', 'networks', 'configs', 'secrets'];
|
||||
|
||||
Reference in New Issue
Block a user