From 55dd1ab0a13cee2692bf7eb4954bc3ddcbbbcbb8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 23 Feb 2024 14:39:52 +0100 Subject: [PATCH 01/17] Update cleanup script and version numbers --- app/Console/Commands/CleanupDatabase.php | 60 ++++++++++++++++++++++++ config/sentry.php | 2 +- config/version.php | 2 +- versions.json | 2 +- 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 app/Console/Commands/CleanupDatabase.php diff --git a/app/Console/Commands/CleanupDatabase.php b/app/Console/Commands/CleanupDatabase.php new file mode 100644 index 000000000..779b32218 --- /dev/null +++ b/app/Console/Commands/CleanupDatabase.php @@ -0,0 +1,60 @@ +where('failed_at', '<', now()->subDays(7)); + $count = $failed_jobs->count(); + echo "Delete $count entries from failed_jobs.\n"; + if ($this->option('yes')) { + $failed_jobs->delete(); + } + + // Cleanup sessions table + $sessions = DB::table('sessions')->where('last_activity', '<', now()->subDays($keep_days)->timestamp); + $count = $sessions->count(); + echo "Delete $count entries from sessions.\n"; + if ($this->option('yes')) { + $sessions->delete(); + } + + // Cleanup activity_log table + $activity_log = DB::table('activity_log')->where('created_at', '<', now()->subDays($keep_days)); + $count = $activity_log->count(); + echo "Delete $count entries from activity_log.\n"; + if ($this->option('yes')) { + $activity_log->delete(); + } + + // Cleanup application_deployment_queues table + $application_deployment_queues = DB::table('application_deployment_queues')->where('created_at', '<', now()->subDays($keep_days)); + $count = $application_deployment_queues->count(); + echo "Delete $count entries from application_deployment_queues.\n"; + if ($this->option('yes')) { + $application_deployment_queues->delete(); + } + + // Cleanup webhooks table + $webhooks = DB::table('webhooks')->where('created_at', '<', now()->subDays($keep_days)); + $count = $webhooks->count(); + echo "Delete $count entries from webhooks.\n"; + if ($this->option('yes')) { + $webhooks->delete(); + } + + } +} diff --git a/config/sentry.php b/config/sentry.php index 00c5f77de..40a4c9906 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) - 'release' => '4.0.0-beta.224', + 'release' => '4.0.0-beta.225', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index c4e13f9de..c3f92910d 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ Date: Fri, 23 Feb 2024 15:45:53 +0100 Subject: [PATCH 02/17] feat: custom server limit --- app/Livewire/Server/Create.php | 7 ++--- app/Livewire/Server/New/ByIp.php | 4 +++ app/Livewire/Subscription/Actions.php | 5 ++-- app/Models/Team.php | 25 ++++++++++++++--- ...custom_server_limits_to_teams_ultimate.php | 28 +++++++++++++++++++ .../views/components/limit-reached.blade.php | 2 +- 6 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 database/migrations/2024_02_23_143119_add_custom_server_limits_to_teams_ultimate.php diff --git a/app/Livewire/Server/Create.php b/app/Livewire/Server/Create.php index 147128457..2f30caf0e 100644 --- a/app/Livewire/Server/Create.php +++ b/app/Livewire/Server/Create.php @@ -3,6 +3,7 @@ namespace App\Livewire\Server; use App\Models\PrivateKey; +use App\Models\Team; use Livewire\Component; class Create extends Component @@ -16,11 +17,7 @@ class Create extends Component $this->limit_reached = false; return; } - $team = currentTeam(); - $servers = $team->servers->count(); - ['serverLimit' => $serverLimit] = $team->limits; - - $this->limit_reached = $servers >= $serverLimit; + $this->limit_reached = Team::serverLimitReached(); } public function render() { diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php index cd0166c54..9799443c7 100644 --- a/app/Livewire/Server/New/ByIp.php +++ b/app/Livewire/Server/New/ByIp.php @@ -5,6 +5,7 @@ namespace App\Livewire\Server\New; use App\Enums\ProxyStatus; use App\Enums\ProxyTypes; use App\Models\Server; +use App\Models\Team; use Livewire\Component; class ByIp extends Component @@ -76,6 +77,9 @@ class ByIp extends Component if (is_null($this->private_key_id)) { return $this->dispatch('error', 'You must select a private key'); } + if (Team::serverLimitReached()) { + return $this->dispatch('error', 'You have reached the server limit for your subscription.'); + } $payload = [ 'name' => $this->name, 'description' => $this->description, diff --git a/app/Livewire/Subscription/Actions.php b/app/Livewire/Subscription/Actions.php index 3050e38ab..90643e01a 100644 --- a/app/Livewire/Subscription/Actions.php +++ b/app/Livewire/Subscription/Actions.php @@ -2,6 +2,7 @@ namespace App\Livewire\Subscription; +use App\Models\Team; use Illuminate\Support\Facades\Http; use Livewire\Component; @@ -10,9 +11,7 @@ class Actions extends Component public $server_limits = 0; public function mount() { - $limits = currentTeam()->limits; - $this->server_limits = data_get($limits, 'serverLimit', 0); - + $this->server_limits = Team::serverLimit(); } public function cancel() { diff --git a/app/Models/Team.php b/app/Models/Team.php index 042f74789..17e5e9ac6 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -49,6 +49,16 @@ class Team extends Model implements SendsDiscord, SendsEmail return explode(',', $recipients); } + static public function serverLimitReached() { + $serverLimit = Team::serverLimit(); + $team = currentTeam(); + $servers = $team->servers->count(); + return $servers >= $serverLimit; + } + static public function serverLimit() + { + return data_get(Team::find(currentTeam()->id), 'limits.serverLimit', 0); + } public function limits(): Attribute { return Attribute::make( @@ -63,14 +73,19 @@ class Team extends Model implements SendsDiscord, SendsEmail $subscription = $subscription->type(); } } - $serverLimit = config('constants.limits.server')[strtolower($subscription)]; + if ($this->custom_server_limit) { + $serverLimit = $this->custom_server_limit; + } else { + $serverLimit = config('constants.limits.server')[strtolower($subscription)]; + } $sharedEmailEnabled = config('constants.limits.email')[strtolower($subscription)]; return ['serverLimit' => $serverLimit, 'sharedEmailEnabled' => $sharedEmailEnabled]; } ); } - public function environment_variables() { + public function environment_variables() + { return $this->hasMany(SharedEnvironmentVariable::class)->whereNull('project_id')->whereNull('environment_id'); } public function members() @@ -130,7 +145,8 @@ class Team extends Model implements SendsDiscord, SendsEmail { return $this->hasMany(S3Storage::class)->where('is_usable', true); } - public function trialEnded() { + public function trialEnded() + { foreach ($this->servers as $server) { $server->settings()->update([ 'is_usable' => false, @@ -138,7 +154,8 @@ class Team extends Model implements SendsDiscord, SendsEmail ]); } } - public function trialEndedButSubscribed() { + public function trialEndedButSubscribed() + { foreach ($this->servers as $server) { $server->settings()->update([ 'is_usable' => true, diff --git a/database/migrations/2024_02_23_143119_add_custom_server_limits_to_teams_ultimate.php b/database/migrations/2024_02_23_143119_add_custom_server_limits_to_teams_ultimate.php new file mode 100644 index 000000000..7e1fe67f5 --- /dev/null +++ b/database/migrations/2024_02_23_143119_add_custom_server_limits_to_teams_ultimate.php @@ -0,0 +1,28 @@ +integer('custom_server_limit')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('teams', function (Blueprint $table) { + $table->dropColumn('custom_server_limit'); + }); + } +}; diff --git a/resources/views/components/limit-reached.blade.php b/resources/views/components/limit-reached.blade.php index f5477cff2..4d44b4328 100644 --- a/resources/views/components/limit-reached.blade.php +++ b/resources/views/components/limit-reached.blade.php @@ -1,6 +1,6 @@
You have reached the limit of {{ $name }} you can create. - Please upgrade your + Please upgrade your subscription to create more {{ $name }}.
From b8b76dfa40bccdcfbfe7d19f1048212ef63b618c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 23 Feb 2024 21:05:48 +0100 Subject: [PATCH 03/17] Refactor CleanupQueue to CleanupDatabase --- app/Console/Commands/CleanupDatabase.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Console/Commands/CleanupDatabase.php b/app/Console/Commands/CleanupDatabase.php index 779b32218..60e6ea901 100644 --- a/app/Console/Commands/CleanupDatabase.php +++ b/app/Console/Commands/CleanupDatabase.php @@ -4,9 +4,8 @@ namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Facades\Redis; -class CleanupQueue extends Command +class CleanupDatabase extends Command { protected $signature = 'cleanup:database {--yes}'; protected $description = 'Cleanup database'; From 61dbc81765a0e6a884e4161690626ee76cd86dc9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 23 Feb 2024 21:51:43 +0100 Subject: [PATCH 04/17] feat: delay container/server jobs --- .../Commands/CleanupUnreachableServers.php | 5 ++-- app/Console/Kernel.php | 28 +++++++++++++++++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/app/Console/Commands/CleanupUnreachableServers.php b/app/Console/Commands/CleanupUnreachableServers.php index 8bbd27d64..b63dc1d36 100644 --- a/app/Console/Commands/CleanupUnreachableServers.php +++ b/app/Console/Commands/CleanupUnreachableServers.php @@ -8,15 +8,16 @@ use Illuminate\Console\Command; class CleanupUnreachableServers extends Command { protected $signature = 'cleanup:unreachable-servers'; - protected $description = 'Cleanup Unreachable Servers (3 days)'; + protected $description = 'Cleanup Unreachable Servers (7 days)'; public function handle() { echo "Running unreachable server cleanup...\n"; - $servers = Server::where('unreachable_count', 3)->where('unreachable_notification_sent', true)->where('updated_at', '<', now()->subDays(3))->get(); + $servers = Server::where('unreachable_count', 3)->where('unreachable_notification_sent', true)->where('updated_at', '<', now()->subDays(7))->get(); if ($servers->count() > 0) { foreach ($servers as $server) { echo "Cleanup unreachable server ($server->id) with name $server->name"; + send_internal_notification("Server $server->name is unreachable for 7 days. Cleaning up..."); $server->update([ 'ip' => '1.2.3.4' ]); diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 76fcbfc1f..636df5d36 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -68,13 +68,35 @@ class Kernel extends ConsoleKernel $containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false); } foreach ($containerServers as $server) { - $schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer(); + // $schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer(); + $schedule + ->call(function () use ($server) { + $randomSeconds = rand(1, 40); + $job = new ContainerStatusJob($server); + $job->delay($randomSeconds); + ray('dispatching container status job in ' . $randomSeconds . ' seconds'); + dispatch($job); + })->name('container-status-' . $server->id)->everyMinute()->onOneServer(); if ($server->isLogDrainEnabled()) { - $schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer(); + $schedule + ->call(function () use ($server) { + $randomSeconds = rand(1, 40); + $job = new CheckLogDrainContainerJob($server); + $job->delay($randomSeconds); + dispatch($job); + })->name('log-drain-container-check-' . $server->id)->everyMinute()->onOneServer(); + // $schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer(); } } foreach ($servers as $server) { - $schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer(); + $schedule + ->call(function () use ($server) { + $randomSeconds = rand(1, 40); + $job = new ServerStatusJob($server); + $job->delay($randomSeconds); + dispatch($job); + })->name('server-status-job-' . $server->id)->everyMinute()->onOneServer(); + // $schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer(); } } private function instance_auto_update($schedule) From 1fcbf0b363d11ab32afa328f55cbbfef629b27c9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 23 Feb 2024 22:14:24 +0100 Subject: [PATCH 05/17] Update pricing plans display and button text --- resources/views/components/pricing-plans.blade.php | 14 +++++++------- .../livewire/subscription/pricing-plans.blade.php | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/views/components/pricing-plans.blade.php b/resources/views/components/pricing-plans.blade.php index 32e004c4f..fbc348197 100644 --- a/resources/views/components/pricing-plans.blade.php +++ b/resources/views/components/pricing-plans.blade.php @@ -188,22 +188,22 @@

Ultimate

-

+

- $? - /month + VAT + Custom + {{-- /month + VAT --}} - $? - /month + VAT + Custom + {{-- /month + VAT --}}

- + {{-- billed monthly billed annually - + --}} @if ($showSubscribeButtons) @isset($ultimate) {{ $ultimate }} diff --git a/resources/views/livewire/subscription/pricing-plans.blade.php b/resources/views/livewire/subscription/pricing-plans.blade.php index 37a8abe2b..bb7001119 100644 --- a/resources/views/livewire/subscription/pricing-plans.blade.php +++ b/resources/views/livewire/subscription/pricing-plans.blade.php @@ -25,13 +25,13 @@ - Contact Us + Contact us - Contact Us + Contact us @endif From 1b055f03165b7d14315571b4cbaa6902d3d68092 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 25 Feb 2024 14:00:35 +0100 Subject: [PATCH 06/17] Refactor subscription pricing and update server limit --- app/Livewire/Subscription/PricingPlans.php | 38 +++++++++++-------- .../subscription/pricing-plans.blade.php | 13 +++---- routes/webhooks.php | 8 ++++ 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/app/Livewire/Subscription/PricingPlans.php b/app/Livewire/Subscription/PricingPlans.php index a3afcaabc..3996d70d5 100644 --- a/app/Livewire/Subscription/PricingPlans.php +++ b/app/Livewire/Subscription/PricingPlans.php @@ -9,8 +9,9 @@ use Stripe\Checkout\Session; class PricingPlans extends Component { public bool $isTrial = false; - public function mount() { - $this->isTrial = !data_get(currentTeam(),'subscription.stripe_trial_already_ended'); + public function mount() + { + $this->isTrial = !data_get(currentTeam(), 'subscription.stripe_trial_already_ended'); if (config('constants.limits.trial_period') == 0) { $this->isTrial = false; } @@ -26,15 +27,15 @@ class PricingPlans extends Component case 'basic-yearly': $priceId = config('subscription.stripe_price_id_basic_yearly'); break; - case 'ultimate-monthly': - $priceId = config('subscription.stripe_price_id_ultimate_monthly'); - break; case 'pro-monthly': $priceId = config('subscription.stripe_price_id_pro_monthly'); break; case 'pro-yearly': $priceId = config('subscription.stripe_price_id_pro_yearly'); break; + case 'ultimate-monthly': + $priceId = config('subscription.stripe_price_id_ultimate_monthly'); + break; case 'ultimate-yearly': $priceId = config('subscription.stripe_price_id_ultimate_yearly'); break; @@ -64,18 +65,25 @@ class PricingPlans extends Component 'success_url' => route('dashboard', ['success' => true]), 'cancel_url' => route('subscription.index', ['cancelled' => true]), ]; - - if (!data_get($team,'subscription.stripe_trial_already_ended')) { - if (config('constants.limits.trial_period') > 0) { - $payload['subscription_data'] = [ - 'trial_period_days' => config('constants.limits.trial_period'), - 'trial_settings' => [ - 'end_behavior' => [ - 'missing_payment_method' => 'cancel', - ] - ], + if (str($type)->contains('ultimate')) { + $payload['line_items'][0]['adjustable_quantity'] = [ + 'enabled' => true, + 'minimum' => 10, ]; + $payload['line_items'][0]['quantity'] = 10; } + + if (!data_get($team, 'subscription.stripe_trial_already_ended')) { + if (config('constants.limits.trial_period') > 0) { + $payload['subscription_data'] = [ + 'trial_period_days' => config('constants.limits.trial_period'), + 'trial_settings' => [ + 'end_behavior' => [ + 'missing_payment_method' => 'cancel', + ] + ], + ]; + } $payload['payment_method_collection'] = 'if_required'; } $customer = currentTeam()->subscription?->stripe_customer_id ?? null; diff --git a/resources/views/livewire/subscription/pricing-plans.blade.php b/resources/views/livewire/subscription/pricing-plans.blade.php index bb7001119..e4a3cc762 100644 --- a/resources/views/livewire/subscription/pricing-plans.blade.php +++ b/resources/views/livewire/subscription/pricing-plans.blade.php @@ -22,16 +22,13 @@ - - Contact us + + {{ $isTrial ? 'Start Trial' : 'Subscribe' }} - - Contact us + {{ $isTrial ? 'Start Trial' : 'Subscribe' }} @endif diff --git a/routes/webhooks.php b/routes/webhooks.php index e4e9c043b..03bbfd999 100644 --- a/routes/webhooks.php +++ b/routes/webhooks.php @@ -875,6 +875,14 @@ Route::post('/payments/stripe/events', function () { $alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_cancel_at_period_end'); $feedback = data_get($data, 'cancellation_details.feedback'); $comment = data_get($data, 'cancellation_details.comment'); + $lookup_key = data_get($data, 'items.data.0.price.lookup_key'); + if (str($lookup_key)->contains('ultimate')) { + $quantity = data_get($data, 'items.data.0.quantity', 10); + $team = data_get($subscription, 'team'); + $team->update([ + 'custom_server_limit' => $quantity, + ]); + } $subscription->update([ 'stripe_feedback' => $feedback, 'stripe_comment' => $comment, From c3cfb8d23bd88348e238dc10db3e28c6cdd3abd3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 25 Feb 2024 18:22:24 +0100 Subject: [PATCH 07/17] Refactor getRecepients method and fix serverLimitReached method in Team model --- app/Models/Team.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Models/Team.php b/app/Models/Team.php index 17e5e9ac6..8617bfffd 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -48,7 +48,6 @@ class Team extends Model implements SendsDiscord, SendsEmail } return explode(',', $recipients); } - static public function serverLimitReached() { $serverLimit = Team::serverLimit(); $team = currentTeam(); @@ -57,7 +56,7 @@ class Team extends Model implements SendsDiscord, SendsEmail } static public function serverLimit() { - return data_get(Team::find(currentTeam()->id), 'limits.serverLimit', 0); + return Team::find(currentTeam()->id)->limits['serverLimit']; } public function limits(): Attribute { From c8c7a415eadcd329e2e5d18800c127880c670ec7 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 25 Feb 2024 22:08:44 +0100 Subject: [PATCH 08/17] Add new Livewire component and update subscription actions --- .../{Sponsorship.php => LayoutPopups.php} | 4 ++-- app/Livewire/Subscription/Actions.php | 1 + app/Models/Team.php | 6 +++++ resources/views/components/banner.blade.php | 22 +++++++++++++++++++ resources/views/layouts/app.blade.php | 2 +- ...ship.blade.php => layout-popups.blade.php} | 5 +++++ .../livewire/subscription/actions.blade.php | 19 +++++++++++----- 7 files changed, 50 insertions(+), 9 deletions(-) rename app/Livewire/{Sponsorship.php => LayoutPopups.php} (86%) create mode 100644 resources/views/components/banner.blade.php rename resources/views/livewire/{sponsorship.blade.php => layout-popups.blade.php} (58%) diff --git a/app/Livewire/Sponsorship.php b/app/Livewire/LayoutPopups.php similarity index 86% rename from app/Livewire/Sponsorship.php rename to app/Livewire/LayoutPopups.php index c4dedffc0..dd7f14678 100644 --- a/app/Livewire/Sponsorship.php +++ b/app/Livewire/LayoutPopups.php @@ -4,7 +4,7 @@ namespace App\Livewire; use Livewire\Component; -class Sponsorship extends Component +class LayoutPopups extends Component { public function getListeners() { @@ -23,6 +23,6 @@ class Sponsorship extends Component } public function render() { - return view('livewire.sponsorship'); + return view('livewire.layout-popups'); } } diff --git a/app/Livewire/Subscription/Actions.php b/app/Livewire/Subscription/Actions.php index 90643e01a..a6a201f3b 100644 --- a/app/Livewire/Subscription/Actions.php +++ b/app/Livewire/Subscription/Actions.php @@ -9,6 +9,7 @@ use Livewire\Component; class Actions extends Component { public $server_limits = 0; + public function mount() { $this->server_limits = Team::serverLimit(); diff --git a/app/Models/Team.php b/app/Models/Team.php index 8617bfffd..7858dde49 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -54,6 +54,12 @@ class Team extends Model implements SendsDiscord, SendsEmail $servers = $team->servers->count(); return $servers >= $serverLimit; } + public function serverOverflow() { + if ($this->serverLimit() < $this->servers->count()) { + return true; + } + return false; + } static public function serverLimit() { return Team::find(currentTeam()->id)->limits['serverLimit']; diff --git a/resources/views/components/banner.blade.php b/resources/views/components/banner.blade.php new file mode 100644 index 000000000..d75a6d75e --- /dev/null +++ b/resources/views/components/banner.blade.php @@ -0,0 +1,22 @@ +@props(['closable' => true]) +
+
+ {{ $slot }} + @if ($closable) + + @endif +
+
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index a5fd6d0e6..7d74f7acb 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -7,7 +7,7 @@
@endpersist - + @auth @endauth diff --git a/resources/views/livewire/sponsorship.blade.php b/resources/views/livewire/layout-popups.blade.php similarity index 58% rename from resources/views/livewire/sponsorship.blade.php rename to resources/views/livewire/layout-popups.blade.php index 28cb96ac4..c58ca4c31 100644 --- a/resources/views/livewire/sponsorship.blade.php +++ b/resources/views/livewire/layout-popups.blade.php @@ -11,4 +11,9 @@ @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.
+
+ @endif diff --git a/resources/views/livewire/subscription/actions.blade.php b/resources/views/livewire/subscription/actions.blade.php index acfd7179e..fedbaf2cf 100644 --- a/resources/views/livewire/subscription/actions.blade.php +++ b/resources/views/livewire/subscription/actions.blade.php @@ -1,7 +1,8 @@
@if (subscriptionProvider() === 'stripe')
-
Your current Plan is: Your current plan +
Tier: {{ data_get(currentTeam(), 'subscription')->type() }}
@if (currentTeam()->subscription->stripe_cancel_at_period_end) @@ -10,13 +11,19 @@
Subscription is active. Last invoice is {{ currentTeam()->subscription->stripe_invoice_paid ? 'paid' : 'not paid' }}.
@endif -

Limits

-
Server: {{ $server_limits }}
-

Actions

+
Number of paid servers: {{ $server_limits }}
+
Currently active servers: {{ currentTeam()->servers->count() }}
+ @if (currentTeam()->serverOverflow()) +
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.
+ @endif +

Manage your subscription

Cancel, upgrade or downgrade your subscription.
- Manage your subscription on + Go to From 5e980c5fe0c9fbdf0eec24a8febf9f54fbec5841 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 25 Feb 2024 22:14:20 +0100 Subject: [PATCH 09/17] Update pricing plans layout and text --- resources/views/components/pricing-plans.blade.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/resources/views/components/pricing-plans.blade.php b/resources/views/components/pricing-plans.blade.php index fbc348197..e6ea81342 100644 --- a/resources/views/components/pricing-plans.blade.php +++ b/resources/views/components/pricing-plans.blade.php @@ -188,22 +188,22 @@

Ultimate

-

+

Custom - {{-- /month + VAT --}} + {{-- pay-as-you-go --}} Custom {{-- /month + VAT --}}

- {{-- - billed monthly + + pay-as-you-go - billed annually - --}} + pay-as-you-go + @if ($showSubscribeButtons) @isset($ultimate) {{ $ultimate }} @@ -219,7 +219,7 @@ d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" /> - Connect unlimited servers + Connect 10+ servers
  • From c7da43f50d5d673c84684534dd783465db2cb38e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 25 Feb 2024 23:13:27 +0100 Subject: [PATCH 10/17] feat: add static ipv4 ipv6 support --- app/Console/Kernel.php | 28 +++++++++++++-------------- app/Jobs/ApplicationDeploymentJob.php | 26 +++++++++++++++++++++++++ app/Jobs/ContainerStatusJob.php | 8 ++++---- bootstrap/helpers/docker.php | 3 ++- tests/Feature/DockerRunTest.php | 9 +++++++++ 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 636df5d36..c67f98cf7 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -78,25 +78,25 @@ class Kernel extends ConsoleKernel dispatch($job); })->name('container-status-' . $server->id)->everyMinute()->onOneServer(); if ($server->isLogDrainEnabled()) { - $schedule - ->call(function () use ($server) { - $randomSeconds = rand(1, 40); - $job = new CheckLogDrainContainerJob($server); - $job->delay($randomSeconds); - dispatch($job); - })->name('log-drain-container-check-' . $server->id)->everyMinute()->onOneServer(); // $schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer(); + $schedule + ->call(function () use ($server) { + $randomSeconds = rand(1, 40); + $job = new CheckLogDrainContainerJob($server); + $job->delay($randomSeconds); + dispatch($job); + })->name('log-drain-container-check-' . $server->id)->everyMinute()->onOneServer(); } } foreach ($servers as $server) { - $schedule - ->call(function () use ($server) { - $randomSeconds = rand(1, 40); - $job = new ServerStatusJob($server); - $job->delay($randomSeconds); - dispatch($job); - })->name('server-status-job-' . $server->id)->everyMinute()->onOneServer(); // $schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer(); + $schedule + ->call(function () use ($server) { + $randomSeconds = rand(1, 40); + $job = new ServerStatusJob($server); + $job->delay($randomSeconds); + dispatch($job); + })->name('server-status-job-' . $server->id)->everyMinute()->onOneServer(); } } private function instance_auto_update($schedule) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index f3e8c4129..61cda4fc6 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1223,6 +1223,19 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if ((bool)$this->application->settings->is_consistent_container_name_enabled) { $custom_compose = convert_docker_run_to_compose($this->application->custom_docker_run_options); if (count($custom_compose) > 0) { + $ipv4 = data_get($custom_compose, 'ip.0'); + $ipv6 = data_get($custom_compose, 'ip6.0'); + data_forget($custom_compose, 'ip'); + data_forget($custom_compose, 'ip6'); + if ($ipv4 || $ipv6) { + data_forget($docker_compose['services'][$this->application->uuid], 'networks'); + } + if ($ipv4) { + $docker_compose['services'][$this->application->uuid]['networks'][$this->destination->network]['ipv4_address'] = $ipv4; + } + if ($ipv6) { + $docker_compose['services'][$this->application->uuid]['networks'][$this->destination->network]['ipv6_address'] = $ipv6; + } $docker_compose['services'][$this->container_name] = array_merge_recursive($docker_compose['services'][$this->container_name], $custom_compose); } } else { @@ -1230,6 +1243,19 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted data_forget($docker_compose, 'services.' . $this->container_name); $custom_compose = convert_docker_run_to_compose($this->application->custom_docker_run_options); if (count($custom_compose) > 0) { + $ipv4 = data_get($custom_compose, 'ip.0'); + $ipv6 = data_get($custom_compose, 'ip6.0'); + data_forget($custom_compose, 'ip'); + data_forget($custom_compose, 'ip6'); + if ($ipv4 || $ipv6) { + data_forget($docker_compose['services'][$this->application->uuid], 'networks'); + } + if ($ipv4) { + $docker_compose['services'][$this->application->uuid]['networks'][$this->destination->network]['ipv4_address'] = $ipv4; + } + if ($ipv6) { + $docker_compose['services'][$this->application->uuid]['networks'][$this->destination->network]['ipv6_address'] = $ipv6; + } $docker_compose['services'][$this->application->uuid] = array_merge_recursive($docker_compose['services'][$this->application->uuid], $custom_compose); } } diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index fbdd555a1..68035a258 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -43,6 +43,10 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted public function handle() { + if (!$this->server->isFunctional()) { + return 'Server is not ready.'; + }; + $applications = $this->server->applications(); $skip_these_applications = collect([]); foreach ($applications as $application) { @@ -57,10 +61,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted $applications = $applications->filter(function ($value, $key) use ($skip_these_applications) { return !$skip_these_applications->pluck('id')->contains($value->id); }); - - if (!$this->server->isFunctional()) { - return 'Server is not ready.'; - }; try { if ($this->server->isSwarm()) { $containers = instant_remote_process(["docker service inspect $(docker service ls -q) --format '{{json .}}'"], $this->server, false); diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 370c05930..6a3e3f839 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -423,7 +423,7 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null '--security-opt', '--sysctl', '--ulimit', - '--device' + '--device', ]); $mapping = collect([ '--cap-add' => 'cap_add', @@ -435,6 +435,7 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null '--init' => 'init', '--ulimit' => 'ulimits', '--privileged' => 'privileged', + '--ip' => 'ip', ]); foreach ($matches as $match) { $option = $match[1]; diff --git a/tests/Feature/DockerRunTest.php b/tests/Feature/DockerRunTest.php index 27816bf5d..2fee5d8e5 100644 --- a/tests/Feature/DockerRunTest.php +++ b/tests/Feature/DockerRunTest.php @@ -8,6 +8,15 @@ test('ConvertCapAdd', function () { ])->ray(); }); +test('ConvertIp', function () { + $input = '--cap-add=NET_ADMIN --cap-add=NET_RAW --cap-add SYS_ADMIN --ip 127.0.0.1 --ip 127.0.0.2'; + $output = convert_docker_run_to_compose($input); + expect($output)->toBe([ + 'cap_add' => ['NET_ADMIN', 'NET_RAW', 'SYS_ADMIN'], + 'ip' => ['127.0.0.1', '127.0.0.2'] + ])->ray(); +}); + test('ConvertPrivilegedAndInit', function () { $input = '---privileged --init'; $output = convert_docker_run_to_compose($input); From 64fca99c269991c80b612a8c1d9fa2c66e1bc969 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 25 Feb 2024 23:34:01 +0100 Subject: [PATCH 11/17] feat: server disabled by overflow --- app/Jobs/ServerOverflowJob.php | 62 ++++++++++++++++++ app/Models/Server.php | 5 ++ .../Server/DisabledDueToOverflow.php | 63 +++++++++++++++++++ ...50_add_disabled_server_due_to_overflow.php | 28 +++++++++ .../server-disabled-due-to-overflow.blade.php | 5 ++ routes/webhooks.php | 2 + 6 files changed, 165 insertions(+) create mode 100644 app/Jobs/ServerOverflowJob.php create mode 100644 app/Notifications/Server/DisabledDueToOverflow.php create mode 100644 database/migrations/2024_02_25_222150_add_disabled_server_due_to_overflow.php create mode 100644 resources/views/emails/server-disabled-due-to-overflow.blade.php diff --git a/app/Jobs/ServerOverflowJob.php b/app/Jobs/ServerOverflowJob.php new file mode 100644 index 000000000..af7b7a927 --- /dev/null +++ b/app/Jobs/ServerOverflowJob.php @@ -0,0 +1,62 @@ +team->uuid))]; + } + + public function uniqueId(): int + { + return $this->team->uuid; + } + + 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); + if ($number_of_servers_to_disable > 0) { + ray('Disabling servers'); + $servers = $servers->sortBy('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)); + }); + } + } catch (\Throwable $e) { + send_internal_notification('ServerOverflowJob failed with: ' . $e->getMessage()); + ray($e->getMessage()); + return handleError($e); + } + } + +} diff --git a/app/Models/Server.php b/app/Models/Server.php index 016efd5f7..4272761a5 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -151,6 +151,11 @@ class Server extends BaseModel } return false; } + public function disableServerDueToOverflow() { + $this->settings->update([ + 'disabled_by_overflow' => true, + ]); + } public function isServerReady(int $tries = 3) { if ($this->skipServer()) { diff --git a/app/Notifications/Server/DisabledDueToOverflow.php b/app/Notifications/Server/DisabledDueToOverflow.php new file mode 100644 index 000000000..957d9c866 --- /dev/null +++ b/app/Notifications/Server/DisabledDueToOverflow.php @@ -0,0 +1,63 @@ +subject("Coolify: Server ({$this->server->name}) disabled because it is not paid!"); + $mail->view('emails.server-disabled-due-to-overflow', [ + 'name' => $this->server->name, + ]); + return $mail; + } + + public function toDiscord(): string + { + $message = "Coolify: Server ({$this->server->name}) disabled because it is not paid!\n All automations and integrations are stopped.\nPlease update your subscription to enable the server again [here](https://app.coolify.io/subsciprtions)."; + return $message; + } + public function toTelegram(): array + { + return [ + "message" => "Coolify: Server ({$this->server->name}) disabled because it is not paid!\n All automations and integrations are stopped.\nPlease update your subscription to enable the server again [here](https://app.coolify.io/subsciprtions)." + ]; + } +} diff --git a/database/migrations/2024_02_25_222150_add_disabled_server_due_to_overflow.php b/database/migrations/2024_02_25_222150_add_disabled_server_due_to_overflow.php new file mode 100644 index 000000000..3d1b808ab --- /dev/null +++ b/database/migrations/2024_02_25_222150_add_disabled_server_due_to_overflow.php @@ -0,0 +1,28 @@ +boolean('disabled_by_overflow')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('server_settings', function (Blueprint $table) { + $table->dropColumn('disabled_by_overflow'); + }); + } +}; diff --git a/resources/views/emails/server-disabled-due-to-overflow.blade.php b/resources/views/emails/server-disabled-due-to-overflow.blade.php new file mode 100644 index 000000000..7cc43c354 --- /dev/null +++ b/resources/views/emails/server-disabled-due-to-overflow.blade.php @@ -0,0 +1,5 @@ + +Your server ({{ $name }}) disabled because it is not paid! All automations and integrations are stopped. + +Please update your subscription to enable the server again [here](https://app.coolify.io/subsciprtions). + diff --git a/routes/webhooks.php b/routes/webhooks.php index 03bbfd999..e8fc64713 100644 --- a/routes/webhooks.php +++ b/routes/webhooks.php @@ -3,6 +3,7 @@ use App\Enums\ProcessStatus; use App\Jobs\ApplicationPullRequestUpdateJob; use App\Jobs\GithubAppPermissionJob; +use App\Jobs\ServerOverflowJob; use App\Jobs\SubscriptionInvoiceFailedJob; use App\Jobs\SubscriptionTrialEndedJob; use App\Jobs\SubscriptionTrialEndsSoonJob; @@ -882,6 +883,7 @@ Route::post('/payments/stripe/events', function () { $team->update([ 'custom_server_limit' => $quantity, ]); + ServerOverflowJob::dispatch($team); } $subscription->update([ 'stripe_feedback' => $feedback, From 964245305206c8803d6ee2d86d525cb87a305b78 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 26 Feb 2024 08:52:17 +0100 Subject: [PATCH 12/17] fix: firefly service --- templates/compose/firefly.yaml | 23 ++++++++++++++++++----- templates/service-templates.json | 2 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/templates/compose/firefly.yaml b/templates/compose/firefly.yaml index 49dc0d9cf..4526fa249 100644 --- a/templates/compose/firefly.yaml +++ b/templates/compose/firefly.yaml @@ -16,6 +16,7 @@ services: - DB_USERNAME=$SERVICE_USER_MYSQL - DB_PASSWORD=$SERVICE_PASSWORD_MYSQL - STATIC_CRON_TOKEN=$SERVICE_BASE64_CRONTOKEN + - TRUSTED_PROXIES=* volumes: - firefly-upload:/var/www/html/storage/upload healthcheck: @@ -49,8 +50,20 @@ services: retries: 10 volumes: - firefly-mysql-data:/var/lib/mysql - # cron: - # image: alpine - # command: sh -c "echo \"0 3 * * * wget -qO- http://app:8080/api/v1/cron/$STATIC_CRON_TOKEN\" | crontab - && crond -f -L /dev/stdout" - # environment: - # - STATIC_CRON_TOKEN=$SERVICE_PASSWORD_32_CRONTOKEN + cron: + image: alpine + entrypoint: ["/entrypoint.sh"] + volumes: + - type: bind + source: ./entrypoint.sh + target: /entrypoint.sh + content: | + #!/bin/sh + # Substitute the environment variable into the cron command + CRON_COMMAND="0 3 * * * wget -qO- http://firefly:8080/api/v1/cron/${STATIC_CRON_TOKEN}" + # Add the cron command to the crontab + echo "$CRON_COMMAND" | crontab - + # Start the cron daemon in the foreground with logging to stdout + crond -f -L /dev/stdout + environment: + - STATIC_CRON_TOKEN=$SERVICE_BASE64_CRONTOKEN diff --git a/templates/service-templates.json b/templates/service-templates.json index 50b53a7f1..2d94904f7 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -195,7 +195,7 @@ "firefly": { "documentation": "https:\/\/firefly-iii.org", "slogan": "A personal finances manager that can help you save money.", - "compose": "c2VydmljZXM6CiAgZmlyZWZseToKICAgIGltYWdlOiAnZmlyZWZseWlpaS9jb3JlOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GSVJFRkxZCiAgICAgIC0gQVBQX0tFWT0kU0VSVklDRV9CQVNFNjRfQVBQS0VZCiAgICAgIC0gREJfSE9TVD1teXNxbAogICAgICAtIERCX1BPUlQ9MzMwNgogICAgICAtIERCX0NPTk5FQ1RJT049bXlzcWwKICAgICAgLSAnREJfREFUQUJBU0U9JHtNWVNRTF9EQVRBQkFTRTotZmlyZWZseX0nCiAgICAgIC0gREJfVVNFUk5BTUU9JFNFUlZJQ0VfVVNFUl9NWVNRTAogICAgICAtIERCX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX01ZU1FMCiAgICAgIC0gU1RBVElDX0NST05fVE9LRU49JFNFUlZJQ0VfQkFTRTY0X0NST05UT0tFTgogICAgdm9sdW1lczoKICAgICAgLSAnZmlyZWZseS11cGxvYWQ6L3Zhci93d3cvaHRtbC9zdG9yYWdlL3VwbG9hZCcKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo4MDgwJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICBkZXBlbmRzX29uOgogICAgICBteXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogIG15c3FsOgogICAgaW1hZ2U6ICdtYXJpYWRiOmx0cycKICAgIGVudmlyb25tZW50OgogICAgICAtICdNWVNRTF9VU0VSPSR7U0VSVklDRV9VU0VSX01ZU1FMfScKICAgICAgLSAnTVlTUUxfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMfScKICAgICAgLSAnTVlTUUxfREFUQUJBU0U9JHtNWVNRTF9EQVRBQkFTRTotZmlyZWZseX0nCiAgICAgIC0gJ01ZU1FMX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMUk9PVH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gbXlzcWxhZG1pbgogICAgICAgIC0gcGluZwogICAgICAgIC0gJy1oJwogICAgICAgIC0gbG9jYWxob3N0CiAgICAgICAgLSAnLXVyb290JwogICAgICAgIC0gJy1wJHtTRVJWSUNFX1BBU1NXT1JEX01ZU1FMUk9PVH0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2ZpcmVmbHktbXlzcWwtZGF0YTovdmFyL2xpYi9teXNxbCcK", + "compose": "c2VydmljZXM6CiAgZmlyZWZseToKICAgIGltYWdlOiAnZmlyZWZseWlpaS9jb3JlOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9GSVJFRkxZCiAgICAgIC0gQVBQX0tFWT0kU0VSVklDRV9CQVNFNjRfQVBQS0VZCiAgICAgIC0gREJfSE9TVD1teXNxbAogICAgICAtIERCX1BPUlQ9MzMwNgogICAgICAtIERCX0NPTk5FQ1RJT049bXlzcWwKICAgICAgLSAnREJfREFUQUJBU0U9JHtNWVNRTF9EQVRBQkFTRTotZmlyZWZseX0nCiAgICAgIC0gREJfVVNFUk5BTUU9JFNFUlZJQ0VfVVNFUl9NWVNRTAogICAgICAtIERCX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX01ZU1FMCiAgICAgIC0gU1RBVElDX0NST05fVE9LRU49JFNFUlZJQ0VfQkFTRTY0X0NST05UT0tFTgogICAgICAtICdUUlVTVEVEX1BST1hJRVM9KicKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2ZpcmVmbHktdXBsb2FkOi92YXIvd3d3L2h0bWwvc3RvcmFnZS91cGxvYWQnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgbXlzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICBteXNxbDoKICAgIGltYWdlOiAnbWFyaWFkYjpsdHMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnTVlTUUxfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NWVNRTH0nCiAgICAgIC0gJ01ZU1FMX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NWVNRTH0nCiAgICAgIC0gJ01ZU1FMX0RBVEFCQVNFPSR7TVlTUUxfREFUQUJBU0U6LWZpcmVmbHl9JwogICAgICAtICdNWVNRTF9ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NWVNRTFJPT1R9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIG15c3FsYWRtaW4KICAgICAgICAtIHBpbmcKICAgICAgICAtICctaCcKICAgICAgICAtIGxvY2FsaG9zdAogICAgICAgIC0gJy11cm9vdCcKICAgICAgICAtICctcCR7U0VSVklDRV9QQVNTV09SRF9NWVNRTFJPT1R9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICdmaXJlZmx5LW15c3FsLWRhdGE6L3Zhci9saWIvbXlzcWwnCiAgY3JvbjoKICAgIGltYWdlOiBhbHBpbmUKICAgIGVudHJ5cG9pbnQ6CiAgICAgIC0gL2VudHJ5cG9pbnQuc2gKICAgIHZvbHVtZXM6CiAgICAgIC0KICAgICAgICB0eXBlOiBiaW5kCiAgICAgICAgc291cmNlOiAuL2VudHJ5cG9pbnQuc2gKICAgICAgICB0YXJnZXQ6IC9lbnRyeXBvaW50LnNoCiAgICAgICAgY29udGVudDogIiMhL2Jpbi9zaFxuIyBTdWJzdGl0dXRlIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZSBpbnRvIHRoZSBjcm9uIGNvbW1hbmRcbkNST05fQ09NTUFORD1cIjAgMyAqICogKiB3Z2V0IC1xTy0gaHR0cDovL2ZpcmVmbHk6ODA4MC9hcGkvdjEvY3Jvbi8ke1NUQVRJQ19DUk9OX1RPS0VOfVwiXG4jIEFkZCB0aGUgY3JvbiBjb21tYW5kIHRvIHRoZSBjcm9udGFiXG5lY2hvIFwiJENST05fQ09NTUFORFwiIHwgY3JvbnRhYiAtXG4jIFN0YXJ0IHRoZSBjcm9uIGRhZW1vbiBpbiB0aGUgZm9yZWdyb3VuZCB3aXRoIGxvZ2dpbmcgdG8gc3Rkb3V0XG5jcm9uZCAtZiAtTCAvZGV2L3N0ZG91dCIKICAgIGVudmlyb25tZW50OgogICAgICAtIFNUQVRJQ19DUk9OX1RPS0VOPSRTRVJWSUNFX0JBU0U2NF9DUk9OVE9LRU4K", "tags": [ "finance", "money", From f6b886adbc3d5486afe567a6ca6e6cd8b2125ab6 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 26 Feb 2024 08:52:46 +0100 Subject: [PATCH 13/17] revert delayed jobs for now --- app/Console/Kernel.php | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index c67f98cf7..e92c602cf 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -68,35 +68,35 @@ class Kernel extends ConsoleKernel $containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false); } foreach ($containerServers as $server) { - // $schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer(); - $schedule - ->call(function () use ($server) { - $randomSeconds = rand(1, 40); - $job = new ContainerStatusJob($server); - $job->delay($randomSeconds); - ray('dispatching container status job in ' . $randomSeconds . ' seconds'); - dispatch($job); - })->name('container-status-' . $server->id)->everyMinute()->onOneServer(); + $schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer(); + // $schedule + // ->call(function () use ($server) { + // $randomSeconds = rand(1, 40); + // $job = new ContainerStatusJob($server); + // $job->delay($randomSeconds); + // ray('dispatching container status job in ' . $randomSeconds . ' seconds'); + // dispatch($job); + // })->name('container-status-' . $server->id)->everyMinute()->onOneServer(); if ($server->isLogDrainEnabled()) { - // $schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer(); - $schedule - ->call(function () use ($server) { - $randomSeconds = rand(1, 40); - $job = new CheckLogDrainContainerJob($server); - $job->delay($randomSeconds); - dispatch($job); - })->name('log-drain-container-check-' . $server->id)->everyMinute()->onOneServer(); + $schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer(); + // $schedule + // ->call(function () use ($server) { + // $randomSeconds = rand(1, 40); + // $job = new CheckLogDrainContainerJob($server); + // $job->delay($randomSeconds); + // dispatch($job); + // })->name('log-drain-container-check-' . $server->id)->everyMinute()->onOneServer(); } } foreach ($servers as $server) { - // $schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer(); - $schedule - ->call(function () use ($server) { - $randomSeconds = rand(1, 40); - $job = new ServerStatusJob($server); - $job->delay($randomSeconds); - dispatch($job); - })->name('server-status-job-' . $server->id)->everyMinute()->onOneServer(); + $schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer(); + // $schedule + // ->call(function () use ($server) { + // $randomSeconds = rand(1, 40); + // $job = new ServerStatusJob($server); + // $job->delay($randomSeconds); + // dispatch($job); + // })->name('server-status-job-' . $server->id)->everyMinute()->onOneServer(); } } private function instance_auto_update($schedule) From b550c32f9b07c1b1737cfee6489688fda44204ff Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 26 Feb 2024 09:09:01 +0100 Subject: [PATCH 14/17] Add whitespace-pre-line class to font-mono in deployment show blade file --- .../livewire/project/application/deployment/show.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/project/application/deployment/show.blade.php b/resources/views/livewire/project/application/deployment/show.blade.php index cc31d625d..e7f74b8a6 100644 --- a/resources/views/livewire/project/application/deployment/show.blade.php +++ b/resources/views/livewire/project/application/deployment/show.blade.php @@ -51,7 +51,7 @@ @if (decode_remote_command_output($application_deployment_queue)->count() > 0) @foreach (decode_remote_command_output($application_deployment_queue) as $line)
    $line['hidden'], 'text-red-500' => $line['type'] == 'stderr', ])>[{{ $line['timestamp'] }}] @if ($line['hidden']) From 453956172b3a3c416bc9ee1230fd055c349cbc2d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 26 Feb 2024 09:32:28 +0100 Subject: [PATCH 15/17] Refactor show.blade.php to improve code readability --- .../livewire/project/application/deployment/show.blade.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/livewire/project/application/deployment/show.blade.php b/resources/views/livewire/project/application/deployment/show.blade.php index e7f74b8a6..6eabd859c 100644 --- a/resources/views/livewire/project/application/deployment/show.blade.php +++ b/resources/views/livewire/project/application/deployment/show.blade.php @@ -51,9 +51,9 @@ @if (decode_remote_command_output($application_deployment_queue)->count() > 0) @foreach (decode_remote_command_output($application_deployment_queue) as $line)
    $line['hidden'], - 'text-red-500' => $line['type'] == 'stderr', + 'font-mono', + 'text-warning whitespace-pre-line' => $line['hidden'], + 'text-red-500 whitespace-pre-line' => $line['type'] == 'stderr', ])>[{{ $line['timestamp'] }}] @if ($line['hidden'])
    COMMAND:
    {{ $line['command'] }}

    OUTPUT: @endif @if (str($line['output'])->contains('http://') || str($line['output'])->contains('https://')) From 678647f39a69861971ce2e3500712da8f7d6fe31 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 26 Feb 2024 10:25:21 +0100 Subject: [PATCH 16/17] 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\Http\Request; 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\Http\Controllers\Controller; 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\Http\Controllers\Controller; 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 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); ); } } - $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\InteractsWithQueue; 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 @@ class ServerOverflowJob implements ShouldQueue, ShouldBeEncrypted 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 @@ class Index extends Component auth()->login($user); if ($user_id === 0) { + Cache::forget('team:0'); session()->forget('adminToken'); } else { $token_payload = [ @@ -35,6 +37,7 @@ class Index extends Component $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 App\Notifications\Server\Unreachable; 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 @@ class Server extends BaseModel 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 @@ class Server extends BaseModel 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 @@ class Server extends BaseModel } 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\Contracts\Queue\ShouldQueue; 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 @@ class DisabledDueToOverflow extends Notification implements ShouldQueue { $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 @@ trait ExecuteRemoteCommand 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 @@ return new class extends Migration 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 @@ return new class extends Migration 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 @@
    @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 @@ 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 @@
    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 @@
    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, From b67abe58e8b7d7e33f7b7089e634e5a3bdc38cb1 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 26 Feb 2024 10:34:44 +0100 Subject: [PATCH 17/17] Remove commented out code in ServerStatusJob.php --- app/Jobs/ServerStatusJob.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/Jobs/ServerStatusJob.php b/app/Jobs/ServerStatusJob.php index d0243fa9a..31683d097 100644 --- a/app/Jobs/ServerStatusJob.php +++ b/app/Jobs/ServerStatusJob.php @@ -41,15 +41,6 @@ class ServerStatusJob implements ShouldQueue, ShouldBeEncrypted throw new \RuntimeException('Server is not ready.'); }; try { - // $this->server->validateConnection(); - // $this->server->validateOS(); - // $docker_installed = $this->server->validateDockerEngine(); - // if (!$docker_installed) { - // $this->server->installDocker(); - // $this->server->validateDockerEngine(); - // } - - // $this->server->validateDockerEngineVersion(); if ($this->server->isFunctional()) { $this->cleanup(notify: false); }