Merge pull request #1743 from coollabsio/next

v4.0.0-beta.216
This commit is contained in:
Andras Bacsai
2024-02-14 15:21:13 +01:00
committed by GitHub
14 changed files with 106 additions and 68 deletions

View File

@@ -45,6 +45,9 @@ class DeleteService
foreach ($service->databases()->get() as $database) { foreach ($service->databases()->get() as $database) {
$database->forceDelete(); $database->forceDelete();
} }
foreach ($service->scheduled_tasks as $task) {
$task->delete();
}
$service->tags()->detach(); $service->tags()->detach();
} }
} }

View File

@@ -3,6 +3,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Models\Application; use App\Models\Application;
use App\Models\ScheduledTask;
use App\Models\Service; use App\Models\Service;
use App\Models\ServiceApplication; use App\Models\ServiceApplication;
use App\Models\ServiceDatabase; use App\Models\ServiceDatabase;
@@ -108,6 +109,17 @@ class CleanupStuckedResources extends Command
} catch (\Throwable $e) { } catch (\Throwable $e) {
echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n"; echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
} }
try {
$scheduled_tasks = ScheduledTask::all();
foreach ($scheduled_tasks as $scheduled_task) {
if (!$scheduled_task->service && !$scheduled_task->application) {
echo "Deleting stuck scheduledtask: {$scheduled_task->name}\n";
$scheduled_task->delete();
}
}
} catch (\Throwable $e) {
echo "Error in cleaning stuck scheduledtasks: {$e->getMessage()}\n";
}
// Cleanup any resources that are not attached to any environment or destination or server // Cleanup any resources that are not attached to any environment or destination or server
try { try {

View File

@@ -120,8 +120,8 @@ class Kernel extends ConsoleKernel
return; return;
} }
foreach ($scheduled_tasks as $scheduled_task) { foreach ($scheduled_tasks as $scheduled_task) {
$service = $scheduled_task->service()->get(); $service = $scheduled_task->service;
$application = $scheduled_task->application()->get(); $application = $scheduled_task->application;
if (!$application && !$service) { if (!$application && !$service) {
ray('application/service attached to scheduled task does not exist'); ray('application/service attached to scheduled task does not exist');

View File

@@ -16,7 +16,7 @@ class ServerStatusJob implements ShouldQueue, ShouldBeEncrypted
{ {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public ?int $disk_usage = null; public int|string|null $disk_usage = null;
public $tries = 4; public $tries = 4;
public function backoff(): int public function backoff(): int
{ {

View File

@@ -41,7 +41,7 @@ class FileStorage extends Component
$this->fileStorage->content = null; $this->fileStorage->content = null;
} }
$this->fileStorage->save(); $this->fileStorage->save();
$this->fileStorage->saveStorageOnServer($this->service); $this->fileStorage->saveStorageOnServer();
$this->dispatch('success', 'File updated successfully.'); $this->dispatch('success', 'File updated successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->fileStorage->setRawAttributes($original); $this->fileStorage->setRawAttributes($original);

View File

@@ -48,6 +48,9 @@ class Application extends BaseModel
$application->persistentStorages()->delete(); $application->persistentStorages()->delete();
$application->environment_variables()->delete(); $application->environment_variables()->delete();
$application->environment_variables_preview()->delete(); $application->environment_variables_preview()->delete();
foreach ($application->scheduled_tasks as $task) {
$task->delete();
}
$application->tags()->detach(); $application->tags()->detach();
}); });
} }

View File

@@ -13,24 +13,34 @@ class LocalFileVolume extends BaseModel
protected static function booted() protected static function booted()
{ {
static::created(function (LocalFileVolume $fileVolume) { static::created(function (LocalFileVolume $fileVolume) {
$fileVolume->saveStorageOnServer($fileVolume->service); $fileVolume->load(['service']);
$fileVolume->saveStorageOnServer();
}); });
} }
public function service() public function service()
{ {
return $this->morphTo('resource'); return $this->morphTo('resource');
} }
public function saveStorageOnServer(ServiceApplication|ServiceDatabase $service) public function saveStorageOnServer()
{ {
ray('saveStorageOnServer'); $workdir = $this->resource->service->workdir();
$workdir = $service->service->workdir(); $server = $this->resource->service->server;
$server = $service->service->server;
$commands = collect([ $commands = collect([
"mkdir -p $workdir > /dev/null 2>&1 || true", "mkdir -p $workdir > /dev/null 2>&1 || true",
"cd $workdir" "cd $workdir"
]); ]);
$is_directory = $this->is_directory;
if ($is_directory) {
$commands->push("mkdir -p $this->fs_path > /dev/null 2>&1 || true");
}
if (str($this->fs_path)->startsWith('.') || str($this->fs_path)->startsWith('/') || str($this->fs_path)->startsWith('~')) {
$parent_dir = str($this->fs_path)->beforeLast('/');
if ($parent_dir != '') {
$commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
}
}
$fileVolume = $this; $fileVolume = $this;
$path = Str::of(data_get($fileVolume, 'fs_path')); $path = str(data_get($fileVolume, 'fs_path'));
$content = data_get($fileVolume, 'content'); $content = data_get($fileVolume, 'content');
if ($path->startsWith('.')) { if ($path->startsWith('.')) {
$path = $path->after('.'); $path = $path->after('.');
@@ -39,17 +49,18 @@ class LocalFileVolume extends BaseModel
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server); $isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server); $isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
if ($isFile == 'OK' && $fileVolume->is_directory) { if ($isFile == 'OK' && $fileVolume->is_directory) {
throw new \Exception("File $path is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory."); throw new \Exception("The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.");
} else if ($isDir == 'OK' && !$fileVolume->is_directory) { } else if ($isDir == 'OK' && !$fileVolume->is_directory) {
throw new \Exception("File $path is a directory on the server, but you are trying to mark it as a file. Please delete the directory on the server or mark it as directory."); throw new \Exception("The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.");
} }
if (!$fileVolume->is_directory && $isDir == 'NOK') { if (!$fileVolume->is_directory && $isDir == 'NOK') {
if ($content) {
$content = base64_encode($content); $content = base64_encode($content);
$commands->push("echo '$content' | base64 -d > $path"); $commands->push("echo '$content' | base64 -d > $path");
}
} else if ($isDir == 'NOK' && $fileVolume->is_directory) { } else if ($isDir == 'NOK' && $fileVolume->is_directory) {
$commands->push("mkdir -p $path > /dev/null 2>&1 || true"); $commands->push("mkdir -p $path > /dev/null 2>&1 || true");
} }
ray($commands->toArray());
return instant_remote_process($commands, $server); return instant_remote_process($commands, $server);
} }
} }

