Merge branch 'next' into feat/disable-default-redirect

This commit is contained in:
Kael
2024-10-31 23:57:51 +11:00
committed by GitHub
180 changed files with 2400 additions and 1911 deletions

View File

@@ -23,3 +23,4 @@ yarn-error.log
.rnd .rnd
/.ssh /.ssh
.ignition.json .ignition.json
.env.dusk.local

View File

@@ -53,8 +53,6 @@ jobs:
tags: | tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
labels: |
coolify.managed=true
aarch64: aarch64:
runs-on: [self-hosted, arm64] runs-on: [self-hosted, arm64]
@@ -90,8 +88,6 @@ jobs:
tags: | tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
labels: |
coolify.managed=true
merge-manifest: merge-manifest:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -48,8 +48,6 @@ jobs:
tags: | tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
labels: |
coolify.managed=true
aarch64: aarch64:
runs-on: [self-hosted, arm64] runs-on: [self-hosted, arm64]
@@ -83,8 +81,6 @@ jobs:
tags: | tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64
labels: |
coolify.managed=true
merge-manifest: merge-manifest:
runs-on: ubuntu-latest runs-on: ubuntu-latest

1
.gitignore vendored
View File

@@ -33,3 +33,4 @@ _ide_helper_models.php
/.ssh /.ssh
scripts/load-test/* scripts/load-test/*
.ignition.json .ignition.json
.env.dusk.local

View File

@@ -11,8 +11,6 @@ class GenerateConfig
public function handle(Application $application, bool $is_json = false) public function handle(Application $application, bool $is_json = false)
{ {
ray()->clearAll();
return $application->generateConfig(is_json: $is_json); return $application->generateConfig(is_json: $is_json);
} }
} }

View File

@@ -17,7 +17,6 @@ class StopApplication
if (! $server->isFunctional()) { if (! $server->isFunctional()) {
return 'Server is not functional'; return 'Server is not functional';
} }
ray('Stopping application: '.$application->name);
if ($server->isSwarm()) { if ($server->isSwarm()) {
instant_remote_process(["docker stack rm {$application->uuid}"], $server); instant_remote_process(["docker stack rm {$application->uuid}"], $server);
@@ -36,8 +35,6 @@ class StopApplication
CleanupDocker::dispatch($server, true); CleanupDocker::dispatch($server, true);
} }
} catch (\Exception $e) { } catch (\Exception $e) {
ray($e->getMessage());
return $e->getMessage(); return $e->getMessage();
} }
} }

View File

@@ -32,8 +32,6 @@ class StopApplicationOneServer
} }
} }
} catch (\Exception $e) { } catch (\Exception $e) {
ray($e->getMessage());
return $e->getMessage(); return $e->getMessage();
} }
} }

View File

@@ -48,7 +48,6 @@ class PrepareCoolifyTask
call_event_data: $this->remoteProcessArgs->call_event_data, call_event_data: $this->remoteProcessArgs->call_event_data,
); );
if ($this->remoteProcessArgs->type === ActivityTypes::COMMAND->value) { if ($this->remoteProcessArgs->type === ActivityTypes::COMMAND->value) {
ray('Dispatching a high priority job');
dispatch($job)->onQueue('high'); dispatch($job)->onQueue('high');
} else { } else {
dispatch($job); dispatch($job);

View File

@@ -125,7 +125,6 @@ class RunRemoteProcess
])); ]));
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e);
} }
} }

View File

@@ -23,28 +23,28 @@ class StartDatabase
return 'Server is not functional'; return 'Server is not functional';
} }
switch ($database->getMorphClass()) { switch ($database->getMorphClass()) {
case 'App\Models\StandalonePostgresql': case \App\Models\StandalonePostgresql::class:
$activity = StartPostgresql::run($database); $activity = StartPostgresql::run($database);
break; break;
case 'App\Models\StandaloneRedis': case \App\Models\StandaloneRedis::class:
$activity = StartRedis::run($database); $activity = StartRedis::run($database);
break; break;
case 'App\Models\StandaloneMongodb': case \App\Models\StandaloneMongodb::class:
$activity = StartMongodb::run($database); $activity = StartMongodb::run($database);
break; break;
case 'App\Models\StandaloneMysql': case \App\Models\StandaloneMysql::class:
$activity = StartMysql::run($database); $activity = StartMysql::run($database);
break; break;
case 'App\Models\StandaloneMariadb': case \App\Models\StandaloneMariadb::class:
$activity = StartMariadb::run($database); $activity = StartMariadb::run($database);
break; break;
case 'App\Models\StandaloneKeydb': case \App\Models\StandaloneKeydb::class:
$activity = StartKeydb::run($database); $activity = StartKeydb::run($database);
break; break;
case 'App\Models\StandaloneDragonfly': case \App\Models\StandaloneDragonfly::class:
$activity = StartDragonfly::run($database); $activity = StartDragonfly::run($database);
break; break;
case 'App\Models\StandaloneClickhouse': case \App\Models\StandaloneClickhouse::class:
$activity = StartClickhouse::run($database); $activity = StartClickhouse::run($database);
break; break;
} }

View File

@@ -26,7 +26,7 @@ class StartDatabaseProxy
$server = data_get($database, 'destination.server'); $server = data_get($database, 'destination.server');
$containerName = data_get($database, 'uuid'); $containerName = data_get($database, 'uuid');
$proxyContainerName = "{$database->uuid}-proxy"; $proxyContainerName = "{$database->uuid}-proxy";
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') { if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
$databaseType = $database->databaseType(); $databaseType = $database->databaseType();
// $connectPredefined = data_get($database, 'service.connect_to_docker_network'); // $connectPredefined = data_get($database, 'service.connect_to_docker_network');
$network = $database->service->uuid; $network = $database->service->uuid;
@@ -34,54 +34,54 @@ class StartDatabaseProxy
$proxyContainerName = "{$database->service->uuid}-proxy"; $proxyContainerName = "{$database->service->uuid}-proxy";
switch ($databaseType) { switch ($databaseType) {
case 'standalone-mariadb': case 'standalone-mariadb':
$type = 'App\Models\StandaloneMariadb'; $type = \App\Models\StandaloneMariadb::class;
$containerName = "mariadb-{$database->service->uuid}"; $containerName = "mariadb-{$database->service->uuid}";
break; break;
case 'standalone-mongodb': case 'standalone-mongodb':
$type = 'App\Models\StandaloneMongodb'; $type = \App\Models\StandaloneMongodb::class;
$containerName = "mongodb-{$database->service->uuid}"; $containerName = "mongodb-{$database->service->uuid}";
break; break;
case 'standalone-mysql': case 'standalone-mysql':
$type = 'App\Models\StandaloneMysql'; $type = \App\Models\StandaloneMysql::class;
$containerName = "mysql-{$database->service->uuid}"; $containerName = "mysql-{$database->service->uuid}";
break; break;
case 'standalone-postgresql': case 'standalone-postgresql':
$type = 'App\Models\StandalonePostgresql'; $type = \App\Models\StandalonePostgresql::class;
$containerName = "postgresql-{$database->service->uuid}"; $containerName = "postgresql-{$database->service->uuid}";
break; break;
case 'standalone-redis': case 'standalone-redis':
$type = 'App\Models\StandaloneRedis'; $type = \App\Models\StandaloneRedis::class;
$containerName = "redis-{$database->service->uuid}"; $containerName = "redis-{$database->service->uuid}";
break; break;
case 'standalone-keydb': case 'standalone-keydb':
$type = 'App\Models\StandaloneKeydb'; $type = \App\Models\StandaloneKeydb::class;
$containerName = "keydb-{$database->service->uuid}"; $containerName = "keydb-{$database->service->uuid}";
break; break;
case 'standalone-dragonfly': case 'standalone-dragonfly':
$type = 'App\Models\StandaloneDragonfly'; $type = \App\Models\StandaloneDragonfly::class;
$containerName = "dragonfly-{$database->service->uuid}"; $containerName = "dragonfly-{$database->service->uuid}";
break; break;
case 'standalone-clickhouse': case 'standalone-clickhouse':
$type = 'App\Models\StandaloneClickhouse'; $type = \App\Models\StandaloneClickhouse::class;
$containerName = "clickhouse-{$database->service->uuid}"; $containerName = "clickhouse-{$database->service->uuid}";
break; break;
} }
} }
if ($type === 'App\Models\StandaloneRedis') { if ($type === \App\Models\StandaloneRedis::class) {
$internalPort = 6379; $internalPort = 6379;
} elseif ($type === 'App\Models\StandalonePostgresql') { } elseif ($type === \App\Models\StandalonePostgresql::class) {
$internalPort = 5432; $internalPort = 5432;
} elseif ($type === 'App\Models\StandaloneMongodb') { } elseif ($type === \App\Models\StandaloneMongodb::class) {
$internalPort = 27017; $internalPort = 27017;
} elseif ($type === 'App\Models\StandaloneMysql') { } elseif ($type === \App\Models\StandaloneMysql::class) {
$internalPort = 3306; $internalPort = 3306;
} elseif ($type === 'App\Models\StandaloneMariadb') { } elseif ($type === \App\Models\StandaloneMariadb::class) {
$internalPort = 3306; $internalPort = 3306;
} elseif ($type === 'App\Models\StandaloneKeydb') { } elseif ($type === \App\Models\StandaloneKeydb::class) {
$internalPort = 6379; $internalPort = 6379;
} elseif ($type === 'App\Models\StandaloneDragonfly') { } elseif ($type === \App\Models\StandaloneDragonfly::class) {
$internalPort = 6379; $internalPort = 6379;
} elseif ($type === 'App\Models\StandaloneClickhouse') { } elseif ($type === \App\Models\StandaloneClickhouse::class) {
$internalPort = 9000; $internalPort = 9000;
} }
$configuration_dir = database_proxy_dir($database->uuid); $configuration_dir = database_proxy_dir($database->uuid);

View File

@@ -22,7 +22,7 @@ class StopDatabaseProxy
{ {
$server = data_get($database, 'destination.server'); $server = data_get($database, 'destination.server');
$uuid = $database->uuid; $uuid = $database->uuid;
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') { if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
$uuid = $database->service->uuid; $uuid = $database->service->uuid;
$server = data_get($database, 'service.server'); $server = data_get($database, 'service.server');
} }

View File

@@ -6,12 +6,11 @@ use App\Models\User;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;
use Laravel\Fortify\Contracts\CreatesNewUsers; use Laravel\Fortify\Contracts\CreatesNewUsers;
class CreateNewUser implements CreatesNewUsers class CreateNewUser implements CreatesNewUsers
{ {
use PasswordValidationRules;
/** /**
* Validate and create a newly registered user. * Validate and create a newly registered user.
* *
@@ -32,7 +31,7 @@ class CreateNewUser implements CreatesNewUsers
'max:255', 'max:255',
Rule::unique(User::class), Rule::unique(User::class),
], ],
'password' => $this->passwordRules(), 'password' => ['required', Password::defaults(), 'confirmed'],
])->validate(); ])->validate();
if (User::count() == 0) { if (User::count() == 0) {

View File

@@ -1,18 +0,0 @@
<?php
namespace App\Actions\Fortify;
use Laravel\Fortify\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array<int, \Illuminate\Contracts\Validation\Rule|array|string>
*/
protected function passwordRules(): array
{
return ['required', 'string', new Password, 'confirmed'];
}
}

View File

