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
/.ssh
.ignition.json
.env.dusk.local

View File

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

View File

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

1
.gitignore vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,7 +22,7 @@ class StopDatabaseProxy
{
$server = data_get($database, 'destination.server');
$uuid = $database->uuid;
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
$uuid = $database->service->uuid;
$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\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;
use Laravel\Fortify\Contracts\CreatesNewUsers;
class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
/**
* Validate and create a newly registered user.
*
@@ -32,7 +31,7 @@ class CreateNewUser implements CreatesNewUsers
'max:255',
Rule::unique(User::class),
],
'password' => $this->passwordRules(),
'password' => ['required', Password::defaults(), 'confirmed'],
])->validate();
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 Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
@@ -19,7 +18,7 @@ class ResetUserPassword implements ResetsUserPasswords
public function reset(User $user, array $input): void
{
Validator::make($input, [
'password' => $this->passwordRules(),
'password' => ['required', Password::defaults(), 'confirmed'],
])->validate();
$user->forceFill([

View File

@@ -5,12 +5,11 @@ namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
@@ -20,7 +19,7 @@ class UpdateUserPassword implements UpdatesUserPasswords
{
Validator::make($input, [
'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.'),
])->validateWithBag('updatePassword');

View File

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

View File

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

View File

@@ -13,67 +13,63 @@ class StartProxy
public function handle(Server $server, bool $async = true, bool $force = false): string|Activity
{
try {
$proxyType = $server->proxyType();
if ((is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop || $server->isBuildServer()) && $force === false) {
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;
$proxyType = $server->proxyType();
if ((is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop || $server->isBuildServer()) && $force === false) {
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';
}
}
}

View File

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

View File

@@ -16,7 +16,6 @@ class InstallDocker
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>.');
}
ray('Installing Docker on server: '.$server->name.' ('.$server->ip.')'.' with OS type: '.$supported_os_type);
$dockerVersion = '26.0';
$config = base64_encode('{
"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 Lorisleiva\Actions\Concerns\AsAction;
class InstallLogDrain
class StartLogDrain
{
use AsAction;
@@ -13,12 +13,16 @@ class InstallLogDrain
{
if ($server->settings->is_logdrain_newrelic_enabled) {
$type = 'newrelic';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_highlight_enabled) {
$type = 'highlight';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_axiom_enabled) {
$type = 'axiom';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_custom_enabled) {
$type = 'custom';
StopLogDrain::run($server);
} else {
$type = 'none';
}
@@ -151,6 +155,8 @@ services:
- ./parsers.conf:/parsers.conf
ports:
- 127.0.0.1:24224:24224
labels:
- coolify.managed=true
restart: unless-stopped
');
$readme = base64_encode('# New Relic Log Drain
@@ -202,15 +208,11 @@ Files:
throw new \Exception('Unknown log drain type.');
}
$restart_command = [
"echo 'Stopping old Fluent Bit'",
"cd $config_path && docker compose down --remove-orphans || true",
"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);
StopLogDrain::run($server);
return instant_remote_process($command, $server);
} catch (\Throwable $e) {
return handleError($e);

View File

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

View File

@@ -12,7 +12,7 @@ class StopLogDrain
public function handle(Server $server)
{
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) {
return handleError($e);
}

View File

@@ -18,32 +18,28 @@ class UpdateCoolify
public function handle($manual_update = false)
{
try {
$settings = instanceSettings();
$this->server = Server::find(0);
if (! $this->server) {
$settings = instanceSettings();
$this->server = Server::find(0);
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;
}
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;
}
if ($this->latestVersion === $this->currentVersion) {
return;
}
if (version_compare($this->latestVersion, $this->currentVersion, '<')) {
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()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -180,7 +180,7 @@ class Init extends Command
'save_s3' => false,
'frequency' => '0 0 * * *',
'database_id' => $database->id,
'database_type' => 'App\Models\StandalonePostgresql',
'database_type' => \App\Models\StandalonePostgresql::class,
'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();
foreach ($queued_inprogress_deployments as $deployment) {
ray($deployment->id, $deployment->status);
echo "Cleaning up deployment: {$deployment->id}\n";
$deployment->status = ApplicationDeploymentStatus::FAILED->value;
$deployment->save();

View File

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

View File

@@ -12,6 +12,7 @@ use App\Jobs\DockerCleanupJob;
use App\Jobs\PullTemplatesFromCDN;
use App\Jobs\ScheduledTaskJob;
use App\Jobs\ServerCheckJob;
use App\Jobs\ServerCleanupMux;
use App\Jobs\UpdateCoolifyJob;
use App\Models\ScheduledDatabaseBackup;
use App\Models\ScheduledTask;
@@ -120,6 +121,15 @@ class Kernel extends ConsoleKernel
} else {
$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;
}
if (is_null(data_get($scheduled_backup, 'database'))) {
ray('database not found');
$scheduled_backup->delete();
continue;
@@ -170,7 +179,6 @@ class Kernel extends ConsoleKernel
$application = $scheduled_task->application;
if (! $application && ! $service) {
ray('application/service attached to scheduled task does not exist');
$scheduled_task->delete();
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)
{
ray($teamId);
if (is_null($teamId)) {
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')) {
return;
}
ray('reporting to sentry');
Integration::captureUnhandledException($e);
});
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,7 +17,6 @@ class Gitlab extends Controller
{
try {
if (app()->isDownForMaintenance()) {
ray('Maintenance mode is on');
$epoch = now()->valueOf();
$data = [
'attributes' => $request->attributes->all(),
@@ -67,7 +66,6 @@ class Gitlab extends Controller
$removed_files = data_get($payload, 'commits.*.removed');
$modified_files = data_get($payload, 'commits.*.modified');
$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') {
$action = data_get($payload, 'object_attributes.action');
@@ -84,7 +82,6 @@ class Gitlab extends Controller
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%");
if ($x_gitlab_event === 'push') {
@@ -117,7 +114,6 @@ class Gitlab extends Controller
'status' => 'failed',
'message' => 'Invalid signature.',
]);
ray('Invalid signature');
continue;
}
@@ -128,7 +124,6 @@ class Gitlab extends Controller
'status' => 'failed',
'message' => 'Server is not functional',
]);
ray('Server is not functional: '.$application->destination->server->name);
continue;
}
@@ -136,7 +131,6 @@ class Gitlab extends Controller
if ($application->isDeployable()) {
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
ray('Deploying '.$application->name.' with branch '.$branch);
$deployment_uuid = new Cuid2;
queue_application_deployment(
application: $application,
@@ -171,7 +165,6 @@ class Gitlab extends Controller
'application_uuid' => $application->uuid,
'application_name' => $application->name,
]);
ray('Deployments disabled for '.$application->name);
}
}
if ($x_gitlab_event === 'merge_request') {
@@ -207,7 +200,6 @@ class Gitlab extends Controller
is_webhook: true,
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([
'application' => $application->name,
'status' => 'success',
@@ -219,7 +211,6 @@ class Gitlab extends Controller
'status' => 'failed',
'message' => 'Preview deployments disabled',
]);
ray('Preview deployments disabled for '.$application->name);
}
} elseif ($action === 'closed' || $action === 'close' || $action === 'merge') {
$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);
} catch (Exception $e) {
ray($e->getMessage());
return handleError($e);
}
}

View File

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

View File

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

View File

@@ -10,7 +10,6 @@ class ApiAllowed
{
public function handle(Request $request, Closure $next): Response
{
ray()->clearAll();
if (isCloud()) {
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}";
}
}
ray('New container name: ', $this->container_name)->green();
$this->saved_outputs = collect();
@@ -298,7 +297,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
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);
}
ray($e);
$this->fail($e);
throw $e;
} finally {
@@ -389,7 +387,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
} else {
$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->generate_image_names();
$this->prepare_builder_image();
@@ -712,38 +709,26 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
{
$forceFail = true;
if (str($this->application->docker_registry_image_name)->isEmpty()) {
ray('empty docker_registry_image_name');
return;
}
if ($this->restart_only) {
ray('restart_only');
return;
}
if ($this->application->build_pack === 'dockerimage') {
ray('dockerimage');
return;
}
if ($this->use_build_server) {
ray('use_build_server');
$forceFail = true;
}
if ($this->server->isSwarm() && $this->build_pack !== 'dockerimage') {
ray('isSwarm');
$forceFail = true;
}
if ($this->application->additional_servers->count() > 0) {
ray('additional_servers');
$forceFail = true;
}
if ($this->is_this_additional_server) {
ray('this is an additional_servers, no pushy pushy');
return;
}
ray('push_to_docker_registry noww: '.$this->production_image_name);
try {
instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server);
$this->application_deployment_queue->addLogEntry('----------------------------------------');
@@ -775,7 +760,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
if ($forceFail) {
throw new RuntimeException($e->getMessage(), 69420);
}
ray($e);
}
}
@@ -1386,8 +1370,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
return;
}
if ($destination_ids->contains($this->destination->id)) {
ray('Same destination found in additional destinations. Skipping.');
return;
}
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') {
$code = $exception->getCode();
ray($code);
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
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 {
if ($this->application->is_public_repository()) {
ray('Public repository. Skipping comment update.');
return;
}
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 .= 'Last updated at: '.now()->toDateTimeString().' CET';
ray('Updating comment', $this->body);
if ($this->preview->pull_request_issue_comment_id) {
$this->update_comment();
} else {
$this->create_comment();
}
} catch (\Throwable $e) {
ray($e);
return $e;
}
}
@@ -73,7 +67,6 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
'body' => $this->body,
], throwError: false);
if (data_get($data, 'message') === 'Not Found') {
ray('Comment not found. Creating new one.');
$this->create_comment();
}
}

View File

@@ -21,36 +21,32 @@ class CheckAndStartSentinelJob implements ShouldBeEncrypted, ShouldQueue
public function handle(): void
{
try {
$latestVersion = get_latest_sentinel_version();
$latestVersion = get_latest_sentinel_version();
// Check if sentinel is running
$sentinelFound = instant_remote_process(['docker inspect coolify-sentinel'], $this->server, false);
$sentinelFoundJson = json_decode($sentinelFound, true);
$sentinelStatus = data_get($sentinelFoundJson, '0.State.Status', 'exited');
if ($sentinelStatus !== 'running') {
// Check if sentinel is running
$sentinelFound = instant_remote_process(['docker inspect coolify-sentinel'], $this->server, false);
$sentinelFoundJson = json_decode($sentinelFound, true);
$sentinelStatus = data_get($sentinelFoundJson, '0.State.Status', 'exited');
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);
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();
} catch (\Throwable $e) {
send_internal_notification('CheckResaleLicenseJob failed with: '.$e->getMessage());
ray($e);
throw $e;
}
}

View File

@@ -20,18 +20,15 @@ class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, S
public function handle(): void
{
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);
$containerIds = collect(json_decode($containers))->pluck('ID');
if ($containerIds->count() > 0) {
foreach ($containerIds as $containerId) {
ray('Removing container '.$containerId);
instant_remote_process(['docker container rm -f '.$containerId], $this->server, false);
}
}
} catch (\Throwable $e) {
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();
} catch (\Throwable $e) {
send_internal_notification('CleanupInstanceStuffsJob failed with error: '.$e->getMessage());
ray($e->getMessage());
}
try {
$this->cleanup_invitation_link();
} catch (\Throwable $e) {
send_internal_notification('CleanupInstanceStuffsJob failed with error: '.$e->getMessage());
ray($e->getMessage());
}
}

View File

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

View File

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

View File

@@ -25,7 +25,6 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue
if (isDev() || isCloud()) {
return;
}
ray('PullTemplatesAndVersions service-templates');
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
if ($response->successful()) {
$services = $response->json();
@@ -35,7 +34,6 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue
}
} catch (\Throwable $e) {
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\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy;
use App\Actions\Server\InstallLogDrain;
use App\Actions\Server\StartLogDrain;
use App\Actions\Shared\ComplexStatusCheck;
use App\Models\Application;
use App\Models\ApplicationPreview;
@@ -91,123 +91,113 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
public function handle()
{
// TODO: Swarm is not supported yet
try {
if (! $this->data) {
throw new \Exception('No data provided');
}
$data = collect($this->data);
if (! $this->data) {
throw new \Exception('No data provided');
}
$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');
ServerStorageCheckJob::dispatch($this->server, $filesystemUsageRoot);
$filesystemUsageRoot = data_get($data, 'filesystem_usage_root.used_percentage');
ServerStorageCheckJob::dispatch($this->server, $filesystemUsageRoot);
if ($this->containers->isEmpty()) {
return;
}
$this->applications = $this->server->applications();
$this->databases = $this->server->databases();
$this->previews = $this->server->previews();
$this->services = $this->server->services()->get();
$this->allApplicationIds = $this->applications->filter(function ($application) {
return $application->additional_servers->count() === 0;
})->pluck('id');
$this->allApplicationsWithAdditionalServers = $this->applications->filter(function ($application) {
return $application->additional_servers->count() > 0;
if ($this->containers->isEmpty()) {
return;
}
$this->applications = $this->server->applications();
$this->databases = $this->server->databases();
$this->previews = $this->server->previews();
$this->services = $this->server->services()->get();
$this->allApplicationIds = $this->applications->filter(function ($application) {
return $application->additional_servers->count() === 0;
})->pluck('id');
$this->allApplicationsWithAdditionalServers = $this->applications->filter(function ($application) {
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');
$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);
});
$service->databases()->pluck('id')->each(function ($databaseId) {
$this->allServiceDatabaseIds->push($databaseId);
});
$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');
$containerHealth = data_get($container, 'health_status', 'unhealthy');
$containerStatus = "$containerStatus ($containerHealth)";
$labels = collect(data_get($container, 'labels'));
$coolify_managed = $labels->has('coolify.managed');
if ($coolify_managed) {
$name = data_get($container, 'name');
if ($name === 'coolify-log-drain' && $this->isRunning($containerStatus)) {
$this->foundLogDrainContainer = true;
}
if ($labels->has('coolify.applicationId')) {
$applicationId = $labels->get('coolify.applicationId');
$pullRequestId = data_get($labels, 'coolify.pullRequestId', '0');
try {
if ($pullRequestId === '0') {
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);
foreach ($this->containers as $container) {
$containerStatus = data_get($container, 'state', 'exited');
$containerHealth = data_get($container, 'health_status', 'unhealthy');
$containerStatus = "$containerStatus ($containerHealth)";
$labels = collect(data_get($container, 'labels'));
$coolify_managed = $labels->has('coolify.managed');
if ($coolify_managed) {
$name = data_get($container, 'name');
if ($name === 'coolify-log-drain' && $this->isRunning($containerStatus)) {
$this->foundLogDrainContainer = true;
}
if ($labels->has('coolify.applicationId')) {
$applicationId = $labels->get('coolify.applicationId');
$pullRequestId = data_get($labels, 'coolify.pullRequestId', '0');
try {
if ($pullRequestId === '0') {
if ($this->allApplicationIds->contains($applicationId) && $this->isRunning($containerStatus)) {
$this->foundApplicationIds->push($applicationId);
}
} catch (\Exception $e) {
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");
$this->updateApplicationStatus($applicationId, $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);
}
if ($this->allApplicationPreviewsIds->contains($applicationId) && $this->isRunning($containerStatus)) {
$this->foundApplicationPreviewsIds->push($applicationId);
}
$this->updateApplicationPreviewStatus($applicationId, $containerStatus);
}
} 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)
@@ -218,7 +208,6 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
}
$application->status = $containerStatus;
$application->save();
ray('Application updated', ['application_id' => $applicationId, 'status' => $containerStatus]);
}
private function updateApplicationPreviewStatus(string $applicationId, string $containerStatus)
@@ -229,21 +218,17 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
}
$application->status = $containerStatus;
$application->save();
ray('Application preview updated', ['application_id' => $applicationId, 'status' => $containerStatus]);
}
private function updateNotFoundApplicationStatus()
{
$notFoundApplicationIds = $this->allApplicationIds->diff($this->foundApplicationIds);
if ($notFoundApplicationIds->isNotEmpty()) {
ray('Not found application ids', ['application_ids' => $notFoundApplicationIds]);
$notFoundApplicationIds->each(function ($applicationId) {
ray('Updating application status', ['application_id' => $applicationId, 'status' => 'exited']);
$application = Application::find($applicationId);
if ($application) {
$application->status = 'exited';
$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);
if ($notFoundApplicationPreviewsIds->isNotEmpty()) {
ray('Not found application previews ids', ['application_previews_ids' => $notFoundApplicationPreviewsIds]);
$notFoundApplicationPreviewsIds->each(function ($applicationPreviewId) {
ray('Updating application preview status', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']);
$applicationPreview = ApplicationPreview::find($applicationPreviewId);
if ($applicationPreview) {
$applicationPreview->status = 'exited';
$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->save();
ray('Database status updated', ['database_uuid' => $databaseUuid, 'status' => $containerStatus]);
if ($this->isRunning($containerStatus) && $tcpProxy) {
$tcpProxyContainerFound = $this->containers->filter(function ($value, $key) use ($databaseUuid) {
return data_get($value, 'name') === "$databaseUuid-proxy" && data_get($value, 'state') === 'running';
})->first();
if (! $tcpProxyContainerFound) {
ray('Starting TCP proxy for database', ['database_uuid' => $databaseUuid]);
StartDatabaseProxy::dispatch($database);
$this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
} 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);
if ($notFoundDatabaseUuids->isNotEmpty()) {
ray('Not found database uuids', ['database_uuids' => $notFoundDatabaseUuids]);
$notFoundDatabaseUuids->each(function ($databaseUuid) {
ray('Updating database status', ['database_uuid' => $databaseUuid, 'status' => 'exited']);
$database = $this->databases->where('uuid', $databaseUuid)->first();
if ($database) {
$database->status = 'exited';
$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) {
ray('Stopping TCP proxy for database', ['database_uuid' => $databaseUuid]);
StopDatabaseProxy::dispatch($database);
}
}
@@ -341,14 +315,11 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
$application = $service->applications()->where('id', $subId)->first();
$application->status = $containerStatus;
$application->save();
ray('Service application updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]);
} elseif ($subType === 'database') {
$database = $service->databases()->where('id', $subId)->first();
$database->status = $containerStatus;
$database->save();
ray('Service database updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]);
} 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);
$notFoundServiceDatabaseIds = $this->allServiceDatabaseIds->diff($this->foundServiceDatabaseIds);
if ($notFoundServiceApplicationIds->isNotEmpty()) {
ray('Not found service application ids', ['service_application_ids' => $notFoundServiceApplicationIds]);
$notFoundServiceApplicationIds->each(function ($serviceApplicationId) {
ray('Updating service application status', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']);
$application = ServiceApplication::find($serviceApplicationId);
if ($application) {
$application->status = 'exited';
$application->save();
ray('Service application status updated', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']);
}
});
}
if ($notFoundServiceDatabaseIds->isNotEmpty()) {
ray('Not found service database ids', ['service_database_ids' => $notFoundServiceDatabaseIds]);
$notFoundServiceDatabaseIds->each(function ($serviceDatabaseId) {
ray('Updating service database status', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']);
$database = ServiceDatabase::find($serviceDatabaseId);
if ($database) {
$database->status = 'exited';
$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()
{
$this->allApplicationsWithAdditionalServers->each(function ($application) {
ray('Updating additional servers status for application', ['application_id' => $application->id]);
ComplexStatusCheck::run($application);
});
}
@@ -398,7 +362,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
private function checkLogDrainContainer()
{
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);
} catch (\Throwable $e) {
send_internal_notification("SendConfirmationForWaitlistJob failed for {$this->email} with error: ".$e->getMessage());
ray($e->getMessage());
throw $e;
}
}

View File

@@ -5,7 +5,7 @@ namespace App\Jobs;
use App\Actions\Docker\GetContainersStatus;
use App\Actions\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy;
use App\Actions\Server\InstallLogDrain;
use App\Actions\Server\StartLogDrain;
use App\Models\Server;
use App\Notifications\Container\ContainerRestarted;
use Illuminate\Bus\Queueable;
@@ -85,7 +85,6 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
$this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
}
} catch (\Throwable $e) {
ray($e);
}
} else {
$this->server->proxy->status = data_get($foundProxyContainer, 'State.Status');
@@ -97,8 +96,6 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
}
} catch (\Throwable $e) {
ray($e->getMessage());
return handleError($e);
}
@@ -112,10 +109,10 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
if ($foundLogDrainContainer) {
$status = data_get($foundLogDrainContainer, 'State.Status');
if ($status !== 'running') {
InstallLogDrain::dispatch($this->server);
StartLogDrain::dispatch($this->server);
}
} 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();
$limit = data_get($this->team->limits, 'serverLimit', 2);
$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) {
ray('Disabling servers');
$servers = $servers->sortbyDesc('created_at');
$servers_to_disable = $servers->take($number_of_servers_to_disable);
$servers_to_disable->each(function ($server) {
@@ -51,7 +49,6 @@ class ServerLimitCheckJob implements ShouldBeEncrypted, ShouldQueue
}
} catch (\Throwable $e) {
send_internal_notification('ServerLimitCheckJob failed with: '.$e->getMessage());
ray($e->getMessage());
return handleError($e);
}

View File

@@ -38,7 +38,6 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue
if (is_null($this->percentage)) {
$this->percentage = $this->server->storageCheck();
loggy('Server storage check percentage: '.$this->percentage);
}
if (! $this->percentage) {
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.');
$this->team->members()->each(function ($member) use ($mail) {
ray($member);
if ($member->isAdmin()) {
send_user_an_email($mail, $member->email);
}
});
} catch (\Throwable $e) {
send_internal_notification('SubscriptionInvoiceFailedJob failed with: '.$e->getMessage());
ray($e->getMessage());
throw $e;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -73,8 +73,6 @@ class Index extends Component
}
$this->privateKeyName = generate_random_name();
$this->remoteServerName = generate_random_name();
$this->remoteServerPort = $this->remoteServerPort;
$this->remoteServerUser = $this->remoteServerUser;
if (isDev()) {
$this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
@@ -87,26 +85,6 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
$this->remoteServerDescription = 'Created by Coolify';
$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()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -57,7 +57,7 @@ class BackupExecutions extends Component
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);
} else {
delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->destination->server);

View File

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

View File

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

View File

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

View File

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

View File

@@ -153,7 +153,6 @@ class GithubPrivateRepository extends Component
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}");
$json = $response->json();
if ($response->status() !== 200) {

View File

@@ -213,7 +213,7 @@ class PublicGitRepository extends Component
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}");
$this->rate_limit_reset = Carbon::parse((int) $this->rate_limit_reset)->format('Y-M-d H:i:s');
$this->branchFound = true;

View File

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

View File

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

View File

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

View File

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

View File

@@ -44,7 +44,7 @@ class GetLogs extends Component
public function mount()
{
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;
} else {
if ($this->servicesubtype) {
@@ -53,7 +53,7 @@ class GetLogs extends Component
$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-')) {
$this->pull_request = 'Pull Request: '.str($this->container)->afterLast('-pr-')->beforeLast('_')->value();
}
@@ -69,11 +69,11 @@ class GetLogs extends Component
public function instantSave()
{
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->save();
}
if ($this->resource->getMorphClass() === 'App\Models\Service') {
if ($this->resource->getMorphClass() === \App\Models\Service::class) {
$serviceName = str($this->container)->beforeLast('-')->value();
$subType = $this->resource->applications()->where('name', $serviceName)->first();
if ($subType) {
@@ -95,7 +95,7 @@ class GetLogs extends Component
if (! $this->server->isFunctional()) {
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;
}
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) {
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;
$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([
'uuid' => $uuid,
'name' => $this->resource->name.'-clone-'.$uuid,
@@ -78,14 +78,14 @@ class ResourceOperations extends Component
return redirect()->to($route);
} elseif (
$this->resource->getMorphClass() === 'App\Models\StandalonePostgresql' ||
$this->resource->getMorphClass() === 'App\Models\StandaloneMongodb' ||
$this->resource->getMorphClass() === 'App\Models\StandaloneMysql' ||
$this->resource->getMorphClass() === 'App\Models\StandaloneMariadb' ||
$this->resource->getMorphClass() === 'App\Models\StandaloneRedis' ||
$this->resource->getMorphClass() === 'App\Models\StandaloneKeydb' ||
$this->resource->getMorphClass() === 'App\Models\StandaloneDragonfly' ||
$this->resource->getMorphClass() === 'App\Models\StandaloneClickhouse'
$this->resource->getMorphClass() === \App\Models\StandalonePostgresql::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneMongodb::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneMysql::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneMariadb::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneRedis::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneKeydb::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneDragonfly::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneClickhouse::class
) {
$uuid = (string) new Cuid2;
$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 = 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;
}
LocalFileVolume::create(

View File

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

View File

@@ -19,6 +19,15 @@ class Charts extends Component
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()
{
if ($this->poll || $this->interval <= 10) {

View File

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

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