From 678647f39a69861971ce2e3500712da8f7d6fe31 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 26 Feb 2024 10:25:21 +0100 Subject: [PATCH] fix: force enable/disable server in case ultimate package quantity decreases --- app/Http/Controllers/Api/Deploy.php | 2 +- app/Http/Controllers/Api/Project.php | 2 +- app/Http/Controllers/Api/Server.php | 2 +- app/Jobs/ApplicationDeploymentJob.php | 1 - ...verflowJob.php => ServerLimitCheckJob.php} | 24 ++++--- app/Livewire/Admin/Index.php | 3 + app/Livewire/Tags/Show.php | 2 +- app/Models/Server.php | 27 ++++++-- ...ledDueToOverflow.php => ForceDisabled.php} | 4 +- app/Notifications/Server/ForceEnabled.php | 63 +++++++++++++++++++ app/Traits/ExecuteRemoteCommand.php | 6 ++ ...22150_add_server_force_disabled_field.php} | 4 +- .../views/components/server/sidebar.blade.php | 40 +++++------- ...de.php => server-force-disabled.blade.php} | 0 .../emails/server-force-enabled.blade.php | 3 + .../views/livewire/layout-popups.blade.php | 10 ++- .../views/livewire/server/delete.blade.php | 2 +- .../views/livewire/server/form.blade.php | 4 ++ .../views/livewire/server/index.blade.php | 11 ++-- .../proxy/dynamic-configurations.blade.php | 3 +- .../livewire/server/proxy/show.blade.php | 14 +++-- .../livewire/subscription/actions.blade.php | 2 +- routes/api.php | 6 +- routes/web.php | 1 - routes/webhooks.php | 4 +- 25 files changed, 172 insertions(+), 68 deletions(-) rename app/Jobs/{ServerOverflowJob.php => ServerLimitCheckJob.php} (62%) rename app/Notifications/Server/{DisabledDueToOverflow.php => ForceDisabled.php} (93%) create mode 100644 app/Notifications/Server/ForceEnabled.php rename database/migrations/{2024_02_25_222150_add_disabled_server_due_to_overflow.php => 2024_02_25_222150_add_server_force_disabled_field.php} (80%) rename resources/views/emails/{server-disabled-due-to-overflow.blade.php => server-force-disabled.blade.php} (100%) create mode 100644 resources/views/emails/server-force-enabled.blade.php diff --git a/app/Http/Controllers/Api/Deploy.php b/app/Http/Controllers/Api/Deploy.php index 21da51d66..27d4b1ea0 100644 --- a/app/Http/Controllers/Api/Deploy.php +++ b/app/Http/Controllers/Api/Deploy.php @@ -14,7 +14,7 @@ use Illuminate\Support\Collection; use Visus\Cuid2\Cuid2; -class Deploy extends Controller +class APIDeploy extends Controller { public function deploy(Request $request) { diff --git a/app/Http/Controllers/Api/Project.php b/app/Http/Controllers/Api/Project.php index fa2ba34bb..110e51803 100644 --- a/app/Http/Controllers/Api/Project.php +++ b/app/Http/Controllers/Api/Project.php @@ -6,7 +6,7 @@ use App\Models\Project as ModelsProject; use Illuminate\Http\Request; -class Project extends Controller +class APIProject extends Controller { public function projects(Request $request) { diff --git a/app/Http/Controllers/Api/Server.php b/app/Http/Controllers/Api/Server.php index e7b071a43..bab37928f 100644 --- a/app/Http/Controllers/Api/Server.php +++ b/app/Http/Controllers/Api/Server.php @@ -6,7 +6,7 @@ use App\Models\Server as ModelsServer; use Illuminate\Http\Request; -class Server extends Controller +class APIServer extends Controller { public function servers(Request $request) { diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 61cda4fc6..0949ef5e6 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1675,7 +1675,6 @@ public function failed(Throwable $exception): void ); } } - $this->next(ApplicationDeploymentStatus::FAILED->value); } } diff --git a/app/Jobs/ServerOverflowJob.php b/app/Jobs/ServerLimitCheckJob.php similarity index 62% rename from app/Jobs/ServerOverflowJob.php rename to app/Jobs/ServerLimitCheckJob.php index af7b7a927..052260895 100644 --- a/app/Jobs/ServerOverflowJob.php +++ b/app/Jobs/ServerLimitCheckJob.php @@ -3,7 +3,8 @@ namespace App\Jobs; use App\Models\Team; -use App\Notifications\Server\DisabledDueToOverflow; +use App\Notifications\Server\ForceDisabled; +use App\Notifications\Server\ForceEnabled; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; @@ -12,7 +13,7 @@ use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\SerializesModels; -class ServerOverflowJob implements ShouldQueue, ShouldBeEncrypted +class ServerLimitCheckJob implements ShouldQueue, ShouldBeEncrypted { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; @@ -37,26 +38,31 @@ public function uniqueId(): int public function handle() { try { - ray('ServerOverflowJob'); $servers = $this->team->servers; $servers_count = $servers->count(); $limit = $this->team->limits['serverLimit']; $number_of_servers_to_disable = $servers_count - $limit; - ray($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->sortBy('created_at'); + $servers = $servers->sortbyDesc('created_at'); $servers_to_disable = $servers->take($number_of_servers_to_disable); $servers_to_disable->each(function ($server) { - $server->disableServerDueToOverflow(); - $this->team->notify(new DisabledDueToOverflow($server)); + $server->forceDisableServer(); + $this->team->notify(new ForceDisabled($server)); + }); + } else if ($number_of_servers_to_disable === 0) { + $servers->each(function ($server) { + if ($server->isForceDisabled()) { + $server->forceEnableServer(); + $this->team->notify(new ForceEnabled($server)); + } }); } } catch (\Throwable $e) { - send_internal_notification('ServerOverflowJob failed with: ' . $e->getMessage()); + send_internal_notification('ServerLimitCheckJob failed with: ' . $e->getMessage()); ray($e->getMessage()); return handleError($e); } } - } diff --git a/app/Livewire/Admin/Index.php b/app/Livewire/Admin/Index.php index 4ff4ff21b..27e912eed 100644 --- a/app/Livewire/Admin/Index.php +++ b/app/Livewire/Admin/Index.php @@ -3,6 +3,7 @@ namespace App\Livewire\Admin; use App\Models\User; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Crypt; use Livewire\Component; @@ -27,6 +28,7 @@ public function switchUser(int $user_id) auth()->login($user); if ($user_id === 0) { + Cache::forget('team:0'); session()->forget('adminToken'); } else { $token_payload = [ @@ -35,6 +37,7 @@ public function switchUser(int $user_id) $token = Crypt::encrypt($token_payload); session(['adminToken' => $token]); } + session()->regenerate(); return refreshSession(); } public function render() diff --git a/app/Livewire/Tags/Show.php b/app/Livewire/Tags/Show.php index 05b25955a..c0c975f6d 100644 --- a/app/Livewire/Tags/Show.php +++ b/app/Livewire/Tags/Show.php @@ -2,7 +2,7 @@ namespace App\Livewire\Tags; -use App\Http\Controllers\Api\Deploy; +use App\Http\Controllers\Api\APIDeploy as Deploy; use App\Models\ApplicationDeploymentQueue; use App\Models\Tag; use Livewire\Component; diff --git a/app/Models/Server.php b/app/Models/Server.php index 4272761a5..fc400935a 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Storage; use Spatie\SchemalessAttributes\Casts\SchemalessAttributes; use Spatie\SchemalessAttributes\SchemalessAttributesTrait; use Illuminate\Support\Str; @@ -69,7 +70,7 @@ static public function ownedByCurrentTeam(array $select = ['*']) static public function isUsable() { - return Server::ownedByCurrentTeam()->whereRelation('settings', 'is_reachable', true)->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_swarm_worker', false)->whereRelation('settings', 'is_build_server', false); + return Server::ownedByCurrentTeam()->whereRelation('settings', 'is_reachable', true)->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_swarm_worker', false)->whereRelation('settings', 'is_build_server', false)->whereRelation('settings', 'force_disabled', false); } static public function destinationsByServer(string $server_id) @@ -149,13 +150,31 @@ public function skipServer() ray('skipping 1.2.3.4'); return true; } + if ($this->settings->force_disabled === true) { + ray('force_disabled'); + return true; + } return false; } - public function disableServerDueToOverflow() { + public function isForceDisabled() + { + return $this->settings->force_disabled; + } + public function forceEnableServer() + { $this->settings->update([ - 'disabled_by_overflow' => true, + 'force_disabled' => false, ]); } + public function forceDisableServer() + { + $this->settings->update([ + 'force_disabled' => true, + ]); + $sshKeyFileLocation = "id.root@{$this->uuid}"; + Storage::disk('ssh-keys')->delete($sshKeyFileLocation); + Storage::disk('ssh-mux')->delete($this->muxFilename()); + } public function isServerReady(int $tries = 3) { if ($this->skipServer()) { @@ -379,7 +398,7 @@ public function isProxyShouldRun() } public function isFunctional() { - return $this->settings->is_reachable && $this->settings->is_usable; + return $this->settings->is_reachable && $this->settings->is_usable && !$this->settings->force_disabled; } public function isLogDrainEnabled() { diff --git a/app/Notifications/Server/DisabledDueToOverflow.php b/app/Notifications/Server/ForceDisabled.php similarity index 93% rename from app/Notifications/Server/DisabledDueToOverflow.php rename to app/Notifications/Server/ForceDisabled.php index 957d9c866..4bce44e46 100644 --- a/app/Notifications/Server/DisabledDueToOverflow.php +++ b/app/Notifications/Server/ForceDisabled.php @@ -11,7 +11,7 @@ use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; -class DisabledDueToOverflow extends Notification implements ShouldQueue +class ForceDisabled extends Notification implements ShouldQueue { use Queueable; @@ -43,7 +43,7 @@ public function toMail(): MailMessage { $mail = new MailMessage(); $mail->subject("Coolify: Server ({$this->server->name}) disabled because it is not paid!"); - $mail->view('emails.server-disabled-due-to-overflow', [ + $mail->view('emails.server-force-disabled', [ 'name' => $this->server->name, ]); return $mail; diff --git a/app/Notifications/Server/ForceEnabled.php b/app/Notifications/Server/ForceEnabled.php new file mode 100644 index 000000000..c29a08644 --- /dev/null +++ b/app/Notifications/Server/ForceEnabled.php @@ -0,0 +1,63 @@ +subject("Coolify: Server ({$this->server->name}) enabled again!"); + $mail->view('emails.server-force-enabled', [ + 'name' => $this->server->name, + ]); + return $mail; + } + + public function toDiscord(): string + { + $message = "Coolify: Server ({$this->server->name}) enabled again!"; + return $message; + } + public function toTelegram(): array + { + return [ + "message" => "Coolify: Server ({$this->server->name}) enabled again!" + ]; + } +} diff --git a/app/Traits/ExecuteRemoteCommand.php b/app/Traits/ExecuteRemoteCommand.php index 529dacd7a..9b34fabae 100644 --- a/app/Traits/ExecuteRemoteCommand.php +++ b/app/Traits/ExecuteRemoteCommand.php @@ -24,6 +24,12 @@ public function execute_remote_command(...$commands) if ($this->server instanceof Server === false) { throw new \RuntimeException('Server is not set or is not an instance of Server model'); } + if ($this->server->settings->force_disabled) { + $this->application_deployment_queue->update([ + 'status' => ApplicationDeploymentStatus::FAILED->value, + ]); + throw new \RuntimeException('Server is disabled'); + } $commandsText->each(function ($single_command) { $command = data_get($single_command, 'command') ?? $single_command[0] ?? null; if ($command === null) { diff --git a/database/migrations/2024_02_25_222150_add_disabled_server_due_to_overflow.php b/database/migrations/2024_02_25_222150_add_server_force_disabled_field.php similarity index 80% rename from database/migrations/2024_02_25_222150_add_disabled_server_due_to_overflow.php rename to database/migrations/2024_02_25_222150_add_server_force_disabled_field.php index 3d1b808ab..8509a9909 100644 --- a/database/migrations/2024_02_25_222150_add_disabled_server_due_to_overflow.php +++ b/database/migrations/2024_02_25_222150_add_server_force_disabled_field.php @@ -12,7 +12,7 @@ public function up(): void { Schema::table('server_settings', function (Blueprint $table) { - $table->boolean('disabled_by_overflow')->default(false); + $table->boolean('force_disabled')->default(false); }); } @@ -22,7 +22,7 @@ public function up(): void public function down(): void { Schema::table('server_settings', function (Blueprint $table) { - $table->dropColumn('disabled_by_overflow'); + $table->dropColumn('force_disabled'); }); } }; diff --git a/resources/views/components/server/sidebar.blade.php b/resources/views/components/server/sidebar.blade.php index 86bb92a87..a163bf05f 100644 --- a/resources/views/components/server/sidebar.blade.php +++ b/resources/views/components/server/sidebar.blade.php @@ -1,24 +1,18 @@ -
- @if ($server->isFunctional()) -
-
- - - - @if (data_get($server, 'proxy.type') !== 'NONE') - - - - - - - @endif -
-
- @else -
Server is not validated. Validate first.
- @endif +
+
+ + + + @if (data_get($server, 'proxy.type') !== 'NONE') + + + + + + + @endif +
diff --git a/resources/views/emails/server-disabled-due-to-overflow.blade.php b/resources/views/emails/server-force-disabled.blade.php similarity index 100% rename from resources/views/emails/server-disabled-due-to-overflow.blade.php rename to resources/views/emails/server-force-disabled.blade.php diff --git a/resources/views/emails/server-force-enabled.blade.php b/resources/views/emails/server-force-enabled.blade.php new file mode 100644 index 000000000..34718632c --- /dev/null +++ b/resources/views/emails/server-force-enabled.blade.php @@ -0,0 +1,3 @@ + +Your server ({{ $name }}) is enabled again! + diff --git a/resources/views/livewire/layout-popups.blade.php b/resources/views/livewire/layout-popups.blade.php index c58ca4c31..23b9bfe64 100644 --- a/resources/views/livewire/layout-popups.blade.php +++ b/resources/views/livewire/layout-popups.blade.php @@ -12,8 +12,12 @@ class="underline text-warning">Please
@endif @if (currentTeam()->serverOverflow()) - -
WARNING: The number of active servers exceeds the limit covered by your payment. If not resolved, some of your servers will be deactivated in the next billing cycle. Visit /subscription to update your subscription.
-
+ +
WARNING: The number of active servers exceeds the limit + covered by your payment. If not resolved, some of your servers will + be deactivated. Visit /subscription to update your subscription or remove some servers. +
+
@endif diff --git a/resources/views/livewire/server/delete.blade.php b/resources/views/livewire/server/delete.blade.php index 050fb576e..efdf505b4 100644 --- a/resources/views/livewire/server/delete.blade.php +++ b/resources/views/livewire/server/delete.blade.php @@ -7,10 +7,10 @@ back! @if ($server->definedResources()->count() > 0) +
You need to delete all resources before deleting this server.
This server will be deleted. It is not reversible.
Please think again.
-
You need to delete all resources before deleting this server.
@else This server will be deleted. It is not reversible.
Please think again. diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 4e4e11845..687662b67 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -47,6 +47,10 @@ class="w-full mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-1 Validate Server @endif + @if ($server->isForceDisabled() && isCloud()) +
The system has disabled the server because you have exceeded the + number of servers for which you have paid.
+ @endif
diff --git a/resources/views/livewire/server/index.blade.php b/resources/views/livewire/server/index.blade.php index 8b6e12385..75812698a 100644 --- a/resources/views/livewire/server/index.blade.php +++ b/resources/views/livewire/server/index.blade.php @@ -1,18 +1,18 @@

Servers

- + + Add
All Servers
@forelse ($servers as $server) - $server->settings->is_reachable, - 'border-red-500' => !$server->settings->is_reachable, + 'border-transparent' => $server->settings->is_reachable && $server->settings->is_usable && !$server->settings->force_disabled, + 'border-red-500' => !$server->settings->is_reachable || $server->settings->force_disabled, ])>
@@ -30,6 +30,9 @@ @if (!$server->settings->is_usable) Not usable by Coolify @endif + @if ($server->settings->force_disabled) + Disabled by the system + @endif
diff --git a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php index c89c4274f..5bcfb9cbc 100644 --- a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php +++ b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php @@ -1,7 +1,7 @@
+
-
@if ($server->isFunctional())
@@ -48,7 +48,6 @@ class="font-normal text-white normal-case border-none rounded btn btn-primary bt
No dynamic configurations found.
@endif
- @endif
diff --git a/resources/views/livewire/server/proxy/show.blade.php b/resources/views/livewire/server/proxy/show.blade.php index 5d9523885..8668247d3 100644 --- a/resources/views/livewire/server/proxy/show.blade.php +++ b/resources/views/livewire/server/proxy/show.blade.php @@ -1,11 +1,13 @@
-
- -
- @if ($server->isFunctional()) + @if ($server->isFunctional()) +
+ +
- @endif +
-
+ @else +
Server is not validated. Validate first.
+ @endif
diff --git a/resources/views/livewire/subscription/actions.blade.php b/resources/views/livewire/subscription/actions.blade.php index fedbaf2cf..25897dae8 100644 --- a/resources/views/livewire/subscription/actions.blade.php +++ b/resources/views/livewire/subscription/actions.blade.php @@ -17,7 +17,7 @@ class="text-warning">{{ data_get(currentTeam(), 'subscription')->type() }}WARNING: You must delete {{ currentTeam()->servers->count() - $server_limits }} servers, or upgrade your subscription. {{ currentTeam()->servers->count() - $server_limits }} servers will be - deactivated in the next billing cycle.
+ deactivated.
@endif

Manage your subscription

Cancel, upgrade or downgrade your subscription.
diff --git a/routes/api.php b/routes/api.php index 4ef5500f8..004c62abf 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,8 +1,8 @@ update([ 'custom_server_limit' => $quantity, ]); - ServerOverflowJob::dispatch($team); + ServerLimitCheckJob::dispatch($team); } $subscription->update([ 'stripe_feedback' => $feedback,