@@ -5,12 +5,11 @@ namespace App\Actions\Fortify;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;
use Laravel\Fortify\Contracts\ResetsUserPasswords; use Laravel\Fortify\Contracts\ResetsUserPasswords;
class ResetUserPassword implements ResetsUserPasswords class ResetUserPassword implements ResetsUserPasswords
{ {
use PasswordValidationRules;
/** /**
* Validate and reset the user's forgotten password. * Validate and reset the user's forgotten password.
* *
@@ -19,7 +18,7 @@ class ResetUserPassword implements ResetsUserPasswords
public function reset(User $user, array $input): void public function reset(User $user, array $input): void
{ {
Validator::make($input, [ Validator::make($input, [
'password' => $this->passwordRules(), 'password' => ['required', Password::defaults(), 'confirmed'],
])->validate(); ])->validate();
$user->forceFill([ $user->forceFill([

View File

@@ -5,12 +5,11 @@ namespace App\Actions\Fortify;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;
use Laravel\Fortify\Contracts\UpdatesUserPasswords; use Laravel\Fortify\Contracts\UpdatesUserPasswords;
class UpdateUserPassword implements UpdatesUserPasswords class UpdateUserPassword implements UpdatesUserPasswords
{ {
use PasswordValidationRules;
/** /**
* Validate and update the user's password. * Validate and update the user's password.
* *
@@ -20,7 +19,7 @@ class UpdateUserPassword implements UpdatesUserPasswords
{ {
Validator::make($input, [ Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'], 'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(), 'password' => ['required', Password::defaults(), 'confirmed'],
], [ ], [
'current_password.current_password' => __('The provided password does not match your current password.'), 'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword'); ])->validateWithBag('updatePassword');

View File

@@ -25,8 +25,6 @@ class CheckResaleLicense
// } // }
$base_url = config('coolify.license_url'); $base_url = config('coolify.license_url');
$instance_id = config('app.id'); $instance_id = config('app.id');
ray("Checking license key against $base_url/lemon/validate");
$data = Http::withHeaders([ $data = Http::withHeaders([
'Accept' => 'application/json', 'Accept' => 'application/json',
])->get("$base_url/lemon/validate", [ ])->get("$base_url/lemon/validate", [
@@ -34,7 +32,6 @@ class CheckResaleLicense
'instance_id' => $instance_id, 'instance_id' => $instance_id,
])->json(); ])->json();
if (data_get($data, 'valid') === true && data_get($data, 'license_key.status') === 'active') { if (data_get($data, 'valid') === true && data_get($data, 'license_key.status') === 'active') {
ray('Valid & active license key');
$settings->update([ $settings->update([
'is_resale_license_active' => true, 'is_resale_license_active' => true,
]); ]);
@@ -48,7 +45,6 @@ class CheckResaleLicense
'instance_id' => $instance_id, 'instance_id' => $instance_id,
])->json(); ])->json();
if (data_get($data, 'activated') === true) { if (data_get($data, 'activated') === true) {
ray('Activated license key');
$settings->update([ $settings->update([
'is_resale_license_active' => true, 'is_resale_license_active' => true,
]); ]);
@@ -60,7 +56,6 @@ class CheckResaleLicense
} }
throw new \Exception('Cannot activate license key.'); throw new \Exception('Cannot activate license key.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e);
$settings->update([ $settings->update([
'resale_license' => null, 'resale_license' => null,
'is_resale_license_active' => false, 'is_resale_license_active' => false,

View File

@@ -88,7 +88,6 @@ class CheckProxy
$portsToCheck = []; $portsToCheck = [];
} }
} catch (\Exception $e) { } catch (\Exception $e) {
ray($e->getMessage());
} }
if (count($portsToCheck) === 0) { if (count($portsToCheck) === 0) {
return false; return false;

View File

@@ -13,67 +13,63 @@ class StartProxy
public function handle(Server $server, bool $async = true, bool $force = false): string|Activity public function handle(Server $server, bool $async = true, bool $force = false): string|Activity
{ {
try { $proxyType = $server->proxyType();
$proxyType = $server->proxyType(); if ((is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop || $server->isBuildServer()) && $force === false) {
if ((is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop || $server->isBuildServer()) && $force === false) { return 'OK';
return 'OK';
}
$commands = collect([]);
$proxy_path = $server->proxyPath();
$configuration = CheckConfiguration::run($server);
if (! $configuration) {
throw new \Exception('Configuration is not synced');
}
SaveConfiguration::run($server, $configuration);
$docker_compose_yml_base64 = base64_encode($configuration);
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value();
$server->save();
if ($server->isSwarm()) {
$commands = $commands->merge([
"mkdir -p $proxy_path/dynamic",
"cd $proxy_path",
"echo 'Creating required Docker Compose file.'",
"echo 'Starting coolify-proxy.'",
'docker stack deploy -c docker-compose.yml coolify-proxy',
"echo 'Successfully started coolify-proxy.'",
]);
} else {
$caddfile = 'import /dynamic/*.caddy';
$commands = $commands->merge([
"mkdir -p $proxy_path/dynamic",
"cd $proxy_path",
"echo '$caddfile' > $proxy_path/dynamic/Caddyfile",
"echo 'Creating required Docker Compose file.'",
"echo 'Pulling docker image.'",
'docker compose pull',
'if docker ps -a --format "{{.Names}}" | grep -q "^coolify-proxy$"; then',
" echo 'Stopping and removing existing coolify-proxy.'",
' docker rm -f coolify-proxy || true',
" echo 'Successfully stopped and removed existing coolify-proxy.'",
'fi',
"echo 'Starting coolify-proxy.'",
'docker compose up -d --remove-orphans',
"echo 'Successfully started coolify-proxy.'",
]);
$commands = $commands->merge(connectProxyToNetworks($server));
}
if ($async) {
$activity = remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server);
return $activity;
} else {
instant_remote_process($commands, $server);
$server->proxy->set('status', 'running');
$server->proxy->set('type', $proxyType);
$server->save();
ProxyStarted::dispatch($server);
return 'OK';
}
} catch (\Throwable $e) {
ray($e);
throw $e;
} }
$commands = collect([]);
$proxy_path = $server->proxyPath();
$configuration = CheckConfiguration::run($server);
if (! $configuration) {
throw new \Exception('Configuration is not synced');
}
SaveConfiguration::run($server, $configuration);
$docker_compose_yml_base64 = base64_encode($configuration);
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value();
$server->save();
if ($server->isSwarm()) {
$commands = $commands->merge([
"mkdir -p $proxy_path/dynamic",
"cd $proxy_path",
"echo 'Creating required Docker Compose file.'",
"echo 'Starting coolify-proxy.'",
'docker stack deploy -c docker-compose.yml coolify-proxy',
"echo 'Successfully started coolify-proxy.'",
]);
} else {
$caddfile = 'import /dynamic/*.caddy';
$commands = $commands->merge([
"mkdir -p $proxy_path/dynamic",
"cd $proxy_path",
"echo '$caddfile' > $proxy_path/dynamic/Caddyfile",
"echo 'Creating required Docker Compose file.'",
"echo 'Pulling docker image.'",
'docker compose pull',
'if docker ps -a --format "{{.Names}}" | grep -q "^coolify-proxy$"; then',
" echo 'Stopping and removing existing coolify-proxy.'",
' docker rm -f coolify-proxy || true',
" echo 'Successfully stopped and removed existing coolify-proxy.'",
'fi',
"echo 'Starting coolify-proxy.'",
'docker compose up -d --remove-orphans',
"echo 'Successfully started coolify-proxy.'",
]);
$commands = $commands->merge(connectProxyToNetworks($server));
}
if ($async) {
$activity = remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server);
return $activity;
} else {
instant_remote_process($commands, $server);
$server->proxy->set('status', 'running');
$server->proxy->set('type', $proxyType);
$server->save();
ProxyStarted::dispatch($server);
return 'OK';
}
} }
} }

View File

@@ -40,7 +40,6 @@ class ConfigureCloudflared
]); ]);
instant_remote_process($commands, $server); instant_remote_process($commands, $server);
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e);
$server->settings->is_cloudflare_tunnel = false; $server->settings->is_cloudflare_tunnel = false;
$server->settings->save(); $server->settings->save();
throw $e; throw $e;

View File

@@ -16,7 +16,6 @@ class InstallDocker
if (! $supported_os_type) { if (! $supported_os_type) {
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.'); throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
} }
ray('Installing Docker on server: '.$server->name.' ('.$server->ip.')'.' with OS type: '.$supported_os_type);
$dockerVersion = '26.0'; $dockerVersion = '26.0';
$config = base64_encode('{ $config = base64_encode('{
"log-driver": "json-file", "log-driver": "json-file",

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Actions\Server;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
class RestartContainer
{
use AsAction;
public function handle(Server $server, string $containerName)
{
$server->restartContainer($containerName);
}
}

View File

@@ -5,7 +5,7 @@ namespace App\Actions\Server;
use App\Models\Server; use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction; use Lorisleiva\Actions\Concerns\AsAction;
class InstallLogDrain class StartLogDrain
{ {
use AsAction; use AsAction;
@@ -13,12 +13,16 @@ class InstallLogDrain
{ {
if ($server->settings->is_logdrain_newrelic_enabled) { if ($server->settings->is_logdrain_newrelic_enabled) {
$type = 'newrelic'; $type = 'newrelic';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_highlight_enabled) { } elseif ($server->settings->is_logdrain_highlight_enabled) {
$type = 'highlight'; $type = 'highlight';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_axiom_enabled) { } elseif ($server->settings->is_logdrain_axiom_enabled) {
$type = 'axiom'; $type = 'axiom';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_custom_enabled) { } elseif ($server->settings->is_logdrain_custom_enabled) {
$type = 'custom'; $type = 'custom';
StopLogDrain::run($server);
} else { } else {
$type = 'none'; $type = 'none';
} }
@@ -151,6 +155,8 @@ services:
- ./parsers.conf:/parsers.conf - ./parsers.conf:/parsers.conf
ports: ports:
- 127.0.0.1:24224:24224 - 127.0.0.1:24224:24224
labels:
- coolify.managed=true
restart: unless-stopped restart: unless-stopped
'); ');
$readme = base64_encode('# New Relic Log Drain $readme = base64_encode('# New Relic Log Drain
@@ -202,15 +208,11 @@ Files:
throw new \Exception('Unknown log drain type.'); throw new \Exception('Unknown log drain type.');
} }
$restart_command = [ $restart_command = [
"echo 'Stopping old Fluent Bit'",
"cd $config_path && docker compose down --remove-orphans || true",
"echo 'Starting Fluent Bit'", "echo 'Starting Fluent Bit'",
"cd $config_path && docker compose up -d --remove-orphans", "cd $config_path && docker compose up -d",
]; ];
$command = array_merge($command, $add_envs_command, $restart_command); $command = array_merge($command, $add_envs_command, $restart_command);
StopLogDrain::run($server);
return instant_remote_process($command, $server); return instant_remote_process($command, $server);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e); return handleError($e);

View File

@@ -23,6 +23,7 @@ class StartSentinel
$pushInterval = data_get($server, 'settings.sentinel_push_interval_seconds'); $pushInterval = data_get($server, 'settings.sentinel_push_interval_seconds');
$token = data_get($server, 'settings.sentinel_token'); $token = data_get($server, 'settings.sentinel_token');
$endpoint = data_get($server, 'settings.sentinel_custom_url'); $endpoint = data_get($server, 'settings.sentinel_custom_url');
$debug = data_get($server, 'settings.is_sentinel_debug_enabled');
$mountDir = '/data/coolify/sentinel'; $mountDir = '/data/coolify/sentinel';
$image = "ghcr.io/coollabsio/sentinel:$version"; $image = "ghcr.io/coollabsio/sentinel:$version";
if (! $endpoint) { if (! $endpoint) {
@@ -30,6 +31,7 @@ class StartSentinel
} }
$environments = [ $environments = [
'TOKEN' => $token, 'TOKEN' => $token,
'DEBUG' => $debug ? 'true' : 'false',
'PUSH_ENDPOINT' => $endpoint, 'PUSH_ENDPOINT' => $endpoint,
'PUSH_INTERVAL_SECONDS' => $pushInterval, 'PUSH_INTERVAL_SECONDS' => $pushInterval,
'COLLECTOR_ENABLED' => $server->isMetricsEnabled() ? 'true' : 'false', 'COLLECTOR_ENABLED' => $server->isMetricsEnabled() ? 'true' : 'false',

View File

@@ -12,7 +12,7 @@ class StopLogDrain
public function handle(Server $server) public function handle(Server $server)
{ {
try { try {
return instant_remote_process(['docker rm -f coolify-log-drain || true'], $server); return instant_remote_process(['docker rm -f coolify-log-drain'], $server, false);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e); return handleError($e);
} }

View File

@@ -18,32 +18,28 @@ class UpdateCoolify
public function handle($manual_update = false) public function handle($manual_update = false)
{ {
try { $settings = instanceSettings();
$settings = instanceSettings(); $this->server = Server::find(0);
$this->server = Server::find(0); if (! $this->server) {
if (! $this->server) { return;
}
CleanupDocker::dispatch($this->server)->onQueue('high');
$this->latestVersion = get_latest_version_of_coolify();
$this->currentVersion = config('version');
if (! $manual_update) {
if (! $settings->is_auto_update_enabled) {
return; return;
} }
CleanupDocker::dispatch($this->server)->onQueue('high'); if ($this->latestVersion === $this->currentVersion) {
$this->latestVersion = get_latest_version_of_coolify(); return;
$this->currentVersion = config('version'); }
if (! $manual_update) { if (version_compare($this->latestVersion, $this->currentVersion, '<')) {
if (! $settings->is_auto_update_enabled) { return;
return;
}
if ($this->latestVersion === $this->currentVersion) {
return;
}
if (version_compare($this->latestVersion, $this->currentVersion, '<')) {
return;
}
} }
$this->update();
$settings->new_version_available = false;
$settings->save();
} catch (\Throwable $e) {
throw $e;
} }
$this->update();
$settings->new_version_available = false;
$settings->save();
} }
private function update() private function update()

View File

@@ -40,7 +40,6 @@ class DeleteService
foreach ($commands as $command) { foreach ($commands as $command) {
$result = instant_remote_process([$command], $server, false); $result = instant_remote_process([$command], $server, false);
if ($result !== 0) { if ($result !== 0) {
ray("Failed to execute: $command");
} }
} }
} }

View File

@@ -12,7 +12,6 @@ class StartService
public function handle(Service $service) public function handle(Service $service)
{ {
ray('Starting service: '.$service->name);
$service->saveComposeConfigs(); $service->saveComposeConfigs();
$commands[] = 'cd '.$service->workdir(); $commands[] = 'cd '.$service->workdir();
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'"; $commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";

View File

@@ -28,8 +28,6 @@ class StopService
} }
} }
} catch (\Exception $e) { } catch (\Exception $e) {
ray($e->getMessage());
return $e->getMessage(); return $e->getMessage();
} }
} }

View File

@@ -30,7 +30,6 @@ class CleanupStuckedResources extends Command
public function handle() public function handle()
{ {
ray('Running cleanup stucked resources.');
echo "Running cleanup stucked resources.\n"; echo "Running cleanup stucked resources.\n";
$this->cleanup_stucked_resources(); $this->cleanup_stucked_resources();
} }

View File

@@ -19,7 +19,6 @@ class CloudCleanupSubscriptions extends Command
return; return;
} }
ray()->clearAll();
$this->info('Cleaning up subcriptions teams'); $this->info('Cleaning up subcriptions teams');
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));

View File

@@ -124,7 +124,6 @@ class Emails extends Command
$applications = Application::all(); $applications = Application::all();
foreach ($applications as $application) { foreach ($applications as $application) {
$deployments = $application->get_last_days_deployments(); $deployments = $application->get_last_days_deployments();
ray($deployments);
if ($deployments->isEmpty()) { if ($deployments->isEmpty()) {
continue; continue;
} }

View File

@@ -180,7 +180,7 @@ class Init extends Command
'save_s3' => false, 'save_s3' => false,
'frequency' => '0 0 * * *', 'frequency' => '0 0 * * *',
'database_id' => $database->id, 'database_id' => $database->id,
'database_type' => 'App\Models\StandalonePostgresql', 'database_type' => \App\Models\StandalonePostgresql::class,
'team_id' => 0, 'team_id' => 0,
]); ]);
} }
@@ -219,7 +219,6 @@ class Init extends Command
} }
$queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get(); $queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
foreach ($queued_inprogress_deployments as $deployment) { foreach ($queued_inprogress_deployments as $deployment) {
ray($deployment->id, $deployment->status);
echo "Cleaning up deployment: {$deployment->id}\n"; echo "Cleaning up deployment: {$deployment->id}\n";
$deployment->status = ApplicationDeploymentStatus::FAILED->value; $deployment->status = ApplicationDeploymentStatus::FAILED->value;
$deployment->save(); $deployment->save();

View File

@@ -36,8 +36,6 @@ class NotifyDemo extends Command
return; return;
} }
ray($channel);
} }
private function showHelp() private function showHelp()

View File

@@ -12,6 +12,7 @@ use App\Jobs\DockerCleanupJob;
use App\Jobs\PullTemplatesFromCDN; use App\Jobs\PullTemplatesFromCDN;
use App\Jobs\ScheduledTaskJob; use App\Jobs\ScheduledTaskJob;
use App\Jobs\ServerCheckJob; use App\Jobs\ServerCheckJob;
use App\Jobs\ServerCleanupMux;
use App\Jobs\UpdateCoolifyJob; use App\Jobs\UpdateCoolifyJob;
use App\Models\ScheduledDatabaseBackup; use App\Models\ScheduledDatabaseBackup;
use App\Models\ScheduledTask; use App\Models\ScheduledTask;
@@ -120,6 +121,15 @@ class Kernel extends ConsoleKernel
} else { } else {
$schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer(); $schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer();
} }
// Cleanup multiplexed connections every hour
$schedule->job(new ServerCleanupMux($server))->hourly()->onOneServer();
// Temporary solution until we have better memory management for Sentinel
if ($server->isSentinelEnabled()) {
$schedule->job(function () use ($server) {
$server->restartContainer('coolify-sentinel');
})->daily()->onOneServer();
}
} }
} }
@@ -134,7 +144,6 @@ class Kernel extends ConsoleKernel
continue; continue;
} }
if (is_null(data_get($scheduled_backup, 'database'))) { if (is_null(data_get($scheduled_backup, 'database'))) {
ray('database not found');
$scheduled_backup->delete(); $scheduled_backup->delete();
continue; continue;
@@ -170,7 +179,6 @@ class Kernel extends ConsoleKernel
$application = $scheduled_task->application; $application = $scheduled_task->application;
if (! $application && ! $service) { if (! $application && ! $service) {
ray('application/service attached to scheduled task does not exist');
$scheduled_task->delete(); $scheduled_task->delete();
continue; continue;

37
app/Enums/Role.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
namespace App\Enums;
enum Role: string
{
case MEMBER = 'member';
case ADMIN = 'admin';
case OWNER = 'owner';
public function rank(): int
{
return match ($this) {
self::MEMBER => 1,
self::ADMIN => 2,
self::OWNER => 3,
};
}
public function lt(Role|string $role): bool
{
if (is_string($role)) {
$role = Role::from($role);
}
return $this->rank() < $role->rank();
}
public function gt(Role|string $role): bool
{
if (is_string($role)) {
$role = Role::from($role);
}
return $this->rank() > $role->rank();
}
}

View File

@@ -16,7 +16,6 @@ class FileStorageChanged implements ShouldBroadcast
public function __construct($teamId = null) public function __construct($teamId = null)
{ {
ray($teamId);
if (is_null($teamId)) { if (is_null($teamId)) {
throw new \Exception('Team id is null'); throw new \Exception('Team id is null');
} }

View File

@@ -84,7 +84,6 @@ class Handler extends ExceptionHandler
if (str($e->getMessage())->contains('No space left on device')) { if (str($e->getMessage())->contains('No space left on device')) {
return; return;
} }
ray('reporting to sentry');
Integration::captureUnhandledException($e); Integration::captureUnhandledException($e);
}); });
} }

View File

@@ -292,7 +292,7 @@ class DeployController extends Controller
return ['message' => "Resource ($resource) not found.", 'deployment_uuid' => $deployment_uuid]; return ['message' => "Resource ($resource) not found.", 'deployment_uuid' => $deployment_uuid];
} }
switch ($resource?->getMorphClass()) { switch ($resource?->getMorphClass()) {
case 'App\Models\Application': case \App\Models\Application::class:
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
queue_application_deployment( queue_application_deployment(
application: $resource, application: $resource,
@@ -301,7 +301,7 @@ class DeployController extends Controller
); );
$message = "Application {$resource->name} deployment queued."; $message = "Application {$resource->name} deployment queued.";
break; break;
case 'App\Models\Service': case \App\Models\Service::class:
StartService::run($resource); StartService::run($resource);
$message = "Service {$resource->name} started. It could take a while, be patient."; $message = "Service {$resource->name} started. It could take a while, be patient.";
break; break;

View File

@@ -53,7 +53,7 @@ class ResourcesController extends Controller
$resources = $resources->flatten(); $resources = $resources->flatten();
$resources = $resources->map(function ($resource) { $resources = $resources->map(function ($resource) {
$payload = $resource->toArray(); $payload = $resource->toArray();
if ($resource->getMorphClass() === 'App\Models\Service') { if ($resource->getMorphClass() === \App\Models\Service::class) {
$payload['status'] = $resource->status(); $payload['status'] = $resource->status();
} else { } else {
$payload['status'] = $resource->status; $payload['status'] = $resource->status;

View File

@@ -249,7 +249,6 @@ class ServersController extends Controller
return $payload; return $payload;
}); });
$server = $this->removeSensitiveData($server); $server = $this->removeSensitiveData($server);
ray($server);
return response()->json(serializeApiResponse(data_get($server, 'resources'))); return response()->json(serializeApiResponse(data_get($server, 'resources')));
} }

View File

@@ -112,57 +112,48 @@ class Controller extends BaseController
public function accept_invitation() public function accept_invitation()
{ {
try { $resetPassword = request()->query('reset-password');
$resetPassword = request()->query('reset-password'); $invitationUuid = request()->route('uuid');
$invitationUuid = request()->route('uuid'); $invitation = TeamInvitation::whereUuid($invitationUuid)->firstOrFail();
$invitation = TeamInvitation::whereUuid($invitationUuid)->firstOrFail(); $user = User::whereEmail($invitation->email)->firstOrFail();
$user = User::whereEmail($invitation->email)->firstOrFail(); $invitationValid = $invitation->isValid();
$invitationValid = $invitation->isValid(); if ($invitationValid) {
if ($invitationValid) { if ($resetPassword) {
if ($resetPassword) { $user->update([
$user->update([ 'password' => Hash::make($invitationUuid),
'password' => Hash::make($invitationUuid), 'force_password_reset' => true,
'force_password_reset' => true, ]);
]); }
} if ($user->teams()->where('team_id', $invitation->team->id)->exists()) {
if ($user->teams()->where('team_id', $invitation->team->id)->exists()) {
$invitation->delete();
return redirect()->route('team.index');
}
$user->teams()->attach($invitation->team->id, ['role' => $invitation->role]);
$invitation->delete(); $invitation->delete();
if (auth()->user()?->id !== $user->id) {
return redirect()->route('login');
}
refreshSession($invitation->team);
return redirect()->route('team.index'); return redirect()->route('team.index');
} else {
abort(401);
} }
} catch (\Throwable $e) { $user->teams()->attach($invitation->team->id, ['role' => $invitation->role]);
ray($e->getMessage()); $invitation->delete();
throw $e; if (auth()->user()?->id !== $user->id) {
return redirect()->route('login');
}
refreshSession($invitation->team);
return redirect()->route('team.index');
} else {
abort(401);
} }
} }
public function revoke_invitation() public function revoke_invitation()
{ {
try { $invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();
$invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail(); $user = User::whereEmail($invitation->email)->firstOrFail();
$user = User::whereEmail($invitation->email)->firstOrFail(); if (is_null(auth()->user())) {
if (is_null(auth()->user())) { return redirect()->route('login');
return redirect()->route('login');
}
if (auth()->user()->id !== $user->id) {
abort(401);
}
$invitation->delete();
return redirect()->route('team.index');
} catch (\Throwable $e) {
throw $e;
} }
if (auth()->user()->id !== $user->id) {
abort(401);
}
$invitation->delete();
return redirect()->route('team.index');
} }
} }

View File

@@ -35,8 +35,6 @@ class OauthController extends Controller
return redirect('/'); return redirect('/');
} catch (\Exception $e) { } catch (\Exception $e) {
ray($e->getMessage());
$errorCode = $e instanceof HttpException ? 'auth.failed' : 'auth.failed.callback'; $errorCode = $e instanceof HttpException ? 'auth.failed' : 'auth.failed.callback';
return redirect()->route('login')->withErrors([__($errorCode)]); return redirect()->route('login')->withErrors([__($errorCode)]);

View File

@@ -16,7 +16,6 @@ class Bitbucket extends Controller
{ {
try { try {
if (app()->isDownForMaintenance()) { if (app()->isDownForMaintenance()) {
ray('Maintenance mode is on');
$epoch = now()->valueOf(); $epoch = now()->valueOf();
$data = [ $data = [
'attributes' => $request->attributes->all(), 'attributes' => $request->attributes->all(),
@@ -55,7 +54,6 @@ class Bitbucket extends Controller
'message' => 'Nothing to do. No branch found in the request.', 'message' => 'Nothing to do. No branch found in the request.',
]); ]);
} }
ray('Manual webhook bitbucket push event with branch: '.$branch);
} }
if ($x_bitbucket_event === 'pullrequest:created' || $x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') { if ($x_bitbucket_event === 'pullrequest:created' || $x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
$branch = data_get($payload, 'pullrequest.destination.branch.name'); $branch = data_get($payload, 'pullrequest.destination.branch.name');
@@ -85,7 +83,6 @@ class Bitbucket extends Controller
'status' => 'failed', 'status' => 'failed',
'message' => 'Invalid signature.', 'message' => 'Invalid signature.',
]); ]);
ray('Invalid signature');
continue; continue;
} }
@@ -96,13 +93,11 @@ class Bitbucket extends Controller
'status' => 'failed', 'status' => 'failed',
'message' => 'Server is not functional.', 'message' => 'Server is not functional.',
]); ]);
ray('Server is not functional: '.$application->destination->server->name);
continue; continue;
} }
if ($x_bitbucket_event === 'repo:push') { if ($x_bitbucket_event === 'repo:push') {
if ($application->isDeployable()) { if ($application->isDeployable()) {
ray('Deploying '.$application->name.' with branch '.$branch);
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
queue_application_deployment( queue_application_deployment(
application: $application, application: $application,
@@ -126,7 +121,6 @@ class Bitbucket extends Controller
} }
if ($x_bitbucket_event === 'pullrequest:created') { if ($x_bitbucket_event === 'pullrequest:created') {
if ($application->isPRDeployable()) { if ($application->isPRDeployable()) {
ray('Deploying preview for '.$application->name.' with branch '.$branch.' and base branch '.$base_branch.' and pull request id '.$pull_request_id);
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found) { if (! $found) {
@@ -171,7 +165,6 @@ class Bitbucket extends Controller
} }
} }
if ($x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') { if ($x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
ray('Pull request rejected');
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
if ($found) { if ($found) {
$found->delete(); $found->delete();
@@ -191,12 +184,9 @@ class Bitbucket extends Controller
} }
} }
} }
ray($return_payloads);
return response($return_payloads); return response($return_payloads);
} catch (Exception $e) { } catch (Exception $e) {
ray($e);
return handleError($e); return handleError($e);
} }
} }

View File

@@ -19,15 +19,12 @@ class Gitea extends Controller
$return_payloads = collect([]); $return_payloads = collect([]);
$x_gitea_delivery = request()->header('X-Gitea-Delivery'); $x_gitea_delivery = request()->header('X-Gitea-Delivery');
if (app()->isDownForMaintenance()) { if (app()->isDownForMaintenance()) {
ray('Maintenance mode is on');
$epoch = now()->valueOf(); $epoch = now()->valueOf();
$files = Storage::disk('webhooks-during-maintenance')->files(); $files = Storage::disk('webhooks-during-maintenance')->files();
$gitea_delivery_found = collect($files)->filter(function ($file) use ($x_gitea_delivery) { $gitea_delivery_found = collect($files)->filter(function ($file) use ($x_gitea_delivery) {
return Str::contains($file, $x_gitea_delivery); return Str::contains($file, $x_gitea_delivery);
})->first(); })->first();
if ($gitea_delivery_found) { if ($gitea_delivery_found) {
ray('Webhook already found');
return; return;
} }
$data = [ $data = [
@@ -67,8 +64,6 @@ class Gitea extends Controller
$removed_files = data_get($payload, 'commits.*.removed'); $removed_files = data_get($payload, 'commits.*.removed');
$modified_files = data_get($payload, 'commits.*.modified'); $modified_files = data_get($payload, 'commits.*.modified');
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
ray($changed_files);
ray('Manual Webhook Gitea Push Event with branch: '.$branch);
} }
if ($x_gitea_event === 'pull_request') { if ($x_gitea_event === 'pull_request') {
$action = data_get($payload, 'action'); $action = data_get($payload, 'action');
@@ -77,7 +72,6 @@ class Gitea extends Controller
$pull_request_html_url = data_get($payload, 'pull_request.html_url'); $pull_request_html_url = data_get($payload, 'pull_request.html_url');
$branch = data_get($payload, 'pull_request.head.ref'); $branch = data_get($payload, 'pull_request.head.ref');
$base_branch = data_get($payload, 'pull_request.base.ref'); $base_branch = data_get($payload, 'pull_request.base.ref');
ray('Webhook Gitea Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id);
} }
if (! $branch) { if (! $branch) {
return response('Nothing to do. No branch found in the request.'); return response('Nothing to do. No branch found in the request.');
@@ -99,7 +93,6 @@ class Gitea extends Controller
$webhook_secret = data_get($application, 'manual_webhook_secret_gitea'); $webhook_secret = data_get($application, 'manual_webhook_secret_gitea');
$hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret); $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) { if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) {
ray('Invalid signature');
$return_payloads->push([ $return_payloads->push([
'application' => $application->name, 'application' => $application->name,
'status' => 'failed', 'status' => 'failed',
@@ -122,7 +115,6 @@ class Gitea extends Controller
if ($application->isDeployable()) { if ($application->isDeployable()) {
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
if ($is_watch_path_triggered || is_null($application->watch_paths)) { if ($is_watch_path_triggered || is_null($application->watch_paths)) {
ray('Deploying '.$application->name.' with branch '.$branch);
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
queue_application_deployment( queue_application_deployment(
application: $application, application: $application,
@@ -228,12 +220,9 @@ class Gitea extends Controller
} }
} }
} }
ray($return_payloads);
return response($return_payloads); return response($return_payloads);
} catch (Exception $e) { } catch (Exception $e) {
ray($e->getMessage());
return handleError($e); return handleError($e);
} }
} }

View File

@@ -25,15 +25,12 @@ class Github extends Controller
$return_payloads = collect([]); $return_payloads = collect([]);
$x_github_delivery = request()->header('X-GitHub-Delivery'); $x_github_delivery = request()->header('X-GitHub-Delivery');
if (app()->isDownForMaintenance()) { if (app()->isDownForMaintenance()) {
ray('Maintenance mode is on');
$epoch = now()->valueOf(); $epoch = now()->valueOf();
$files = Storage::disk('webhooks-during-maintenance')->files(); $files = Storage::disk('webhooks-during-maintenance')->files();
$github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) { $github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) {
return Str::contains($file, $x_github_delivery); return Str::contains($file, $x_github_delivery);
})->first(); })->first();
if ($github_delivery_found) { if ($github_delivery_found) {
ray('Webhook already found');
return; return;
} }
$data = [ $data = [
@@ -73,7 +70,6 @@ class Github extends Controller
$removed_files = data_get($payload, 'commits.*.removed'); $removed_files = data_get($payload, 'commits.*.removed');
$modified_files = data_get($payload, 'commits.*.modified'); $modified_files = data_get($payload, 'commits.*.modified');
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
ray('Manual Webhook GitHub Push Event with branch: '.$branch);
} }
if ($x_github_event === 'pull_request') { if ($x_github_event === 'pull_request') {
$action = data_get($payload, 'action'); $action = data_get($payload, 'action');
@@ -82,7 +78,6 @@ class Github extends Controller
$pull_request_html_url = data_get($payload, 'pull_request.html_url'); $pull_request_html_url = data_get($payload, 'pull_request.html_url');
$branch = data_get($payload, 'pull_request.head.ref'); $branch = data_get($payload, 'pull_request.head.ref');
$base_branch = data_get($payload, 'pull_request.base.ref'); $base_branch = data_get($payload, 'pull_request.base.ref');
ray('Webhook GitHub Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id);
} }
if (! $branch) { if (! $branch) {
return response('Nothing to do. No branch found in the request.'); return response('Nothing to do. No branch found in the request.');
@@ -104,7 +99,6 @@ class Github extends Controller
$webhook_secret = data_get($application, 'manual_webhook_secret_github'); $webhook_secret = data_get($application, 'manual_webhook_secret_github');
$hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret); $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) { if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) {
ray('Invalid signature');
$return_payloads->push([ $return_payloads->push([
'application' => $application->name, 'application' => $application->name,
'status' => 'failed', 'status' => 'failed',
@@ -127,7 +121,6 @@ class Github extends Controller
if ($application->isDeployable()) { if ($application->isDeployable()) {
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
if ($is_watch_path_triggered || is_null($application->watch_paths)) { if ($is_watch_path_triggered || is_null($application->watch_paths)) {
ray('Deploying '.$application->name.' with branch '.$branch);
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
queue_application_deployment( queue_application_deployment(
application: $application, application: $application,
@@ -232,12 +225,9 @@ class Github extends Controller
} }
} }
} }
ray($return_payloads);
return response($return_payloads); return response($return_payloads);
} catch (Exception $e) { } catch (Exception $e) {
ray($e->getMessage());
return handleError($e); return handleError($e);
} }
} }
@@ -249,15 +239,12 @@ class Github extends Controller
$id = null; $id = null;
$x_github_delivery = $request->header('X-GitHub-Delivery'); $x_github_delivery = $request->header('X-GitHub-Delivery');
if (app()->isDownForMaintenance()) { if (app()->isDownForMaintenance()) {
ray('Maintenance mode is on');
$epoch = now()->valueOf(); $epoch = now()->valueOf();
$files = Storage::disk('webhooks-during-maintenance')->files(); $files = Storage::disk('webhooks-during-maintenance')->files();
$github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) { $github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) {
return Str::contains($file, $x_github_delivery); return Str::contains($file, $x_github_delivery);
})->first(); })->first();
if ($github_delivery_found) { if ($github_delivery_found) {
ray('Webhook already found');
return; return;
} }
$data = [ $data = [
@@ -313,7 +300,6 @@ class Github extends Controller
$removed_files = data_get($payload, 'commits.*.removed'); $removed_files = data_get($payload, 'commits.*.removed');
$modified_files = data_get($payload, 'commits.*.modified'); $modified_files = data_get($payload, 'commits.*.modified');
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
ray('Webhook GitHub Push Event: '.$id.' with branch: '.$branch);
} }
if ($x_github_event === 'pull_request') { if ($x_github_event === 'pull_request') {
$action = data_get($payload, 'action'); $action = data_get($payload, 'action');
@@ -322,7 +308,6 @@ class Github extends Controller
$pull_request_html_url = data_get($payload, 'pull_request.html_url'); $pull_request_html_url = data_get($payload, 'pull_request.html_url');
$branch = data_get($payload, 'pull_request.head.ref'); $branch = data_get($payload, 'pull_request.head.ref');
$base_branch = data_get($payload, 'pull_request.base.ref'); $base_branch = data_get($payload, 'pull_request.base.ref');
ray('Webhook GitHub Pull Request Event: '.$id.' with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id);
} }
if (! $id || ! $branch) { if (! $id || ! $branch) {
return response('Nothing to do. No id or branch found.'); return response('Nothing to do. No id or branch found.');
@@ -356,7 +341,6 @@ class Github extends Controller
if ($application->isDeployable()) { if ($application->isDeployable()) {
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
if ($is_watch_path_triggered || is_null($application->watch_paths)) { if ($is_watch_path_triggered || is_null($application->watch_paths)) {
ray('Deploying '.$application->name.' with branch '.$branch);
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
queue_application_deployment( queue_application_deployment(
application: $application, application: $application,
@@ -460,8 +444,6 @@ class Github extends Controller
return response($return_payloads); return response($return_payloads);
} catch (Exception $e) { } catch (Exception $e) {
ray($e->getMessage());
return handleError($e); return handleError($e);
} }
} }
@@ -505,7 +487,6 @@ class Github extends Controller
try { try {
$installation_id = $request->get('installation_id'); $installation_id = $request->get('installation_id');
if (app()->isDownForMaintenance()) { if (app()->isDownForMaintenance()) {
ray('Maintenance mode is on');
$epoch = now()->valueOf(); $epoch = now()->valueOf();
$data = [ $data = [
'attributes' => $request->attributes->all(), 'attributes' => $request->attributes->all(),

View File

@@ -17,7 +17,6 @@ class Gitlab extends Controller
{ {
try { try {
if (app()->isDownForMaintenance()) { if (app()->isDownForMaintenance()) {
ray('Maintenance mode is on');
$epoch = now()->valueOf(); $epoch = now()->valueOf();
$data = [ $data = [
'attributes' => $request->attributes->all(), 'attributes' => $request->attributes->all(),
@@ -67,7 +66,6 @@ class Gitlab extends Controller
$removed_files = data_get($payload, 'commits.*.removed'); $removed_files = data_get($payload, 'commits.*.removed');
$modified_files = data_get($payload, 'commits.*.modified'); $modified_files = data_get($payload, 'commits.*.modified');
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
ray('Manual Webhook GitLab Push Event with branch: '.$branch);
} }
if ($x_gitlab_event === 'merge_request') { if ($x_gitlab_event === 'merge_request') {
$action = data_get($payload, 'object_attributes.action'); $action = data_get($payload, 'object_attributes.action');
@@ -84,7 +82,6 @@ class Gitlab extends Controller
return response($return_payloads); return response($return_payloads);
} }
ray('Webhook GitHub Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id);
} }
$applications = Application::where('git_repository', 'like', "%$full_name%"); $applications = Application::where('git_repository', 'like', "%$full_name%");
if ($x_gitlab_event === 'push') { if ($x_gitlab_event === 'push') {
@@ -117,7 +114,6 @@ class Gitlab extends Controller
'status' => 'failed', 'status' => 'failed',
'message' => 'Invalid signature.', 'message' => 'Invalid signature.',
]); ]);
ray('Invalid signature');
continue; continue;
} }
@@ -128,7 +124,6 @@ class Gitlab extends Controller
'status' => 'failed', 'status' => 'failed',
'message' => 'Server is not functional', 'message' => 'Server is not functional',
]); ]);
ray('Server is not functional: '.$application->destination->server->name);
continue; continue;
} }
@@ -136,7 +131,6 @@ class Gitlab extends Controller
if ($application->isDeployable()) { if ($application->isDeployable()) {
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
if ($is_watch_path_triggered || is_null($application->watch_paths)) { if ($is_watch_path_triggered || is_null($application->watch_paths)) {
ray('Deploying '.$application->name.' with branch '.$branch);
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
queue_application_deployment( queue_application_deployment(
application: $application, application: $application,
@@ -171,7 +165,6 @@ class Gitlab extends Controller
'application_uuid' => $application->uuid, 'application_uuid' => $application->uuid,
'application_name' => $application->name, 'application_name' => $application->name,
]); ]);
ray('Deployments disabled for '.$application->name);
} }
} }
if ($x_gitlab_event === 'merge_request') { if ($x_gitlab_event === 'merge_request') {
@@ -207,7 +200,6 @@ class Gitlab extends Controller
is_webhook: true, is_webhook: true,
git_type: 'gitlab' git_type: 'gitlab'
); );
ray('Deploying preview for '.$application->name.' with branch '.$branch.' and base branch '.$base_branch.' and pull request id '.$pull_request_id);
$return_payloads->push([ $return_payloads->push([
'application' => $application->name, 'application' => $application->name,
'status' => 'success', 'status' => 'success',
@@ -219,7 +211,6 @@ class Gitlab extends Controller
'status' => 'failed', 'status' => 'failed',
'message' => 'Preview deployments disabled', 'message' => 'Preview deployments disabled',
]); ]);
ray('Preview deployments disabled for '.$application->name);
} }
} elseif ($action === 'closed' || $action === 'close' || $action === 'merge') { } elseif ($action === 'closed' || $action === 'close' || $action === 'merge') {
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
@@ -253,8 +244,6 @@ class Gitlab extends Controller
return response($return_payloads); return response($return_payloads);
} catch (Exception $e) { } catch (Exception $e) {
ray($e->getMessage());
return handleError($e); return handleError($e);
} }
} }

View File

@@ -22,7 +22,6 @@ class Stripe extends Controller
{ {
try { try {
if (app()->isDownForMaintenance()) { if (app()->isDownForMaintenance()) {
ray('Maintenance mode is on');
$epoch = now()->valueOf(); $epoch = now()->valueOf();
$data = [ $data = [
'attributes' => $request->attributes->all(), 'attributes' => $request->attributes->all(),

View File

@@ -13,7 +13,6 @@ class Waitlist extends Controller
{ {
$email = request()->get('email'); $email = request()->get('email');
$confirmation_code = request()->get('confirmation_code'); $confirmation_code = request()->get('confirmation_code');
ray($email, $confirmation_code);
try { try {
$found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first(); $found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first();
if ($found) { if ($found) {
@@ -36,7 +35,6 @@ class Waitlist extends Controller
return redirect()->route('dashboard'); return redirect()->route('dashboard');
} catch (Exception $e) { } catch (Exception $e) {
send_internal_notification('Waitlist confirmation failed: '.$e->getMessage()); send_internal_notification('Waitlist confirmation failed: '.$e->getMessage());
ray($e->getMessage());
return redirect()->route('dashboard'); return redirect()->route('dashboard');
} }
@@ -58,7 +56,6 @@ class Waitlist extends Controller
return redirect()->route('dashboard'); return redirect()->route('dashboard');
} catch (Exception $e) { } catch (Exception $e) {
send_internal_notification('Waitlist cancellation failed: '.$e->getMessage()); send_internal_notification('Waitlist cancellation failed: '.$e->getMessage());
ray($e->getMessage());
return redirect()->route('dashboard'); return redirect()->route('dashboard');
} }

View File

@@ -10,7 +10,6 @@ class ApiAllowed
{ {
public function handle(Request $request, Closure $next): Response public function handle(Request $request, Closure $next): Response
{ {
ray()->clearAll();
if (isCloud()) { if (isCloud()) {
return $next($request); return $next($request);
} }

View File

@@ -208,7 +208,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$this->container_name = "{$this->application->settings->custom_internal_name}-pr-{$this->pull_request_id}"; $this->container_name = "{$this->application->settings->custom_internal_name}-pr-{$this->pull_request_id}";
} }
} }
ray('New container name: ', $this->container_name)->green();
$this->saved_outputs = collect(); $this->saved_outputs = collect();
@@ -298,7 +297,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
if ($this->pull_request_id !== 0 && $this->application->is_github_based()) { if ($this->pull_request_id !== 0 && $this->application->is_github_based()) {
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::ERROR); ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::ERROR);
} }
ray($e);
$this->fail($e); $this->fail($e);
throw $e; throw $e;
} finally { } finally {
@@ -389,7 +387,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
} else { } else {
$this->dockerImageTag = $this->application->docker_registry_image_tag; $this->dockerImageTag = $this->application->docker_registry_image_tag;
} }
ray("echo 'Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.'");
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}."); $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.");
$this->generate_image_names(); $this->generate_image_names();
$this->prepare_builder_image(); $this->prepare_builder_image();
@@ -712,38 +709,26 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
{ {
$forceFail = true; $forceFail = true;
if (str($this->application->docker_registry_image_name)->isEmpty()) { if (str($this->application->docker_registry_image_name)->isEmpty()) {
ray('empty docker_registry_image_name');
return; return;
} }
if ($this->restart_only) { if ($this->restart_only) {
ray('restart_only');
return; return;
} }
if ($this->application->build_pack === 'dockerimage') { if ($this->application->build_pack === 'dockerimage') {
ray('dockerimage');
return; return;
} }
if ($this->use_build_server) { if ($this->use_build_server) {
ray('use_build_server');
$forceFail = true; $forceFail = true;
} }
if ($this->server->isSwarm() && $this->build_pack !== 'dockerimage') { if ($this->server->isSwarm() && $this->build_pack !== 'dockerimage') {
ray('isSwarm');
$forceFail = true; $forceFail = true;
} }
if ($this->application->additional_servers->count() > 0) { if ($this->application->additional_servers->count() > 0) {
ray('additional_servers');
$forceFail = true; $forceFail = true;
} }
if ($this->is_this_additional_server) { if ($this->is_this_additional_server) {
ray('this is an additional_servers, no pushy pushy');
return; return;
} }
ray('push_to_docker_registry noww: '.$this->production_image_name);
try { try {
instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server); instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server);
$this->application_deployment_queue->addLogEntry('----------------------------------------'); $this->application_deployment_queue->addLogEntry('----------------------------------------');
@@ -775,7 +760,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
if ($forceFail) { if ($forceFail) {
throw new RuntimeException($e->getMessage(), 69420); throw new RuntimeException($e->getMessage(), 69420);
} }
ray($e);
} }
} }
@@ -1386,8 +1370,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
return; return;
} }
if ($destination_ids->contains($this->destination->id)) { if ($destination_ids->contains($this->destination->id)) {
ray('Same destination found in additional destinations. Skipping.');
return; return;
} }
foreach ($destination_ids as $destination_id) { foreach ($destination_ids as $destination_id) {
@@ -2449,7 +2431,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
if ($this->application->build_pack !== 'dockercompose') { if ($this->application->build_pack !== 'dockercompose') {
$code = $exception->getCode(); $code = $exception->getCode();
ray($code);
if ($code !== 69420) { if ($code !== 69420) {
// 69420 means failed to push the image to the registry, so we don't need to remove the new version as it is the currently running one // 69420 means failed to push the image to the registry, so we don't need to remove the new version as it is the currently running one
if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) { if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) {

View File

@@ -31,8 +31,6 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
{ {
try { try {
if ($this->application->is_public_repository()) { if ($this->application->is_public_repository()) {
ray('Public repository. Skipping comment update.');
return; return;
} }
if ($this->status === ProcessStatus::CLOSED) { if ($this->status === ProcessStatus::CLOSED) {
@@ -53,16 +51,12 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
$this->body .= '[Open Build Logs]('.$this->build_logs_url.")\n\n\n"; $this->body .= '[Open Build Logs]('.$this->build_logs_url.")\n\n\n";
$this->body .= 'Last updated at: '.now()->toDateTimeString().' CET'; $this->body .= 'Last updated at: '.now()->toDateTimeString().' CET';
ray('Updating comment', $this->body);
if ($this->preview->pull_request_issue_comment_id) { if ($this->preview->pull_request_issue_comment_id) {
$this->update_comment(); $this->update_comment();
} else { } else {
$this->create_comment(); $this->create_comment();
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e);
return $e; return $e;
} }
} }
@@ -73,7 +67,6 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
'body' => $this->body, 'body' => $this->body,
], throwError: false); ], throwError: false);
if (data_get($data, 'message') === 'Not Found') { if (data_get($data, 'message') === 'Not Found') {
ray('Comment not found. Creating new one.');
$this->create_comment(); $this->create_comment();
} }
} }

View File

@@ -21,36 +21,32 @@ class CheckAndStartSentinelJob implements ShouldBeEncrypted, ShouldQueue
public function handle(): void public function handle(): void
{ {
try { $latestVersion = get_latest_sentinel_version();
$latestVersion = get_latest_sentinel_version();
// Check if sentinel is running // Check if sentinel is running
$sentinelFound = instant_remote_process(['docker inspect coolify-sentinel'], $this->server, false); $sentinelFound = instant_remote_process(['docker inspect coolify-sentinel'], $this->server, false);
$sentinelFoundJson = json_decode($sentinelFound, true); $sentinelFoundJson = json_decode($sentinelFound, true);
$sentinelStatus = data_get($sentinelFoundJson, '0.State.Status', 'exited'); $sentinelStatus = data_get($sentinelFoundJson, '0.State.Status', 'exited');
if ($sentinelStatus !== 'running') { if ($sentinelStatus !== 'running') {
StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion);
return;
}
// If sentinel is running, check if it needs an update
$runningVersion = instant_remote_process(['docker exec coolify-sentinel sh -c "curl http://127.0.0.1:8888/api/version"'], $this->server, false);
if (empty($runningVersion)) {
$runningVersion = '0.0.0';
}
if ($latestVersion === '0.0.0' && $runningVersion === '0.0.0') {
StartSentinel::run(server: $this->server, restart: true, latestVersion: 'latest');
return;
} else {
if (version_compare($runningVersion, $latestVersion, '<')) {
StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion); StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion);
return; return;
} }
// If sentinel is running, check if it needs an update
$runningVersion = instant_remote_process(['docker exec coolify-sentinel sh -c "curl http://127.0.0.1:8888/api/version"'], $this->server, false);
if (empty($runningVersion)) {
$runningVersion = '0.0.0';
}
if ($latestVersion === '0.0.0' && $runningVersion === '0.0.0') {
StartSentinel::run(server: $this->server, restart: true, latestVersion: 'latest');
return;
} else {
if (version_compare($runningVersion, $latestVersion, '<')) {
StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion);
return;
}
}
} catch (\Throwable $e) {
throw $e;
} }
} }
} }

View File

@@ -22,7 +22,6 @@ class CheckResaleLicenseJob implements ShouldBeEncrypted, ShouldQueue
CheckResaleLicense::run(); CheckResaleLicense::run();
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('CheckResaleLicenseJob failed with: '.$e->getMessage()); send_internal_notification('CheckResaleLicenseJob failed with: '.$e->getMessage());
ray($e);
throw $e; throw $e;
} }
} }

View File

@@ -20,18 +20,15 @@ class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, S
public function handle(): void public function handle(): void
{ {
try { try {
ray('Cleaning up helper containers on '.$this->server->name);
$containers = instant_remote_process(['docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image | contains("ghcr.io/coollabsio/coolify-helper")))\''], $this->server, false); $containers = instant_remote_process(['docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image | contains("ghcr.io/coollabsio/coolify-helper")))\''], $this->server, false);
$containerIds = collect(json_decode($containers))->pluck('ID'); $containerIds = collect(json_decode($containers))->pluck('ID');
if ($containerIds->count() > 0) { if ($containerIds->count() > 0) {
foreach ($containerIds as $containerId) { foreach ($containerIds as $containerId) {
ray('Removing container '.$containerId);
instant_remote_process(['docker container rm -f '.$containerId], $this->server, false); instant_remote_process(['docker container rm -f '.$containerId], $this->server, false);
} }
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('CleanupHelperContainersJob failed with error: '.$e->getMessage()); send_internal_notification('CleanupHelperContainersJob failed with error: '.$e->getMessage());
ray($e->getMessage());
} }
} }
} }

View File

@@ -29,13 +29,11 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho
// $this->cleanup_waitlist(); // $this->cleanup_waitlist();
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('CleanupInstanceStuffsJob failed with error: '.$e->getMessage()); send_internal_notification('CleanupInstanceStuffsJob failed with error: '.$e->getMessage());
ray($e->getMessage());
} }
try { try {
$this->cleanup_invitation_link(); $this->cleanup_invitation_link();
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('CleanupInstanceStuffsJob failed with error: '.$e->getMessage()); send_internal_notification('CleanupInstanceStuffsJob failed with error: '.$e->getMessage());
ray($e->getMessage());
} }
} }

View File

@@ -72,7 +72,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
return; return;
} }
if (data_get($this->backup, 'database_type') === 'App\Models\ServiceDatabase') { if (data_get($this->backup, 'database_type') === \App\Models\ServiceDatabase::class) {
$this->database = data_get($this->backup, 'database'); $this->database = data_get($this->backup, 'database');
$this->server = $this->database->service->server; $this->server = $this->database->service->server;
$this->s3 = $this->backup->s3; $this->s3 = $this->backup->s3;
@@ -92,11 +92,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$status = str(data_get($this->database, 'status')); $status = str(data_get($this->database, 'status'));
if (! $status->startsWith('running') && $this->database->id !== 0) { if (! $status->startsWith('running') && $this->database->id !== 0) {
ray('database not running');
return; return;
} }
if (data_get($this->backup, 'database_type') === 'App\Models\ServiceDatabase') { if (data_get($this->backup, 'database_type') === \App\Models\ServiceDatabase::class) {
$databaseType = $this->database->databaseType(); $databaseType = $this->database->databaseType();
$serviceUuid = $this->database->service->uuid; $serviceUuid = $this->database->service->uuid;
$serviceName = str($this->database->service->name)->slug(); $serviceName = str($this->database->service->name)->slug();
@@ -222,7 +220,6 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
// Format: db1:collection1,collection2|db2:collection3,collection4 // Format: db1:collection1,collection2|db2:collection3,collection4
$databasesToBackup = explode('|', $databasesToBackup); $databasesToBackup = explode('|', $databasesToBackup);
$databasesToBackup = array_map('trim', $databasesToBackup); $databasesToBackup = array_map('trim', $databasesToBackup);
ray($databasesToBackup);
} elseif (str($databaseType)->contains('mysql')) { } elseif (str($databaseType)->contains('mysql')) {
// Format: db1,db2,db3 // Format: db1,db2,db3
$databasesToBackup = explode(',', $databasesToBackup); $databasesToBackup = explode(',', $databasesToBackup);
@@ -244,7 +241,6 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
} }
foreach ($databasesToBackup as $database) { foreach ($databasesToBackup as $database) {
$size = 0; $size = 0;
ray('Backing up '.$database);
try { try {
if (str($databaseType)->contains('postgres')) { if (str($databaseType)->contains('postgres')) {
$this->backup_file = "/pg-dump-$database-".Carbon::now()->timestamp.'.dmp'; $this->backup_file = "/pg-dump-$database-".Carbon::now()->timestamp.'.dmp';
@@ -377,10 +373,8 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
if ($this->backup_output === '') { if ($this->backup_output === '') {
$this->backup_output = null; $this->backup_output = null;
} }
ray('Backup done for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->add_to_backup_output($e->getMessage()); $this->add_to_backup_output($e->getMessage());
ray('Backup failed for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location.'\n\nError:'.$e->getMessage());
throw $e; throw $e;
} }
} }
@@ -400,16 +394,13 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
} }
$commands[] = $backupCommand; $commands[] = $backupCommand;
ray($commands);
$this->backup_output = instant_remote_process($commands, $this->server); $this->backup_output = instant_remote_process($commands, $this->server);
$this->backup_output = trim($this->backup_output); $this->backup_output = trim($this->backup_output);
if ($this->backup_output === '') { if ($this->backup_output === '') {
$this->backup_output = null; $this->backup_output = null;
} }
ray('Backup done for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->add_to_backup_output($e->getMessage()); $this->add_to_backup_output($e->getMessage());
ray('Backup failed for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location.'\n\nError:'.$e->getMessage());
throw $e; throw $e;
} }
} }
@@ -428,10 +419,8 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
if ($this->backup_output === '') { if ($this->backup_output === '') {
$this->backup_output = null; $this->backup_output = null;
} }
ray('Backup done for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->add_to_backup_output($e->getMessage()); $this->add_to_backup_output($e->getMessage());
ray('Backup failed for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location.'\n\nError:'.$e->getMessage());
throw $e; throw $e;
} }
} }
@@ -445,16 +434,13 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
} else { } else {
$commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} $database > $this->backup_location"; $commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} $database > $this->backup_location";
} }
ray($commands);
$this->backup_output = instant_remote_process($commands, $this->server); $this->backup_output = instant_remote_process($commands, $this->server);
$this->backup_output = trim($this->backup_output); $this->backup_output = trim($this->backup_output);
if ($this->backup_output === '') { if ($this->backup_output === '') {
$this->backup_output = null; $this->backup_output = null;
} }
ray('Backup done for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->add_to_backup_output($e->getMessage()); $this->add_to_backup_output($e->getMessage());
ray('Backup failed for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location.'\n\nError:'.$e->getMessage());
throw $e; throw $e;
} }
} }
@@ -498,7 +484,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$bucket = $this->s3->bucket; $bucket = $this->s3->bucket;
$endpoint = $this->s3->endpoint; $endpoint = $this->s3->endpoint;
$this->s3->testConnection(shouldSave: true); $this->s3->testConnection(shouldSave: true);
if (data_get($this->backup, 'database_type') === 'App\Models\ServiceDatabase') { if (data_get($this->backup, 'database_type') === \App\Models\ServiceDatabase::class) {
$network = $this->database->service->destination->network; $network = $this->database->service->destination->network;
} else { } else {
$network = $this->database->destination->network; $network = $this->database->destination->network;

View File

@@ -42,7 +42,6 @@ class GithubAppPermissionJob implements ShouldBeEncrypted, ShouldQueue
$this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret'); $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('GithubAppPermissionJob failed with: '.$e->getMessage()); send_internal_notification('GithubAppPermissionJob failed with: '.$e->getMessage());
ray($e->getMessage());
throw $e; throw $e;
} }
} }

View File

@@ -20,12 +20,8 @@ class PullHelperImageJob implements ShouldBeEncrypted, ShouldQueue
public function handle(): void public function handle(): void
{ {
try { $helperImage = config('coolify.helper_image');
$helperImage = config('coolify.helper_image'); $latest_version = instanceSettings()->helper_version;
$latest_version = instanceSettings()->helper_version; instant_remote_process(["docker pull -q {$helperImage}:{$latest_version}"], $this->server, false);
instant_remote_process(["docker pull -q {$helperImage}:{$latest_version}"], $this->server, false);
} catch (\Throwable $e) {
throw $e;
}
} }
} }

View File

@@ -25,7 +25,6 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue
if (isDev() || isCloud()) { if (isDev() || isCloud()) {
return; return;
} }
ray('PullTemplatesAndVersions service-templates');
$response = Http::retry(3, 1000)->get(config('constants.services.official')); $response = Http::retry(3, 1000)->get(config('constants.services.official'));
if ($response->successful()) { if ($response->successful()) {
$services = $response->json(); $services = $response->json();
@@ -35,7 +34,6 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('PullTemplatesAndVersions failed with: '.$e->getMessage()); send_internal_notification('PullTemplatesAndVersions failed with: '.$e->getMessage());
ray($e->getMessage());
} }
} }
} }

View File

@@ -1,39 +0,0 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
class PullVersionsFromCDN implements ShouldBeEncrypted, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $timeout = 10;
public function __construct() {}
public function handle(): void
{
try {
if (! isDev() && ! isCloud()) {
ray('PullTemplatesAndVersions versions.json');
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
if ($response->successful()) {
$versions = $response->json();
File::put(base_path('versions.json'), json_encode($versions, JSON_PRETTY_PRINT));
} else {
send_internal_notification('PullTemplatesAndVersions failed with: '.$response->status().' '.$response->body());
}
}
} catch (\Throwable $e) {
throw $e;
}
}
}

View File

@@ -6,7 +6,7 @@ use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy; use App\Actions\Database\StopDatabaseProxy;
use App\Actions\Proxy\CheckProxy; use App\Actions\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy; use App\Actions\Proxy\StartProxy;
use App\Actions\Server\InstallLogDrain; use App\Actions\Server\StartLogDrain;
use App\Actions\Shared\ComplexStatusCheck; use App\Actions\Shared\ComplexStatusCheck;
use App\Models\Application; use App\Models\Application;
use App\Models\ApplicationPreview; use App\Models\ApplicationPreview;
@@ -91,123 +91,113 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
public function handle() public function handle()
{ {
// TODO: Swarm is not supported yet // TODO: Swarm is not supported yet
try { if (! $this->data) {
if (! $this->data) { throw new \Exception('No data provided');
throw new \Exception('No data provided'); }
} $data = collect($this->data);
$data = collect($this->data);
$this->server->sentinelHeartbeat(); $this->server->sentinelHeartbeat();
$this->containers = collect(data_get($data, 'containers')); $this->containers = collect(data_get($data, 'containers'));
$filesystemUsageRoot = data_get($data, 'filesystem_usage_root.used_percentage'); $filesystemUsageRoot = data_get($data, 'filesystem_usage_root.used_percentage');
ServerStorageCheckJob::dispatch($this->server, $filesystemUsageRoot); ServerStorageCheckJob::dispatch($this->server, $filesystemUsageRoot);
if ($this->containers->isEmpty()) { if ($this->containers->isEmpty()) {
return; return;
} }
$this->applications = $this->server->applications(); $this->applications = $this->server->applications();
$this->databases = $this->server->databases(); $this->databases = $this->server->databases();
$this->previews = $this->server->previews(); $this->previews = $this->server->previews();
$this->services = $this->server->services()->get(); $this->services = $this->server->services()->get();
$this->allApplicationIds = $this->applications->filter(function ($application) { $this->allApplicationIds = $this->applications->filter(function ($application) {
return $application->additional_servers->count() === 0; return $application->additional_servers->count() === 0;
})->pluck('id'); })->pluck('id');
$this->allApplicationsWithAdditionalServers = $this->applications->filter(function ($application) { $this->allApplicationsWithAdditionalServers = $this->applications->filter(function ($application) {
return $application->additional_servers->count() > 0; return $application->additional_servers->count() > 0;
});
$this->allApplicationPreviewsIds = $this->previews->pluck('id');
$this->allDatabaseUuids = $this->databases->pluck('uuid');
$this->allTcpProxyUuids = $this->databases->where('is_public', true)->pluck('uuid');
$this->services->each(function ($service) {
$service->applications()->pluck('id')->each(function ($applicationId) {
$this->allServiceApplicationIds->push($applicationId);
}); });
$this->allApplicationPreviewsIds = $this->previews->pluck('id'); $service->databases()->pluck('id')->each(function ($databaseId) {
$this->allDatabaseUuids = $this->databases->pluck('uuid'); $this->allServiceDatabaseIds->push($databaseId);
$this->allTcpProxyUuids = $this->databases->where('is_public', true)->pluck('uuid');
$this->services->each(function ($service) {
$service->applications()->pluck('id')->each(function ($applicationId) {
$this->allServiceApplicationIds->push($applicationId);
});
$service->databases()->pluck('id')->each(function ($databaseId) {
$this->allServiceDatabaseIds->push($databaseId);
});
}); });
});
ray('allServiceApplicationIds', ['allServiceApplicationIds' => $this->allServiceApplicationIds]); foreach ($this->containers as $container) {
$containerStatus = data_get($container, 'state', 'exited');
foreach ($this->containers as $container) { $containerHealth = data_get($container, 'health_status', 'unhealthy');
$containerStatus = data_get($container, 'state', 'exited'); $containerStatus = "$containerStatus ($containerHealth)";
$containerHealth = data_get($container, 'health_status', 'unhealthy'); $labels = collect(data_get($container, 'labels'));
$containerStatus = "$containerStatus ($containerHealth)"; $coolify_managed = $labels->has('coolify.managed');
$labels = collect(data_get($container, 'labels')); if ($coolify_managed) {
$coolify_managed = $labels->has('coolify.managed'); $name = data_get($container, 'name');
if ($coolify_managed) { if ($name === 'coolify-log-drain' && $this->isRunning($containerStatus)) {
$name = data_get($container, 'name'); $this->foundLogDrainContainer = true;
if ($name === 'coolify-log-drain' && $this->isRunning($containerStatus)) { }
$this->foundLogDrainContainer = true; if ($labels->has('coolify.applicationId')) {
} $applicationId = $labels->get('coolify.applicationId');
if ($labels->has('coolify.applicationId')) { $pullRequestId = data_get($labels, 'coolify.pullRequestId', '0');
$applicationId = $labels->get('coolify.applicationId'); try {
$pullRequestId = data_get($labels, 'coolify.pullRequestId', '0'); if ($pullRequestId === '0') {
try { if ($this->allApplicationIds->contains($applicationId) && $this->isRunning($containerStatus)) {
if ($pullRequestId === '0') { $this->foundApplicationIds->push($applicationId);
if ($this->allApplicationIds->contains($applicationId) && $this->isRunning($containerStatus)) {
$this->foundApplicationIds->push($applicationId);
}
$this->updateApplicationStatus($applicationId, $containerStatus);
} else {
if ($this->allApplicationPreviewsIds->contains($applicationId) && $this->isRunning($containerStatus)) {
$this->foundApplicationPreviewsIds->push($applicationId);
}
$this->updateApplicationPreviewStatus($applicationId, $containerStatus);
} }
} catch (\Exception $e) { $this->updateApplicationStatus($applicationId, $containerStatus);
ray()->error($e);
}
} elseif ($labels->has('coolify.serviceId')) {
$serviceId = $labels->get('coolify.serviceId');
$subType = $labels->get('coolify.service.subType');
$subId = $labels->get('coolify.service.subId');
if ($subType === 'application' && $this->isRunning($containerStatus)) {
$this->foundServiceApplicationIds->push($subId);
$this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus);
} elseif ($subType === 'database' && $this->isRunning($containerStatus)) {
$this->foundServiceDatabaseIds->push($subId);
$this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus);
}
} else {
$uuid = $labels->get('com.docker.compose.service');
$type = $labels->get('coolify.type');
if ($name === 'coolify-proxy' && $this->isRunning($containerStatus)) {
$this->foundProxy = true;
} elseif ($type === 'service' && $this->isRunning($containerStatus)) {
ray("Service: $uuid, $containerStatus");
} else { } else {
if ($this->allDatabaseUuids->contains($uuid) && $this->isRunning($containerStatus)) { if ($this->allApplicationPreviewsIds->contains($applicationId) && $this->isRunning($containerStatus)) {
$this->foundDatabaseUuids->push($uuid); $this->foundApplicationPreviewsIds->push($applicationId);
if ($this->allTcpProxyUuids->contains($uuid) && $this->isRunning($containerStatus)) { }
$this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: true); $this->updateApplicationPreviewStatus($applicationId, $containerStatus);
} else { }
$this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: false); } catch (\Exception $e) {
} }
} elseif ($labels->has('coolify.serviceId')) {
$serviceId = $labels->get('coolify.serviceId');
$subType = $labels->get('coolify.service.subType');
$subId = $labels->get('coolify.service.subId');
if ($subType === 'application' && $this->isRunning($containerStatus)) {
$this->foundServiceApplicationIds->push($subId);
$this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus);
} elseif ($subType === 'database' && $this->isRunning($containerStatus)) {
$this->foundServiceDatabaseIds->push($subId);
$this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus);
}
} else {
$uuid = $labels->get('com.docker.compose.service');
$type = $labels->get('coolify.type');
if ($name === 'coolify-proxy' && $this->isRunning($containerStatus)) {
$this->foundProxy = true;
} elseif ($type === 'service' && $this->isRunning($containerStatus)) {
} else {
if ($this->allDatabaseUuids->contains($uuid) && $this->isRunning($containerStatus)) {
$this->foundDatabaseUuids->push($uuid);
if ($this->allTcpProxyUuids->contains($uuid) && $this->isRunning($containerStatus)) {
$this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: true);
} else {
$this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: false);
} }
} }
} }
} }
} }
$this->updateProxyStatus();
$this->updateNotFoundApplicationStatus();
$this->updateNotFoundApplicationPreviewStatus();
$this->updateNotFoundDatabaseStatus();
$this->updateNotFoundServiceStatus();
$this->updateAdditionalServersStatus();
$this->checkLogDrainContainer();
} catch (\Exception $e) {
throw $e;
} }
$this->updateProxyStatus();
$this->updateNotFoundApplicationStatus();
$this->updateNotFoundApplicationPreviewStatus();
$this->updateNotFoundDatabaseStatus();
$this->updateNotFoundServiceStatus();
$this->updateAdditionalServersStatus();
$this->checkLogDrainContainer();
} }
private function updateApplicationStatus(string $applicationId, string $containerStatus) private function updateApplicationStatus(string $applicationId, string $containerStatus)
@@ -218,7 +208,6 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
} }
$application->status = $containerStatus; $application->status = $containerStatus;
$application->save(); $application->save();
ray('Application updated', ['application_id' => $applicationId, 'status' => $containerStatus]);
} }
private function updateApplicationPreviewStatus(string $applicationId, string $containerStatus) private function updateApplicationPreviewStatus(string $applicationId, string $containerStatus)
@@ -229,21 +218,17 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
} }
$application->status = $containerStatus; $application->status = $containerStatus;
$application->save(); $application->save();
ray('Application preview updated', ['application_id' => $applicationId, 'status' => $containerStatus]);
} }
private function updateNotFoundApplicationStatus() private function updateNotFoundApplicationStatus()
{ {
$notFoundApplicationIds = $this->allApplicationIds->diff($this->foundApplicationIds); $notFoundApplicationIds = $this->allApplicationIds->diff($this->foundApplicationIds);
if ($notFoundApplicationIds->isNotEmpty()) { if ($notFoundApplicationIds->isNotEmpty()) {
ray('Not found application ids', ['application_ids' => $notFoundApplicationIds]);
$notFoundApplicationIds->each(function ($applicationId) { $notFoundApplicationIds->each(function ($applicationId) {
ray('Updating application status', ['application_id' => $applicationId, 'status' => 'exited']);
$application = Application::find($applicationId); $application = Application::find($applicationId);
if ($application) { if ($application) {
$application->status = 'exited'; $application->status = 'exited';
$application->save(); $application->save();
ray('Application status updated', ['application_id' => $applicationId, 'status' => 'exited']);
} }
}); });
} }
@@ -253,14 +238,11 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
{ {
$notFoundApplicationPreviewsIds = $this->allApplicationPreviewsIds->diff($this->foundApplicationPreviewsIds); $notFoundApplicationPreviewsIds = $this->allApplicationPreviewsIds->diff($this->foundApplicationPreviewsIds);
if ($notFoundApplicationPreviewsIds->isNotEmpty()) { if ($notFoundApplicationPreviewsIds->isNotEmpty()) {
ray('Not found application previews ids', ['application_previews_ids' => $notFoundApplicationPreviewsIds]);
$notFoundApplicationPreviewsIds->each(function ($applicationPreviewId) { $notFoundApplicationPreviewsIds->each(function ($applicationPreviewId) {
ray('Updating application preview status', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']);
$applicationPreview = ApplicationPreview::find($applicationPreviewId); $applicationPreview = ApplicationPreview::find($applicationPreviewId);
if ($applicationPreview) { if ($applicationPreview) {
$applicationPreview->status = 'exited'; $applicationPreview->status = 'exited';
$applicationPreview->save(); $applicationPreview->save();
ray('Application preview status updated', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']);
} }
}); });
} }
@@ -294,17 +276,14 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
} }
$database->status = $containerStatus; $database->status = $containerStatus;
$database->save(); $database->save();
ray('Database status updated', ['database_uuid' => $databaseUuid, 'status' => $containerStatus]);
if ($this->isRunning($containerStatus) && $tcpProxy) { if ($this->isRunning($containerStatus) && $tcpProxy) {
$tcpProxyContainerFound = $this->containers->filter(function ($value, $key) use ($databaseUuid) { $tcpProxyContainerFound = $this->containers->filter(function ($value, $key) use ($databaseUuid) {
return data_get($value, 'name') === "$databaseUuid-proxy" && data_get($value, 'state') === 'running'; return data_get($value, 'name') === "$databaseUuid-proxy" && data_get($value, 'state') === 'running';
})->first(); })->first();
if (! $tcpProxyContainerFound) { if (! $tcpProxyContainerFound) {
ray('Starting TCP proxy for database', ['database_uuid' => $databaseUuid]);
StartDatabaseProxy::dispatch($database); StartDatabaseProxy::dispatch($database);
$this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
} else { } else {
ray('TCP proxy for database found in containers', ['database_uuid' => $databaseUuid]);
} }
} }
} }
@@ -313,17 +292,12 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
{ {
$notFoundDatabaseUuids = $this->allDatabaseUuids->diff($this->foundDatabaseUuids); $notFoundDatabaseUuids = $this->allDatabaseUuids->diff($this->foundDatabaseUuids);
if ($notFoundDatabaseUuids->isNotEmpty()) { if ($notFoundDatabaseUuids->isNotEmpty()) {
ray('Not found database uuids', ['database_uuids' => $notFoundDatabaseUuids]);
$notFoundDatabaseUuids->each(function ($databaseUuid) { $notFoundDatabaseUuids->each(function ($databaseUuid) {
ray('Updating database status', ['database_uuid' => $databaseUuid, 'status' => 'exited']);
$database = $this->databases->where('uuid', $databaseUuid)->first(); $database = $this->databases->where('uuid', $databaseUuid)->first();
if ($database) { if ($database) {
$database->status = 'exited'; $database->status = 'exited';
$database->save(); $database->save();
ray('Database status updated', ['database_uuid' => $databaseUuid, 'status' => 'exited']);
ray('Database is public', ['database_uuid' => $databaseUuid, 'is_public' => $database->is_public]);
if ($database->is_public) { if ($database->is_public) {
ray('Stopping TCP proxy for database', ['database_uuid' => $databaseUuid]);
StopDatabaseProxy::dispatch($database); StopDatabaseProxy::dispatch($database);
} }
} }
@@ -341,14 +315,11 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
$application = $service->applications()->where('id', $subId)->first(); $application = $service->applications()->where('id', $subId)->first();
$application->status = $containerStatus; $application->status = $containerStatus;
$application->save(); $application->save();
ray('Service application updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]);
} elseif ($subType === 'database') { } elseif ($subType === 'database') {
$database = $service->databases()->where('id', $subId)->first(); $database = $service->databases()->where('id', $subId)->first();
$database->status = $containerStatus; $database->status = $containerStatus;
$database->save(); $database->save();
ray('Service database updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]);
} else { } else {
ray()->warning('Unknown sub type', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]);
} }
} }
@@ -357,26 +328,20 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
$notFoundServiceApplicationIds = $this->allServiceApplicationIds->diff($this->foundServiceApplicationIds); $notFoundServiceApplicationIds = $this->allServiceApplicationIds->diff($this->foundServiceApplicationIds);
$notFoundServiceDatabaseIds = $this->allServiceDatabaseIds->diff($this->foundServiceDatabaseIds); $notFoundServiceDatabaseIds = $this->allServiceDatabaseIds->diff($this->foundServiceDatabaseIds);
if ($notFoundServiceApplicationIds->isNotEmpty()) { if ($notFoundServiceApplicationIds->isNotEmpty()) {
ray('Not found service application ids', ['service_application_ids' => $notFoundServiceApplicationIds]);
$notFoundServiceApplicationIds->each(function ($serviceApplicationId) { $notFoundServiceApplicationIds->each(function ($serviceApplicationId) {
ray('Updating service application status', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']);
$application = ServiceApplication::find($serviceApplicationId); $application = ServiceApplication::find($serviceApplicationId);
if ($application) { if ($application) {
$application->status = 'exited'; $application->status = 'exited';
$application->save(); $application->save();
ray('Service application status updated', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']);
} }
}); });
} }
if ($notFoundServiceDatabaseIds->isNotEmpty()) { if ($notFoundServiceDatabaseIds->isNotEmpty()) {
ray('Not found service database ids', ['service_database_ids' => $notFoundServiceDatabaseIds]);
$notFoundServiceDatabaseIds->each(function ($serviceDatabaseId) { $notFoundServiceDatabaseIds->each(function ($serviceDatabaseId) {
ray('Updating service database status', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']);
$database = ServiceDatabase::find($serviceDatabaseId); $database = ServiceDatabase::find($serviceDatabaseId);
if ($database) { if ($database) {
$database->status = 'exited'; $database->status = 'exited';
$database->save(); $database->save();
ray('Service database status updated', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']);
} }
}); });
} }
@@ -385,7 +350,6 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
private function updateAdditionalServersStatus() private function updateAdditionalServersStatus()
{ {
$this->allApplicationsWithAdditionalServers->each(function ($application) { $this->allApplicationsWithAdditionalServers->each(function ($application) {
ray('Updating additional servers status for application', ['application_id' => $application->id]);
ComplexStatusCheck::run($application); ComplexStatusCheck::run($application);
}); });
} }
@@ -398,7 +362,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
private function checkLogDrainContainer() private function checkLogDrainContainer()
{ {
if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) { if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) {
InstallLogDrain::dispatch($this->server); StartLogDrain::dispatch($this->server);
} }
} }
} }

View File

@@ -31,7 +31,6 @@ class SendConfirmationForWaitlistJob implements ShouldBeEncrypted, ShouldQueue
send_user_an_email($mail, $this->email); send_user_an_email($mail, $this->email);
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification("SendConfirmationForWaitlistJob failed for {$this->email} with error: ".$e->getMessage()); send_internal_notification("SendConfirmationForWaitlistJob failed for {$this->email} with error: ".$e->getMessage());
ray($e->getMessage());
throw $e; throw $e;
} }
} }

View File

@@ -5,7 +5,7 @@ namespace App\Jobs;
use App\Actions\Docker\GetContainersStatus; use App\Actions\Docker\GetContainersStatus;
use App\Actions\Proxy\CheckProxy; use App\Actions\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy; use App\Actions\Proxy\StartProxy;
use App\Actions\Server\InstallLogDrain; use App\Actions\Server\StartLogDrain;
use App\Models\Server; use App\Models\Server;
use App\Notifications\Container\ContainerRestarted; use App\Notifications\Container\ContainerRestarted;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
@@ -85,7 +85,6 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
$this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server)); $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e);
} }
} else { } else {
$this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status');
@@ -97,8 +96,6 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e->getMessage());
return handleError($e); return handleError($e);
} }
@@ -112,10 +109,10 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
if ($foundLogDrainContainer) { if ($foundLogDrainContainer) {
$status = data_get($foundLogDrainContainer, 'State.Status'); $status = data_get($foundLogDrainContainer, 'State.Status');
if ($status !== 'running') { if ($status !== 'running') {
InstallLogDrain::dispatch($this->server); StartLogDrain::dispatch($this->server);
} }
} else { } else {
InstallLogDrain::dispatch($this->server); StartLogDrain::dispatch($this->server);
} }
} }
} }

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Jobs;
use App\Helpers\SshMultiplexingHelper;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ServerCleanupMux implements ShouldBeEncrypted, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
public $timeout = 60;
public function backoff(): int
{
return isDev() ? 1 : 3;
}
public function __construct(public Server $server) {}
public function handle()
{
try {
if ($this->server->serverStatus() === false) {
return 'Server is not reachable or not ready.';
}
SshMultiplexingHelper::removeMuxFile($this->server);
} catch (\Throwable $e) {
return handleError($e);
}
}
}

View File

@@ -32,9 +32,7 @@ class ServerLimitCheckJob implements ShouldBeEncrypted, ShouldQueue
$servers_count = $servers->count(); $servers_count = $servers->count();
$limit = data_get($this->team->limits, 'serverLimit', 2); $limit = data_get($this->team->limits, 'serverLimit', 2);
$number_of_servers_to_disable = $servers_count - $limit; $number_of_servers_to_disable = $servers_count - $limit;
ray('ServerLimitCheckJob', $this->team->uuid, $servers_count, $limit, $number_of_servers_to_disable);
if ($number_of_servers_to_disable > 0) { if ($number_of_servers_to_disable > 0) {
ray('Disabling servers');
$servers = $servers->sortbyDesc('created_at'); $servers = $servers->sortbyDesc('created_at');
$servers_to_disable = $servers->take($number_of_servers_to_disable); $servers_to_disable = $servers->take($number_of_servers_to_disable);
$servers_to_disable->each(function ($server) { $servers_to_disable->each(function ($server) {
@@ -51,7 +49,6 @@ class ServerLimitCheckJob implements ShouldBeEncrypted, ShouldQueue
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('ServerLimitCheckJob failed with: '.$e->getMessage()); send_internal_notification('ServerLimitCheckJob failed with: '.$e->getMessage());
ray($e->getMessage());
return handleError($e); return handleError($e);
} }

View File

@@ -38,7 +38,6 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue
if (is_null($this->percentage)) { if (is_null($this->percentage)) {
$this->percentage = $this->server->storageCheck(); $this->percentage = $this->server->storageCheck();
loggy('Server storage check percentage: '.$this->percentage);
} }
if (! $this->percentage) { if (! $this->percentage) {
return 'No percentage could be retrieved.'; return 'No percentage could be retrieved.';

View File

@@ -27,14 +27,12 @@ class SubscriptionInvoiceFailedJob implements ShouldBeEncrypted, ShouldQueue
]); ]);
$mail->subject('Your last payment was failed for Coolify Cloud.'); $mail->subject('Your last payment was failed for Coolify Cloud.');
$this->team->members()->each(function ($member) use ($mail) { $this->team->members()->each(function ($member) use ($mail) {
ray($member);
if ($member->isAdmin()) { if ($member->isAdmin()) {
send_user_an_email($mail, $member->email); send_user_an_email($mail, $member->email);
} }
}); });
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('SubscriptionInvoiceFailedJob failed with: '.$e->getMessage()); send_internal_notification('SubscriptionInvoiceFailedJob failed with: '.$e->getMessage());
ray($e->getMessage());
throw $e; throw $e;
} }
} }

View File

@@ -30,14 +30,12 @@ class SubscriptionTrialEndedJob implements ShouldBeEncrypted, ShouldQueue
]); ]);
$this->team->members()->each(function ($member) use ($mail) { $this->team->members()->each(function ($member) use ($mail) {
if ($member->isAdmin()) { if ($member->isAdmin()) {
ray('Sending trial ended email to '.$member->email);
send_user_an_email($mail, $member->email); send_user_an_email($mail, $member->email);
send_internal_notification('Trial reminder email sent to '.$member->email); send_internal_notification('Trial reminder email sent to '.$member->email);
} }
}); });
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('SubscriptionTrialEndsSoonJob failed with: '.$e->getMessage()); send_internal_notification('SubscriptionTrialEndsSoonJob failed with: '.$e->getMessage());
ray($e->getMessage());
throw $e; throw $e;
} }
} }

View File

@@ -30,14 +30,12 @@ class SubscriptionTrialEndsSoonJob implements ShouldBeEncrypted, ShouldQueue
]); ]);
$this->team->members()->each(function ($member) use ($mail) { $this->team->members()->each(function ($member) use ($mail) {
if ($member->isAdmin()) { if ($member->isAdmin()) {
ray('Sending trial ending email to '.$member->email);
send_user_an_email($mail, $member->email); send_user_an_email($mail, $member->email);
send_internal_notification('Trial reminder email sent to '.$member->email); send_internal_notification('Trial reminder email sent to '.$member->email);
} }
}); });
} catch (\Throwable $e) { } catch (\Throwable $e) {
send_internal_notification('SubscriptionTrialEndsSoonJob failed with: '.$e->getMessage()); send_internal_notification('SubscriptionTrialEndsSoonJob failed with: '.$e->getMessage());
ray($e->getMessage());
throw $e; throw $e;
} }
} }

View File

@@ -13,7 +13,6 @@ class MaintenanceModeDisabledNotification
public function handle(EventsMaintenanceModeDisabled $event): void public function handle(EventsMaintenanceModeDisabled $event): void
{ {
ray('Maintenance mode disabled!');
$files = Storage::disk('webhooks-during-maintenance')->files(); $files = Storage::disk('webhooks-during-maintenance')->files();
$files = collect($files); $files = collect($files);
$files = $files->sort(); $files = $files->sort();
@@ -41,7 +40,6 @@ class MaintenanceModeDisabledNotification
$instance = new $class; $instance = new $class;
$instance->$method($request); $instance->$method($request);
} catch (\Throwable $th) { } catch (\Throwable $th) {
ray($th);
} finally { } finally {
Storage::disk('webhooks-during-maintenance')->delete($file); Storage::disk('webhooks-during-maintenance')->delete($file);
} }

View File

@@ -17,8 +17,5 @@ class MaintenanceModeEnabledNotification
/** /**
* Handle the event. * Handle the event.
*/ */
public function handle(EventsMaintenanceModeEnabled $event): void public function handle(EventsMaintenanceModeEnabled $event): void {}
{
ray('Maintenance mode enabled!');
}
} }