View File

@@ -125,6 +125,9 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
} }
if (isset($livewire)) { if (isset($livewire)) {
if (str($message)->length() > 20) {
return $livewire->dispatch('error', 'Error occured', $message);
}
return $livewire->dispatch('error', $message); return $livewire->dispatch('error', $message);
} }
throw new Exception($message); throw new Exception($message);
@@ -527,7 +530,10 @@ function getTopLevelNetworks(Service|Application $resource)
$definedNetwork = collect([$resource->uuid]); $definedNetwork = collect([$resource->uuid]);
$services = collect($services)->map(function ($service, $_) use ($topLevelNetworks, $definedNetwork) { $services = collect($services)->map(function ($service, $_) use ($topLevelNetworks, $definedNetwork) {
$serviceNetworks = collect(data_get($service, 'networks', [])); $serviceNetworks = collect(data_get($service, 'networks', []));
$hasHostNetworkMode = data_get($service, 'network_mode') === 'host' ? true : false;
// Only add 'networks' key if 'network_mode' is not 'host'
if (!$hasHostNetworkMode) {
// Collect/create/update networks // Collect/create/update networks
if ($serviceNetworks->count() > 0) { if ($serviceNetworks->count() > 0) {
foreach ($serviceNetworks as $networkName => $networkDetails) { foreach ($serviceNetworks as $networkName => $networkDetails) {
@@ -551,6 +557,7 @@ function getTopLevelNetworks(Service|Application $resource)
]); ]);
} }
} }
}
return $service; return $service;
}); });
@@ -628,6 +635,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
$serviceNetworks = collect(data_get($service, 'networks', [])); $serviceNetworks = collect(data_get($service, 'networks', []));
$serviceVariables = collect(data_get($service, 'environment', [])); $serviceVariables = collect(data_get($service, 'environment', []));
$serviceLabels = collect(data_get($service, 'labels', [])); $serviceLabels = collect(data_get($service, 'labels', []));
$hasHostNetworkMode = data_get($service, 'network_mode') === 'host' ? true : false;
if ($serviceLabels->count() > 0) { if ($serviceLabels->count() > 0) {
$removedLabels = collect([]); $removedLabels = collect([]);
$serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) { $serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
@@ -698,7 +706,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
$savedService->image = $image; $savedService->image = $image;
$savedService->save(); $savedService->save();
} }
// Collect/create/update networks // Collect/create/update networks
if ($serviceNetworks->count() > 0) { if ($serviceNetworks->count() > 0) {
foreach ($serviceNetworks as $networkName => $networkDetails) { foreach ($serviceNetworks as $networkName => $networkDetails) {
@@ -729,6 +736,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
$savedService->ports = $collectedPorts->implode(','); $savedService->ports = $collectedPorts->implode(',');
$savedService->save(); $savedService->save();
if (!$hasHostNetworkMode) {
// Add Coolify specific networks // Add Coolify specific networks
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) { $definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
return $value == $definedNetwork; return $value == $definedNetwork;
@@ -760,6 +768,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
$networks->put($network, null); $networks->put($network, null);
} }
data_set($service, 'networks', $networks->toArray()); data_set($service, 'networks', $networks->toArray());
}
// Collect/create/update volumes // Collect/create/update volumes
if ($serviceVolumes->count() > 0) { if ($serviceVolumes->count() > 0) {

View File

@@ -7,7 +7,7 @@ return [
// The release version of your application // The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
'release' => '4.0.0-beta.215', 'release' => '4.0.0-beta.216',
// When left empty or `null` the Laravel environment will be used // When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'), 'environment' => config('app.env'),

View File

@@ -1,3 +1,3 @@
<?php <?php
return '4.0.0-beta.215'; return '4.0.0-beta.216';

View File

@@ -28,7 +28,7 @@
</form> </form>
<div class="pt-4"> <div class="pt-4">
<h3 class="py-4">Recent executions</h3> <h3 class="py-4">Recent executions <span class="text-xs text-neutral-500">(click to check output)</span></h3>
<livewire:project.shared.scheduled-task.executions key="{{ $task->id }}" selectedKey="" :executions="$task->executions->take(-20)" /> <livewire:project.shared.scheduled-task.executions key="{{ $task->id }}" selectedKey="" :executions="$task->executions->take(-20)" />
</div> </div>
</div> </div>

View File

@@ -4,7 +4,7 @@
services: services:
directus: directus:
image: directus/directus:10.7 image: directus/directus:10
volumes: volumes:
- directus-uploads:/directus/uploads - directus-uploads:/directus/uploads
- directus-extensions:/directus/extensions - directus-extensions:/directus/extensions

View File

@@ -68,7 +68,7 @@
"directus-with-postgresql": { "directus-with-postgresql": {
"documentation": "https:\/\/docs.directus.io\/self-hosted\/quickstart.html", "documentation": "https:\/\/docs.directus.io\/self-hosted\/quickstart.html",
"slogan": "Directus is an open-source tool that wraps custom SQL databases with a dynamic API, and provides an intuitive admin app for managing its content.", "slogan": "Directus is an open-source tool that wraps custom SQL databases with a dynamic API, and provides an intuitive admin app for managing its content.",
"compose": "c2VydmljZXM6CiAgZGlyZWN0dXM6CiAgICBpbWFnZTogJ2RpcmVjdHVzL2RpcmVjdHVzOjEwLjcnCiAgICB2b2x1bWVzOgogICAgICAtICdkaXJlY3R1cy11cGxvYWRzOi9kaXJlY3R1cy91cGxvYWRzJwogICAgICAtICdkaXJlY3R1cy1leHRlbnNpb25zOi9kaXJlY3R1cy9leHRlbnNpb25zJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0RJUkVDVFVTCiAgICAgIC0gS0VZPSRTRVJWSUNFX0JBU0U2NF82NF9LRVkKICAgICAgLSBTRUNSRVQ9JFNFUlZJQ0VfQkFTRTY0XzY0X1NFQ1JFVAogICAgICAtICdBRE1JTl9FTUFJTD0ke0FETUlOX0VNQUlMOi1hZG1pbkBleGFtcGxlLmNvbX0nCiAgICAgIC0gQURNSU5fUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfQURNSU4KICAgICAgLSBEQl9DTElFTlQ9cG9zdGdyZXMKICAgICAgLSBEQl9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBEQl9QT1JUPTU0MzIKICAgICAgLSAnREJfREFUQUJBU0U9JHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1kaXJlY3R1c30nCiAgICAgIC0gREJfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTUUwKICAgICAgLSBEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMCiAgICAgIC0gUkVESVNfSE9TVD1yZWRpcwogICAgICAtIFJFRElTX1BPUlQ9NjM3OQogICAgICAtIFdFQlNPQ0tFVFNfRU5BQkxFRD10cnVlCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAnZGlyZWN0dXMtcG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNRTF9EQVRBQkFTRTotZGlyZWN0dXN9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogIHJlZGlzOgogICAgaW1hZ2U6ICdyZWRpczo3LWFscGluZScKICAgIGNvbW1hbmQ6ICdyZWRpcy1zZXJ2ZXIgLS1hcHBlbmRvbmx5IHllcycKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2RpcmVjdHVzLXJlZGlzLWRhdGE6L2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBwaW5nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK", "compose": "c2VydmljZXM6CiAgZGlyZWN0dXM6CiAgICBpbWFnZTogJ2RpcmVjdHVzL2RpcmVjdHVzOjEwJwogICAgdm9sdW1lczoKICAgICAgLSAnZGlyZWN0dXMtdXBsb2FkczovZGlyZWN0dXMvdXBsb2FkcycKICAgICAgLSAnZGlyZWN0dXMtZXh0ZW5zaW9uczovZGlyZWN0dXMvZXh0ZW5zaW9ucycKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9ESVJFQ1RVUwogICAgICAtIEtFWT0kU0VSVklDRV9CQVNFNjRfNjRfS0VZCiAgICAgIC0gU0VDUkVUPSRTRVJWSUNFX0JBU0U2NF82NF9TRUNSRVQKICAgICAgLSAnQURNSU5fRU1BSUw9JHtBRE1JTl9FTUFJTDotYWRtaW5AZXhhbXBsZS5jb219JwogICAgICAtIEFETUlOX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX0FETUlOCiAgICAgIC0gREJfQ0xJRU5UPXBvc3RncmVzCiAgICAgIC0gREJfSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gREJfUE9SVD01NDMyCiAgICAgIC0gJ0RCX0RBVEFCQVNFPSR7UE9TVEdSRVNRTF9EQVRBQkFTRTotZGlyZWN0dXN9JwogICAgICAtIERCX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMCiAgICAgIC0gREJfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTAogICAgICAtIFJFRElTX0hPU1Q9cmVkaXMKICAgICAgLSBSRURJU19QT1JUPTYzNzkKICAgICAgLSBXRUJTT0NLRVRTX0VOQUJMRUQ9dHJ1ZQogIHBvc3RncmVzcWw6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2LWFscGluZScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2RpcmVjdHVzLXBvc3RncmVzcWwtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTUUxfREFUQUJBU0U6LWRpcmVjdHVzfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICByZWRpczoKICAgIGltYWdlOiAncmVkaXM6Ny1hbHBpbmUnCiAgICBjb21tYW5kOiAncmVkaXMtc2VydmVyIC0tYXBwZW5kb25seSB5ZXMnCiAgICB2b2x1bWVzOgogICAgICAtICdkaXJlY3R1cy1yZWRpcy1kYXRhOi9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIHJlZGlzLWNsaQogICAgICAgIC0gcGluZwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
"tags": [ "tags": [
"directus", "directus",
"cms", "cms",

View File

@@ -4,7 +4,7 @@
"version": "3.12.36" "version": "3.12.36"
}, },
"v4": { "v4": {
"version": "4.0.0-beta.215" "version": "4.0.0-beta.216"
} }
} }
} }