View File

@@ -73,8 +73,6 @@ class Index extends Component
} }
$this->privateKeyName = generate_random_name(); $this->privateKeyName = generate_random_name();
$this->remoteServerName = generate_random_name(); $this->remoteServerName = generate_random_name();
$this->remoteServerPort = $this->remoteServerPort;
$this->remoteServerUser = $this->remoteServerUser;
if (isDev()) { if (isDev()) {
$this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY----- $this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
@@ -87,26 +85,6 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
$this->remoteServerDescription = 'Created by Coolify'; $this->remoteServerDescription = 'Created by Coolify';
$this->remoteServerHost = 'coolify-testing-host'; $this->remoteServerHost = 'coolify-testing-host';
} }
// if ($this->currentState === 'create-project') {
// $this->getProjects();
// }
// if ($this->currentState === 'create-resource') {
// $this->selectExistingServer();
// $this->selectExistingProject();
// }
// if ($this->currentState === 'private-key') {
// $this->setServerType('remote');
// }
// if ($this->currentState === 'create-server') {
// $this->selectExistingPrivateKey();
// }
// if ($this->currentState === 'validate-server') {
// $this->selectExistingServer();
// }
// if ($this->currentState === 'select-existing-server') {
// $this->selectExistingServer();
// }
} }
public function explanation() public function explanation()

View File

@@ -29,7 +29,7 @@ class Form extends Component
public function delete() public function delete()
{ {
try { try {
if ($this->destination->getMorphClass() === 'App\Models\StandaloneDocker') { if ($this->destination->getMorphClass() === \App\Models\StandaloneDocker::class) {
if ($this->destination->attachedTo()) { if ($this->destination->attachedTo()) {
return $this->dispatch('error', 'You must delete all resources before deleting this destination.'); return $this->dispatch('error', 'You must delete all resources before deleting this destination.');
} }

View File

@@ -4,6 +4,7 @@ namespace App\Livewire;
use DanHarrin\LivewireRateLimiting\WithRateLimiting; use DanHarrin\LivewireRateLimiting\WithRateLimiting;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
use Livewire\Component; use Livewire\Component;
class ForcePasswordReset extends Component class ForcePasswordReset extends Component
@@ -16,14 +17,19 @@ class ForcePasswordReset extends Component
public string $password_confirmation; public string $password_confirmation;
protected $rules = [ public function rules(): array
'email' => 'required|email', {
'password' => 'required|min:8', return [
'password_confirmation' => 'required|same:password', 'email' => ['required', 'email'],
]; 'password' => ['required', Password::defaults(), 'confirmed'],
];
}
public function mount() public function mount()
{ {
if (auth()->user()->force_password_reset === false) {
return redirect()->route('dashboard');
}
$this->email = auth()->user()->email; $this->email = auth()->user()->email;
} }
@@ -34,6 +40,10 @@ class ForcePasswordReset extends Component
public function submit() public function submit()
{ {
if (auth()->user()->force_password_reset === false) {
return redirect()->route('dashboard');
}
try { try {
$this->rateLimit(10); $this->rateLimit(10);
$this->validate(); $this->validate();

View File

@@ -68,7 +68,6 @@ class NewActivityMonitor extends Component
} else { } else {
$this->dispatch($this->eventToDispatch); $this->dispatch($this->eventToDispatch);
} }
ray('Dispatched event: '.$this->eventToDispatch.' with data: '.$this->eventData);
} }
} }
} }

View File

@@ -35,7 +35,6 @@ class Discord extends Component
try { try {
$this->submit(); $this->submit();
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e->getMessage());
$this->team->discord_enabled = false; $this->team->discord_enabled = false;
$this->validate(); $this->validate();
} }

View File

@@ -42,7 +42,6 @@ class Telegram extends Component
try { try {
$this->submit(); $this->submit();
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e->getMessage());
$this->team->telegram_enabled = false; $this->team->telegram_enabled = false;
$this->validate(); $this->validate();
} }

View File

@@ -3,6 +3,7 @@
namespace App\Livewire\Profile; namespace App\Livewire\Profile;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
use Livewire\Attributes\Validate; use Livewire\Attributes\Validate;
use Livewire\Component; use Livewire\Component;
@@ -48,9 +49,8 @@ class Index extends Component
{ {
try { try {
$this->validate([ $this->validate([
'current_password' => 'required', 'current_password' => ['required'],
'new_password' => 'required|min:8', 'new_password' => ['required', Password::defaults(), 'confirmed'],
'new_password_confirmation' => 'required|min:8|same:new_password',
]); ]);
if (! Hash::check($this->current_password, auth()->user()->password)) { if (! Hash::check($this->current_password, auth()->user()->password)) {
$this->dispatch('error', 'Current password is incorrect.'); $this->dispatch('error', 'Current password is incorrect.');

View File

@@ -46,8 +46,6 @@ class DeploymentNavbar extends Component
try { try {
force_start_deployment($this->application_deployment_queue); force_start_deployment($this->application_deployment_queue);
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e);
return handleError($e, $this); return handleError($e, $this);
} }
} }
@@ -81,8 +79,6 @@ class DeploymentNavbar extends Component
} }
instant_remote_process([$kill_command], $server); instant_remote_process([$kill_command], $server);
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e);
return handleError($e, $this); return handleError($e, $this);
} finally { } finally {
$this->application_deployment_queue->update([ $this->application_deployment_queue->update([

View File

@@ -24,10 +24,10 @@ class Index extends Component
} }
// No backups // No backups
if ( if (
$database->getMorphClass() === 'App\Models\StandaloneRedis' || $database->getMorphClass() === \App\Models\StandaloneRedis::class ||
$database->getMorphClass() === 'App\Models\StandaloneKeydb' || $database->getMorphClass() === \App\Models\StandaloneKeydb::class ||
$database->getMorphClass() === 'App\Models\StandaloneDragonfly' || $database->getMorphClass() === \App\Models\StandaloneDragonfly::class ||
$database->getMorphClass() === 'App\Models\StandaloneClickhouse' $database->getMorphClass() === \App\Models\StandaloneClickhouse::class
) { ) {
return redirect()->route('project.database.configuration', [ return redirect()->route('project.database.configuration', [
'project_uuid' => $project->uuid, 'project_uuid' => $project->uuid,

View File

@@ -77,7 +77,7 @@ class BackupEdit extends Component
$this->backup->delete(); $this->backup->delete();
if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') { if ($this->backup->database->getMorphClass() === \App\Models\ServiceDatabase::class) {
$previousUrl = url()->previous(); $previousUrl = url()->previous();
$url = Url::fromString($previousUrl); $url = Url::fromString($previousUrl);
$url = $url->withoutQueryParameter('selectedBackupId'); $url = $url->withoutQueryParameter('selectedBackupId');
@@ -138,7 +138,7 @@ class BackupEdit extends Component
$backupFolder = null; $backupFolder = null;
foreach ($executions as $execution) { foreach ($executions as $execution) {
if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') { if ($this->backup->database->getMorphClass() === \App\Models\ServiceDatabase::class) {
$server = $this->backup->database->service->destination->server; $server = $this->backup->database->service->destination->server;
} else { } else {
$server = $this->backup->database->destination->server; $server = $this->backup->database->destination->server;

View File

@@ -57,7 +57,7 @@ class BackupExecutions extends Component
return; return;
} }
if ($execution->scheduledDatabaseBackup->database->getMorphClass() === 'App\Models\ServiceDatabase') { if ($execution->scheduledDatabaseBackup->database->getMorphClass() === \App\Models\ServiceDatabase::class) {
delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->service->destination->server); delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->service->destination->server);
} else { } else {
delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->destination->server); delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->destination->server);

View File

@@ -66,7 +66,7 @@ class CreateScheduledBackup extends Component
} }
$databaseBackup = ScheduledDatabaseBackup::create($payload); $databaseBackup = ScheduledDatabaseBackup::create($payload);
if ($this->database->getMorphClass() === 'App\Models\ServiceDatabase') { if ($this->database->getMorphClass() === \App\Models\ServiceDatabase::class) {
$this->dispatch('refreshScheduledBackups', $databaseBackup->id); $this->dispatch('refreshScheduledBackups', $databaseBackup->id);
} else { } else {
$this->dispatch('refreshScheduledBackups'); $this->dispatch('refreshScheduledBackups');

View File

@@ -77,10 +77,10 @@ class Import extends Component
} }
if ( if (
$this->resource->getMorphClass() == 'App\Models\StandaloneRedis' || $this->resource->getMorphClass() == \App\Models\StandaloneRedis::class ||
$this->resource->getMorphClass() == 'App\Models\StandaloneKeydb' || $this->resource->getMorphClass() == \App\Models\StandaloneKeydb::class ||
$this->resource->getMorphClass() == 'App\Models\StandaloneDragonfly' || $this->resource->getMorphClass() == \App\Models\StandaloneDragonfly::class ||
$this->resource->getMorphClass() == 'App\Models\StandaloneClickhouse' $this->resource->getMorphClass() == \App\Models\StandaloneClickhouse::class
) { ) {
$this->unsupported = true; $this->unsupported = true;
} }
@@ -108,19 +108,19 @@ class Import extends Component
$this->importCommands[] = "docker cp {$tmpPath} {$this->container}:{$tmpPath}"; $this->importCommands[] = "docker cp {$tmpPath} {$this->container}:{$tmpPath}";
switch ($this->resource->getMorphClass()) { switch ($this->resource->getMorphClass()) {
case 'App\Models\StandaloneMariadb': case \App\Models\StandaloneMariadb::class:
$this->importCommands[] = "docker exec {$this->container} sh -c '{$this->mariadbRestoreCommand} < {$tmpPath}'"; $this->importCommands[] = "docker exec {$this->container} sh -c '{$this->mariadbRestoreCommand} < {$tmpPath}'";
$this->importCommands[] = "rm {$tmpPath}"; $this->importCommands[] = "rm {$tmpPath}";
break; break;
case 'App\Models\StandaloneMysql': case \App\Models\StandaloneMysql::class:
$this->importCommands[] = "docker exec {$this->container} sh -c '{$this->mysqlRestoreCommand} < {$tmpPath}'"; $this->importCommands[] = "docker exec {$this->container} sh -c '{$this->mysqlRestoreCommand} < {$tmpPath}'";
$this->importCommands[] = "rm {$tmpPath}"; $this->importCommands[] = "rm {$tmpPath}";
break; break;
case 'App\Models\StandalonePostgresql': case \App\Models\StandalonePostgresql::class:
$this->importCommands[] = "docker exec {$this->container} sh -c '{$this->postgresqlRestoreCommand} {$tmpPath}'"; $this->importCommands[] = "docker exec {$this->container} sh -c '{$this->postgresqlRestoreCommand} {$tmpPath}'";
$this->importCommands[] = "rm {$tmpPath}"; $this->importCommands[] = "rm {$tmpPath}";
break; break;
case 'App\Models\StandaloneMongodb': case \App\Models\StandaloneMongodb::class:
$this->importCommands[] = "docker exec {$this->container} sh -c '{$this->mongodbRestoreCommand}{$tmpPath}'"; $this->importCommands[] = "docker exec {$this->container} sh -c '{$this->mongodbRestoreCommand}{$tmpPath}'";
$this->importCommands[] = "rm {$tmpPath}"; $this->importCommands[] = "rm {$tmpPath}";
break; break;

View File

@@ -29,7 +29,7 @@ class ScheduledBackups extends Component
$this->setSelectedBackup($this->selectedBackupId, true); $this->setSelectedBackup($this->selectedBackupId, true);
} }
$this->parameters = get_route_parameters(); $this->parameters = get_route_parameters();
if ($this->database->getMorphClass() === 'App\Models\ServiceDatabase') { if ($this->database->getMorphClass() === \App\Models\ServiceDatabase::class) {
$this->type = 'service-database'; $this->type = 'service-database';
} else { } else {
$this->type = 'database'; $this->type = 'database';

View File

@@ -46,7 +46,6 @@ class DockerImage extends Component
$project = Project::where('uuid', $this->parameters['project_uuid'])->first(); $project = Project::where('uuid', $this->parameters['project_uuid'])->first();
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first(); $environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
ray($image, $tag);
$application = Application::create([ $application = Application::create([
'name' => 'docker-image-'.new Cuid2, 'name' => 'docker-image-'.new Cuid2,
'repository_project_id' => 0, 'repository_project_id' => 0,

View File

@@ -153,7 +153,6 @@ class GithubPrivateRepository extends Component
protected function loadBranchByPage() protected function loadBranchByPage()
{ {
ray('Loading page '.$this->page);
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}"); $response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}");
$json = $response->json(); $json = $response->json();
if ($response->status() !== 200) { if ($response->status() !== 200) {

View File

@@ -213,7 +213,7 @@ class PublicGitRepository extends Component
return; return;
} }
if ($this->git_source->getMorphClass() === 'App\Models\GithubApp') { if ($this->git_source->getMorphClass() === \App\Models\GithubApp::class) {
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = githubApi(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}"); ['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = githubApi(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
$this->rate_limit_reset = Carbon::parse((int) $this->rate_limit_reset)->format('Y-M-d H:i:s'); $this->rate_limit_reset = Carbon::parse((int) $this->rate_limit_reset)->format('Y-M-d H:i:s');
$this->branchFound = true; $this->branchFound = true;

View File

@@ -96,7 +96,6 @@ class Database extends Component
updateCompose($this->database); updateCompose($this->database);
$this->dispatch('success', 'Database saved.'); $this->dispatch('success', 'Database saved.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
ray($e);
} finally { } finally {
$this->dispatch('generateDockerCompose'); $this->dispatch('generateDockerCompose');
} }

View File

@@ -27,7 +27,6 @@ class Navbar extends Component
public function mount() public function mount()
{ {
if (str($this->service->status())->contains('running') && is_null($this->service->config_hash)) { if (str($this->service->status())->contains('running') && is_null($this->service->config_hash)) {
ray('isConfigurationChanged init');
$this->service->isConfigurationChanged(true); $this->service->isConfigurationChanged(true);
$this->dispatch('configurationChanged'); $this->dispatch('configurationChanged');
} }

View File

@@ -35,7 +35,7 @@ class All extends Component
public function mount() public function mount()
{ {
$this->resourceClass = get_class($this->resource); $this->resourceClass = get_class($this->resource);
$resourceWithPreviews = ['App\Models\Application']; $resourceWithPreviews = [\App\Models\Application::class];
$simpleDockerfile = ! is_null(data_get($this->resource, 'dockerfile')); $simpleDockerfile = ! is_null(data_get($this->resource, 'dockerfile'));
if (str($this->resourceClass)->contains($resourceWithPreviews) && ! $simpleDockerfile) { if (str($this->resourceClass)->contains($resourceWithPreviews) && ! $simpleDockerfile) {
$this->showPreview = true; $this->showPreview = true;

View File

@@ -58,7 +58,7 @@ class Show extends Component
public function mount() public function mount()
{ {
if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') { if ($this->env->getMorphClass() === \App\Models\SharedEnvironmentVariable::class) {
$this->isSharedVariable = true; $this->isSharedVariable = true;
} }
$this->modalId = new Cuid2; $this->modalId = new Cuid2;
@@ -80,7 +80,7 @@ class Show extends Component
public function serialize() public function serialize()
{ {
data_forget($this->env, 'real_value'); data_forget($this->env, 'real_value');
if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') { if ($this->env->getMorphClass() === \App\Models\SharedEnvironmentVariable::class) {
data_forget($this->env, 'is_build_time'); data_forget($this->env, 'is_build_time');
} }
} }

View File

@@ -44,7 +44,7 @@ class GetLogs extends Component
public function mount() public function mount()
{ {
if (! is_null($this->resource)) { if (! is_null($this->resource)) {
if ($this->resource->getMorphClass() === 'App\Models\Application') { if ($this->resource->getMorphClass() === \App\Models\Application::class) {
$this->showTimeStamps = $this->resource->settings->is_include_timestamps; $this->showTimeStamps = $this->resource->settings->is_include_timestamps;
} else { } else {
if ($this->servicesubtype) { if ($this->servicesubtype) {
@@ -53,7 +53,7 @@ class GetLogs extends Component
$this->showTimeStamps = $this->resource->is_include_timestamps; $this->showTimeStamps = $this->resource->is_include_timestamps;
} }
} }
if ($this->resource?->getMorphClass() === 'App\Models\Application') { if ($this->resource?->getMorphClass() === \App\Models\Application::class) {
if (str($this->container)->contains('-pr-')) { if (str($this->container)->contains('-pr-')) {
$this->pull_request = 'Pull Request: '.str($this->container)->afterLast('-pr-')->beforeLast('_')->value(); $this->pull_request = 'Pull Request: '.str($this->container)->afterLast('-pr-')->beforeLast('_')->value();
} }
@@ -69,11 +69,11 @@ class GetLogs extends Component
public function instantSave() public function instantSave()
{ {
if (! is_null($this->resource)) { if (! is_null($this->resource)) {
if ($this->resource->getMorphClass() === 'App\Models\Application') { if ($this->resource->getMorphClass() === \App\Models\Application::class) {
$this->resource->settings->is_include_timestamps = $this->showTimeStamps; $this->resource->settings->is_include_timestamps = $this->showTimeStamps;
$this->resource->settings->save(); $this->resource->settings->save();
} }
if ($this->resource->getMorphClass() === 'App\Models\Service') { if ($this->resource->getMorphClass() === \App\Models\Service::class) {
$serviceName = str($this->container)->beforeLast('-')->value(); $serviceName = str($this->container)->beforeLast('-')->value();
$subType = $this->resource->applications()->where('name', $serviceName)->first(); $subType = $this->resource->applications()->where('name', $serviceName)->first();
if ($subType) { if ($subType) {
@@ -95,7 +95,7 @@ class GetLogs extends Component
if (! $this->server->isFunctional()) { if (! $this->server->isFunctional()) {
return; return;
} }
if (! $refresh && ($this->resource?->getMorphClass() === 'App\Models\Service' || str($this->container)->contains('-pr-'))) { if (! $refresh && ($this->resource?->getMorphClass() === \App\Models\Service::class || str($this->container)->contains('-pr-'))) {
return; return;
} }
if ($this->numberOfLines <= 0 || is_null($this->numberOfLines)) { if ($this->numberOfLines <= 0 || is_null($this->numberOfLines)) {

View File

@@ -109,7 +109,6 @@ class Logs extends Component
$this->containers = $this->containers->filter(function ($container) { $this->containers = $this->containers->filter(function ($container) {
return str_contains($container, $this->query['pull_request_id']); return str_contains($container, $this->query['pull_request_id']);
}); });
ray($this->containers);
} }

View File

@@ -41,7 +41,7 @@ class ResourceOperations extends Component
} }
$uuid = (string) new Cuid2; $uuid = (string) new Cuid2;
$server = $new_destination->server; $server = $new_destination->server;
if ($this->resource->getMorphClass() === 'App\Models\Application') { if ($this->resource->getMorphClass() === \App\Models\Application::class) {
$new_resource = $this->resource->replicate()->fill([ $new_resource = $this->resource->replicate()->fill([
'uuid' => $uuid, 'uuid' => $uuid,
'name' => $this->resource->name.'-clone-'.$uuid, 'name' => $this->resource->name.'-clone-'.$uuid,
@@ -78,14 +78,14 @@ class ResourceOperations extends Component
return redirect()->to($route); return redirect()->to($route);
} elseif ( } elseif (
$this->resource->getMorphClass() === 'App\Models\StandalonePostgresql' || $this->resource->getMorphClass() === \App\Models\StandalonePostgresql::class ||
$this->resource->getMorphClass() === 'App\Models\StandaloneMongodb' || $this->resource->getMorphClass() === \App\Models\StandaloneMongodb::class ||
$this->resource->getMorphClass() === 'App\Models\StandaloneMysql' || $this->resource->getMorphClass() === \App\Models\StandaloneMysql::class ||
$this->resource->getMorphClass() === 'App\Models\StandaloneMariadb' || $this->resource->getMorphClass() === \App\Models\StandaloneMariadb::class ||
$this->resource->getMorphClass() === 'App\Models\StandaloneRedis' || $this->resource->getMorphClass() === \App\Models\StandaloneRedis::class ||
$this->resource->getMorphClass() === 'App\Models\StandaloneKeydb' || $this->resource->getMorphClass() === \App\Models\StandaloneKeydb::class ||
$this->resource->getMorphClass() === 'App\Models\StandaloneDragonfly' || $this->resource->getMorphClass() === \App\Models\StandaloneDragonfly::class ||
$this->resource->getMorphClass() === 'App\Models\StandaloneClickhouse' $this->resource->getMorphClass() === \App\Models\StandaloneClickhouse::class
) { ) {
$uuid = (string) new Cuid2; $uuid = (string) new Cuid2;
$new_resource = $this->resource->replicate()->fill([ $new_resource = $this->resource->replicate()->fill([

View File

@@ -83,7 +83,7 @@ class Add extends Component
]); ]);
$this->file_storage_path = trim($this->file_storage_path); $this->file_storage_path = trim($this->file_storage_path);
$this->file_storage_path = str($this->file_storage_path)->start('/')->value(); $this->file_storage_path = str($this->file_storage_path)->start('/')->value();
if ($this->resource->getMorphClass() === 'App\Models\Application') { if ($this->resource->getMorphClass() === \App\Models\Application::class) {
$fs_path = application_configuration_dir().'/'.$this->resource->uuid.$this->file_storage_path; $fs_path = application_configuration_dir().'/'.$this->resource->uuid.$this->file_storage_path;
} }
LocalFileVolume::create( LocalFileVolume::create(

View File

@@ -4,45 +4,82 @@ namespace App\Livewire\Server;
use App\Jobs\DockerCleanupJob; use App\Jobs\DockerCleanupJob;
use App\Models\Server; use App\Models\Server;
use Livewire\Attributes\Rule;
use Livewire\Component; use Livewire\Component;
class Advanced extends Component class Advanced extends Component
{ {
public Server $server; public Server $server;
protected $rules = [ public array $parameters = [];
'server.settings.concurrent_builds' => 'required|integer|min:1',
'server.settings.dynamic_timeout' => 'required|integer|min:1',
'server.settings.force_docker_cleanup' => 'required|boolean',
'server.settings.docker_cleanup_frequency' => 'required_if:server.settings.force_docker_cleanup,true|string',
'server.settings.docker_cleanup_threshold' => 'required_if:server.settings.force_docker_cleanup,false|integer|min:1|max:100',
'server.settings.server_disk_usage_notification_threshold' => 'required|integer|min:50|max:100',
'server.settings.delete_unused_volumes' => 'boolean',
'server.settings.delete_unused_networks' => 'boolean',
];
protected $validationAttributes = [ #[Rule(['integer', 'min:1'])]
public int $concurrentBuilds = 1;
'server.settings.concurrent_builds' => 'Concurrent Builds', #[Rule(['integer', 'min:1'])]
'server.settings.dynamic_timeout' => 'Dynamic Timeout', public int $dynamicTimeout = 1;
'server.settings.force_docker_cleanup' => 'Force Docker Cleanup',
'server.settings.docker_cleanup_frequency' => 'Docker Cleanup Frequency', #[Rule('boolean')]
'server.settings.docker_cleanup_threshold' => 'Docker Cleanup Threshold', public bool $forceDockerCleanup = false;
'server.settings.server_disk_usage_notification_threshold' => 'Server Disk Usage Notification Threshold',
'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', #[Rule('string')]
'server.settings.delete_unused_networks' => 'Delete Unused Networks', public string $dockerCleanupFrequency = '*/10 * * * *';
];
#[Rule(['integer', 'min:1', 'max:99'])]
public int $dockerCleanupThreshold = 10;
#[Rule(['integer', 'min:1', 'max:99'])]
public int $serverDiskUsageNotificationThreshold = 50;
#[Rule('boolean')]
public bool $deleteUnusedVolumes = false;
#[Rule('boolean')]
public bool $deleteUnusedNetworks = false;
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->parameters = get_route_parameters();
$this->syncData();
} catch (\Throwable $e) {
return redirect()->route('server.show');
}
}
public function syncData(bool $toModel = false)
{
if ($toModel) {
$this->validate();
$this->server->settings->concurrent_builds = $this->concurrentBuilds;
$this->server->settings->dynamic_timeout = $this->dynamicTimeout;
$this->server->settings->force_docker_cleanup = $this->forceDockerCleanup;
$this->server->settings->docker_cleanup_frequency = $this->dockerCleanupFrequency;
$this->server->settings->docker_cleanup_threshold = $this->dockerCleanupThreshold;
$this->server->settings->server_disk_usage_notification_threshold = $this->serverDiskUsageNotificationThreshold;
$this->server->settings->delete_unused_volumes = $this->deleteUnusedVolumes;
$this->server->settings->delete_unused_networks = $this->deleteUnusedNetworks;
$this->server->settings->save();
} else {
$this->concurrentBuilds = $this->server->settings->concurrent_builds;
$this->dynamicTimeout = $this->server->settings->dynamic_timeout;
$this->forceDockerCleanup = $this->server->settings->force_docker_cleanup;
$this->dockerCleanupFrequency = $this->server->settings->docker_cleanup_frequency;
$this->dockerCleanupThreshold = $this->server->settings->docker_cleanup_threshold;
$this->serverDiskUsageNotificationThreshold = $this->server->settings->server_disk_usage_notification_threshold;
$this->deleteUnusedVolumes = $this->server->settings->delete_unused_volumes;
$this->deleteUnusedNetworks = $this->server->settings->delete_unused_networks;
}
}
public function instantSave() public function instantSave()
{ {
try { try {
$this->validate(); $this->syncData(true);
$this->server->settings->save();
$this->dispatch('success', 'Server updated.'); $this->dispatch('success', 'Server updated.');
$this->dispatch('refreshServerShow'); // $this->dispatch('refreshServerShow');
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->server->settings->refresh();
return handleError($e, $this); return handleError($e, $this);
} }
} }
@@ -60,12 +97,11 @@ class Advanced extends Component
public function submit() public function submit()
{ {
try { try {
$frequency = $this->server->settings->docker_cleanup_frequency; if (! validate_cron_expression($this->dockerCleanupFrequency)) {
if (empty($frequency) || ! validate_cron_expression($frequency)) { $this->dockerCleanupFrequency = $this->server->settings->getOriginal('docker_cleanup_frequency');
$this->server->settings->docker_cleanup_frequency = '*/10 * * * *'; throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency.');
throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency. Resetting to default 10 minutes.');
} }
$this->server->settings->save(); $this->syncData(true);
$this->dispatch('success', 'Server updated.'); $this->dispatch('success', 'Server updated.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);

View File

@@ -19,6 +19,15 @@ class Charts extends Component
public bool $poll = true; public bool $poll = true;
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function pollData() public function pollData()
{ {
if ($this->poll || $this->interval <= 10) { if ($this->poll || $this->interval <= 10) {

View File

@@ -3,27 +3,33 @@
namespace App\Livewire\Server; namespace App\Livewire\Server;
use App\Models\Server; use App\Models\Server;
use Livewire\Attributes\Rule;
use Livewire\Component; use Livewire\Component;
class CloudflareTunnels extends Component class CloudflareTunnels extends Component
{ {
public Server $server; public Server $server;
protected $rules = [ #[Rule(['required', 'boolean'])]
'server.settings.is_cloudflare_tunnel' => 'required|boolean', public bool $isCloudflareTunnelsEnabled;
];
protected $validationAttributes = [ public function mount(string $server_uuid)
'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel', {
]; try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->isCloudflareTunnelsEnabled = $this->server->settings->is_cloudflare_tunnel;
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSave() public function instantSave()
{ {
try { try {
$this->validate(); $this->validate();
$this->server->settings->is_cloudflare_tunnel = $this->isCloudflareTunnelsEnabled;
$this->server->settings->save(); $this->server->settings->save();
$this->dispatch('success', 'Server updated.'); $this->dispatch('success', 'Server updated.');
$this->dispatch('refreshServerShow');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);
} }
@@ -31,6 +37,7 @@ class CloudflareTunnels extends Component
public function manualCloudflareConfig() public function manualCloudflareConfig()
{ {
$this->isCloudflareTunnelsEnabled = true;
$this->server->settings->is_cloudflare_tunnel = true; $this->server->settings->is_cloudflare_tunnel = true;
$this->server->settings->save(); $this->server->settings->save();
$this->server->refresh(); $this->server->refresh();

Some files were not shown because too many files have changed in this diff Show More