From a2bca3d5b82913638831301ab25699a52259d21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Mon, 30 Sep 2024 00:43:35 +0200 Subject: [PATCH 01/57] added embedded Discord messages logic --- app/Dto/Notification/DiscordMessage.php | 70 +++++++++++++++++++ app/Jobs/SendMessageToDiscordJob.php | 8 +-- app/Notifications/Channels/DiscordChannel.php | 2 +- app/Notifications/Test.php | 13 ++-- 4 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 app/Dto/Notification/DiscordMessage.php diff --git a/app/Dto/Notification/DiscordMessage.php b/app/Dto/Notification/DiscordMessage.php new file mode 100644 index 000000000..88feda7e3 --- /dev/null +++ b/app/Dto/Notification/DiscordMessage.php @@ -0,0 +1,70 @@ +fields[] = [ + 'name' => $name, + 'value' => $value, + ]; + + return $this; + } + + public function toPayload(): array + { + $payload = [ + 'embeds' => [ + [ + 'title' => $this->title, + 'description' => $this->description, + 'color' => $this->color, + 'fields' => $this->addTimestampToFields($this->fields), + ], + ], + ]; + + if ($this->isCritical) { + $payload['content'] = '@here'; + } + + return $payload; + } + + private function addTimestampToFields(array $fields): array + { + $fields[] = [ + 'name' => 'Time', + 'value' => 'timestamp.':R>', + ]; + + return $fields; + } +} diff --git a/app/Jobs/SendMessageToDiscordJob.php b/app/Jobs/SendMessageToDiscordJob.php index f38cf823c..8b238a36d 100644 --- a/app/Jobs/SendMessageToDiscordJob.php +++ b/app/Jobs/SendMessageToDiscordJob.php @@ -2,6 +2,7 @@ namespace App\Jobs; +use App\Dto\Notification\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; @@ -29,7 +30,7 @@ class SendMessageToDiscordJob implements ShouldBeEncrypted, ShouldQueue public int $maxExceptions = 5; public function __construct( - public string $text, + public DiscordMessage $message, public string $webhookUrl ) {} @@ -38,9 +39,6 @@ class SendMessageToDiscordJob implements ShouldBeEncrypted, ShouldQueue */ public function handle(): void { - $payload = [ - 'content' => $this->text, - ]; - Http::post($this->webhookUrl, $payload); + Http::post($this->webhookUrl, $this->message->toPayload()); } } diff --git a/app/Notifications/Channels/DiscordChannel.php b/app/Notifications/Channels/DiscordChannel.php index f1706f138..3a33d8902 100644 --- a/app/Notifications/Channels/DiscordChannel.php +++ b/app/Notifications/Channels/DiscordChannel.php @@ -12,7 +12,7 @@ class DiscordChannel */ public function send(SendsDiscord $notifiable, Notification $notification): void { - $message = $notification->toDiscord($notifiable); + $message = $notification->toDiscord(); $webhookUrl = $notifiable->routeNotificationForDiscord(); if (! $webhookUrl) { return; diff --git a/app/Notifications/Test.php b/app/Notifications/Test.php index 3b46a9a24..f3bb1e3f6 100644 --- a/app/Notifications/Test.php +++ b/app/Notifications/Test.php @@ -2,6 +2,7 @@ namespace App\Notifications; +use App\Dto\Notification\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -29,11 +30,15 @@ class Test extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = 'Coolify: This is a test Discord notification from Coolify.'; - $message .= "\n\n"; - $message .= '[Go to your dashboard]('.base_url().')'; + $message = new DiscordMessage( + title: 'Coolify: This is a test Discord notification from Coolify.', + description: 'This is a test Discord notification from Coolify.', + color: DiscordMessage::successColor(), + ); + + $message->addField('Link', '[Go to your dashboard]('.base_url().')'); return $message; } From 9e2f0fb894dead9bf6da22398cbb4525f942ed35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Mon, 30 Sep 2024 10:06:50 +0200 Subject: [PATCH 02/57] updated namespace for DiscordMessage --- app/Jobs/SendMessageToDiscordJob.php | 2 +- app/{Dto/Notification => Notifications/Dto}/DiscordMessage.php | 2 +- app/Notifications/Test.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename app/{Dto/Notification => Notifications/Dto}/DiscordMessage.php (97%) diff --git a/app/Jobs/SendMessageToDiscordJob.php b/app/Jobs/SendMessageToDiscordJob.php index 8b238a36d..5b406f50f 100644 --- a/app/Jobs/SendMessageToDiscordJob.php +++ b/app/Jobs/SendMessageToDiscordJob.php @@ -2,7 +2,7 @@ namespace App\Jobs; -use App\Dto\Notification\DiscordMessage; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; diff --git a/app/Dto/Notification/DiscordMessage.php b/app/Notifications/Dto/DiscordMessage.php similarity index 97% rename from app/Dto/Notification/DiscordMessage.php rename to app/Notifications/Dto/DiscordMessage.php index 88feda7e3..39c4be718 100644 --- a/app/Dto/Notification/DiscordMessage.php +++ b/app/Notifications/Dto/DiscordMessage.php @@ -1,6 +1,6 @@ Date: Tue, 1 Oct 2024 21:38:12 +0200 Subject: [PATCH 03/57] updated DiscordMessages for Server notifications --- app/Notifications/Server/DockerCleanup.php | 11 +++++++---- app/Notifications/Server/ForceDisabled.php | 11 +++++++++-- app/Notifications/Server/ForceEnabled.php | 11 +++++++---- app/Notifications/Server/HighDiskUsage.php | 13 +++++++++++-- app/Notifications/Server/Revived.php | 11 +++++++---- app/Notifications/Server/Unreachable.php | 11 +++++++++-- 6 files changed, 50 insertions(+), 18 deletions(-) diff --git a/app/Notifications/Server/DockerCleanup.php b/app/Notifications/Server/DockerCleanup.php index 682ed7a1a..68d35b15e 100644 --- a/app/Notifications/Server/DockerCleanup.php +++ b/app/Notifications/Server/DockerCleanup.php @@ -5,6 +5,7 @@ namespace App\Notifications\Server; use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; @@ -49,11 +50,13 @@ class DockerCleanup extends Notification implements ShouldQueue // return $mail; // } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server '{$this->server->name}' cleanup job done!\n\n{$this->message}"; - - return $message; + return new DiscordMessage( + title: "Coolify: Server '{$this->server->name}' cleanup job done!", + description: $this->message, + color: DiscordMessage::successColor(), + ); } public function toTelegram(): array diff --git a/app/Notifications/Server/ForceDisabled.php b/app/Notifications/Server/ForceDisabled.php index 6377f2f15..a02228dc3 100644 --- a/app/Notifications/Server/ForceDisabled.php +++ b/app/Notifications/Server/ForceDisabled.php @@ -6,6 +6,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -50,9 +51,15 @@ class ForceDisabled extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $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/subscriptions)."; + $message = new DiscordMessage( + title: "Coolify: Server ({$this->server->name}) disabled because it is not paid!", + description: 'All automations and integrations are stopped.', + color: DiscordMessage::errorColor(), + ); + + $message->addField('Link', 'Please update your subscription to enable the server again [here](https://app.coolify.io/subscriptions).'); return $message; } diff --git a/app/Notifications/Server/ForceEnabled.php b/app/Notifications/Server/ForceEnabled.php index 83594d643..c5c3e42b3 100644 --- a/app/Notifications/Server/ForceEnabled.php +++ b/app/Notifications/Server/ForceEnabled.php @@ -6,6 +6,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -50,11 +51,13 @@ class ForceEnabled extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server ({$this->server->name}) enabled again!"; - - return $message; + return new DiscordMessage( + title: "Coolify: Server '{$this->server->name}' enabled again!", + description: 'All automations and integrations are started.', + color: DiscordMessage::successColor(), + ); } public function toTelegram(): array diff --git a/app/Notifications/Server/HighDiskUsage.php b/app/Notifications/Server/HighDiskUsage.php index 34cb22091..c91b8c266 100644 --- a/app/Notifications/Server/HighDiskUsage.php +++ b/app/Notifications/Server/HighDiskUsage.php @@ -6,6 +6,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -52,9 +53,17 @@ class HighDiskUsage extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->docker_cleanup_threshold}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup."; + $message = new DiscordMessage( + title: "Coolify: Server '{$this->server->name}' high disk usage detected!", + description: 'Please cleanup your disk to prevent data-loss.', + color: DiscordMessage::errorColor(), + ); + + $message->addField('Disk usage', "{$this->disk_usage}%"); + $message->addField('Threshold', "{$this->docker_cleanup_threshold}%"); + $message->addField('Link', 'Here are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.'); return $message; } diff --git a/app/Notifications/Server/Revived.php b/app/Notifications/Server/Revived.php index 3f2b3b696..c3a3f389a 100644 --- a/app/Notifications/Server/Revived.php +++ b/app/Notifications/Server/Revived.php @@ -8,6 +8,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -72,11 +73,13 @@ class Revived extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server '{$this->server->name}' revived. All automations & integrations are turned on again!"; - - return $message; + return new DiscordMessage( + title: "Coolify: Server '{$this->server->name}' revived.", + description: 'All automations & integrations are turned on again!', + color: DiscordMessage::successColor(), + ); } public function toTelegram(): array diff --git a/app/Notifications/Server/Unreachable.php b/app/Notifications/Server/Unreachable.php index 2fb83559a..7e56123e4 100644 --- a/app/Notifications/Server/Unreachable.php +++ b/app/Notifications/Server/Unreachable.php @@ -6,6 +6,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -63,9 +64,15 @@ class Unreachable extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server and turn on all automations & integrations."; + $message = new DiscordMessage( + title: "Coolify: Your server '{$this->server->name}' is unreachable.", + description: 'All automations & integrations are turned off! Please check your server!', + color: DiscordMessage::errorColor(), + ); + + $message->addField('IMPORTANT', 'We automatically try to revive your server and turn on all automations & integrations.'); return $message; } From cb5dc13bf1260594c80b913bc44de449f6bdd9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Tue, 1 Oct 2024 21:42:13 +0200 Subject: [PATCH 04/57] updated DiscordMessages for Internal&ScheduledTask notifications --- app/Notifications/Dto/DiscordMessage.php | 5 +++++ app/Notifications/Internal/GeneralNotification.php | 9 +++++++-- app/Notifications/ScheduledTask/TaskFailed.php | 13 +++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/Notifications/Dto/DiscordMessage.php b/app/Notifications/Dto/DiscordMessage.php index 39c4be718..0d0028f56 100644 --- a/app/Notifications/Dto/DiscordMessage.php +++ b/app/Notifications/Dto/DiscordMessage.php @@ -28,6 +28,11 @@ class DiscordMessage return hexdec('ff705f'); } + public static function infoColor(): int + { + return hexdec('4f545c'); + } + public function addField(string $name, string $value): self { $this->fields[] = [ diff --git a/app/Notifications/Internal/GeneralNotification.php b/app/Notifications/Internal/GeneralNotification.php index 1d4d648c8..48e7d8340 100644 --- a/app/Notifications/Internal/GeneralNotification.php +++ b/app/Notifications/Internal/GeneralNotification.php @@ -4,6 +4,7 @@ namespace App\Notifications\Internal; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; @@ -32,9 +33,13 @@ class GeneralNotification extends Notification implements ShouldQueue return $channels; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return $this->message; + return new DiscordMessage( + title: 'Coolify: General Notification', + description: $this->message, + color: DiscordMessage::infoColor(), + ); } public function toTelegram(): array diff --git a/app/Notifications/ScheduledTask/TaskFailed.php b/app/Notifications/ScheduledTask/TaskFailed.php index 479cc1aa1..aac665fb6 100644 --- a/app/Notifications/ScheduledTask/TaskFailed.php +++ b/app/Notifications/ScheduledTask/TaskFailed.php @@ -3,6 +3,7 @@ namespace App\Notifications\ScheduledTask; use App\Models\ScheduledTask; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -46,9 +47,17 @@ class TaskFailed extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return "Coolify: Scheduled task ({$this->task->name}, [link]({$this->url})) failed with output: {$this->output}"; + $message = new DiscordMessage( + title: "Coolify: Scheduled task ({$this->task->name}) failed.", + description: "Output: {$this->output}", + color: DiscordMessage::errorColor(), + ); + + $message->addField('Link', '[Open task in Coolify]('.$this->url.')'); + + return $message; } public function toTelegram(): array From 53a6e97ca37069347132a65c591d71aac6198bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Tue, 1 Oct 2024 21:46:56 +0200 Subject: [PATCH 05/57] updated DiscordMessages for Database notifications --- app/Notifications/Database/BackupFailed.php | 15 +++++++++++++-- app/Notifications/Database/BackupSuccess.php | 13 +++++++++++-- app/Notifications/Database/DailyBackup.php | 9 +++++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/Notifications/Database/BackupFailed.php b/app/Notifications/Database/BackupFailed.php index 77024c05b..ef6128c5f 100644 --- a/app/Notifications/Database/BackupFailed.php +++ b/app/Notifications/Database/BackupFailed.php @@ -3,6 +3,7 @@ namespace App\Notifications\Database; use App\Models\ScheduledDatabaseBackup; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -45,9 +46,19 @@ class BackupFailed extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return "Coolify: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was FAILED.\n\nReason:\n{$this->output}"; + $message = new DiscordMessage( + title: "Coolify: Database backup for {$this->name} (db:{$this->database_name}) has FAILED.", + description: 'Please check the output below for more information.', + color: DiscordMessage::errorColor(), + isCritical: true, + ); + + $message->addField('Frequency', $this->frequency); + $message->addField('Output', $this->output); + + return $message; } public function toTelegram(): array diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php index f8dc6eb56..fa9eb616c 100644 --- a/app/Notifications/Database/BackupSuccess.php +++ b/app/Notifications/Database/BackupSuccess.php @@ -3,6 +3,7 @@ namespace App\Notifications\Database; use App\Models\ScheduledDatabaseBackup; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -44,9 +45,17 @@ class BackupSuccess extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return "Coolify: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was successful."; + $message = new DiscordMessage( + title: "Coolify: Database backup for {$this->name} (db:{$this->database_name}) was successful.", + description: 'Please check the output below for more information.', + color: DiscordMessage::successColor(), + ); + + $message->addField('Frequency', $this->frequency); + + return $message; } public function toTelegram(): array diff --git a/app/Notifications/Database/DailyBackup.php b/app/Notifications/Database/DailyBackup.php index a51ac6283..b53a56903 100644 --- a/app/Notifications/Database/DailyBackup.php +++ b/app/Notifications/Database/DailyBackup.php @@ -4,6 +4,7 @@ namespace App\Notifications\Database; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Channels\MailChannel; @@ -34,9 +35,13 @@ class DailyBackup extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return 'Coolify: Daily backup statuses'; + return new DiscordMessage( + title: 'Coolify: Daily backup statuses', + description: 'Nothing to report.', + color: DiscordMessage::infoColor(), + ); // todo: is this necessary notification? what is the purpose of this notification? } public function toTelegram(): array From aac491da251edb953f112a9ea53b2420be3398e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Tue, 1 Oct 2024 21:48:14 +0200 Subject: [PATCH 06/57] updated DiscordMessages for Container notifications --- app/Notifications/Container/ContainerRestarted.php | 9 +++++++-- app/Notifications/Container/ContainerStopped.php | 11 +++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/Notifications/Container/ContainerRestarted.php b/app/Notifications/Container/ContainerRestarted.php index 23f6de264..49c2cecf0 100644 --- a/app/Notifications/Container/ContainerRestarted.php +++ b/app/Notifications/Container/ContainerRestarted.php @@ -3,6 +3,7 @@ namespace App\Notifications\Container; use App\Models\Server; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -34,9 +35,13 @@ class ContainerRestarted extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}"; + $message = new DiscordMessage( + title: "Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}", + description: 'Please check the output below for more information.', + color: DiscordMessage::infoColor(), + ); return $message; } diff --git a/app/Notifications/Container/ContainerStopped.php b/app/Notifications/Container/ContainerStopped.php index bcf5e67a5..d8ed2316b 100644 --- a/app/Notifications/Container/ContainerStopped.php +++ b/app/Notifications/Container/ContainerStopped.php @@ -3,6 +3,7 @@ namespace App\Notifications\Container; use App\Models\Server; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -34,11 +35,13 @@ class ContainerStopped extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}"; - - return $message; + return new DiscordMessage( + title: "Coolify: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}", + description: 'Please check the output below for more information.', + color: DiscordMessage::errorColor(), + ); } public function toTelegram(): array From 3b4759f349912b2d5c6cf5434fb0f3b7b28cd1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Tue, 1 Oct 2024 22:07:24 +0200 Subject: [PATCH 07/57] updated DiscordMessages for Application notifications --- .../Application/DeploymentFailed.php | 23 +++++++++++---- .../Application/DeploymentSuccess.php | 29 ++++++++++++------- .../Application/StatusChanged.php | 13 ++++++--- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/app/Notifications/Application/DeploymentFailed.php b/app/Notifications/Application/DeploymentFailed.php index 1809da368..b255cc667 100644 --- a/app/Notifications/Application/DeploymentFailed.php +++ b/app/Notifications/Application/DeploymentFailed.php @@ -4,6 +4,7 @@ namespace App\Notifications\Application; use App\Models\Application; use App\Models\ApplicationPreview; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -72,14 +73,26 @@ class DeploymentFailed extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { if ($this->preview) { - $message = 'Coolify: Pull request #'.$this->preview->pull_request_id.' of '.$this->application_name.' ('.$this->preview->fqdn.') deployment failed: '; - $message .= '[View Deployment Logs]('.$this->deployment_url.')'; + $message = new DiscordMessage( + title: 'Coolify: Deployment failed of pull request #'.$this->preview->pull_request_id.' of '.$this->application_name, + description: 'Check in the link below', + color: DiscordMessage::errorColor(), + isCritical: true, + ); + + $message->addField('Deployment Logs', '[Here]('.$this->deployment_url.')'); } else { - $message = 'Coolify: Deployment failed of '.$this->application_name.' ('.$this->fqdn.'): '; - $message .= '[View Deployment Logs]('.$this->deployment_url.')'; + $message = new DiscordMessage( + title: 'Coolify: Deployment failed of '.$this->application_name, + description: 'Check in the link below', + color: DiscordMessage::errorColor(), + isCritical: true, + ); + + $message->addField('Deployment Logs', '[Here]('.$this->deployment_url.')'); } return $message; diff --git a/app/Notifications/Application/DeploymentSuccess.php b/app/Notifications/Application/DeploymentSuccess.php index 5085065c2..96ec2ce82 100644 --- a/app/Notifications/Application/DeploymentSuccess.php +++ b/app/Notifications/Application/DeploymentSuccess.php @@ -4,6 +4,7 @@ namespace App\Notifications\Application; use App\Models\Application; use App\Models\ApplicationPreview; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -78,24 +79,32 @@ class DeploymentSuccess extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { if ($this->preview) { - $message = 'Coolify: New PR'.$this->preview->pull_request_id.' version successfully deployed of '.$this->application_name.' + $message = new DiscordMessage( + title: "Coolify: New PR{$this->preview->pull_request_id} version successfully deployed of {$this->application_name}", + description: 'Check in the links below.', + color: DiscordMessage::successColor(), + ); -'; if ($this->preview->fqdn) { - $message .= '[Open Application]('.$this->preview->fqdn.') | '; + $message->addField('Open Application', '[Here]('.$this->preview->fqdn.')'); } - $message .= '[Deployment logs]('.$this->deployment_url.')'; - } else { - $message = 'Coolify: New version successfully deployed of '.$this->application_name.' -'; + $message->addField('Deployment logs', '[Here]('.$this->deployment_url.')'); + } else { + $message = new DiscordMessage( + title: "Coolify: New version successfully deployed of {$this->application_name}", + description: 'Check in the links below.', + color: DiscordMessage::successColor(), + ); + if ($this->fqdn) { - $message .= '[Open Application]('.$this->fqdn.') | '; + $message->addField('Open Application', '[Here]('.$this->fqdn.')'); } - $message .= '[Deployment logs]('.$this->deployment_url.')'; + + $message->addField('Deployment logs', '[Here]('.$this->deployment_url.')'); } return $message; diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index 53ed8a589..abc93a3a4 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -3,6 +3,7 @@ namespace App\Notifications\Application; use App\Models\Application; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -55,12 +56,16 @@ class StatusChanged extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = 'Coolify: '.$this->resource_name.' has been stopped. + $message = new DiscordMessage( + title: "Coolify: {$this->resource_name} has been stopped", + description: 'Check the application in Coolify', + color: DiscordMessage::errorColor(), + isCritical: true, + ); -'; - $message .= '[Open Application in Coolify]('.$this->resource_url.')'; + $message->addField('Link', '[Open Application in Coolify]('.$this->resource_url.')'); return $message; } From b4593ec1d225ffe15a471687d35df2fbac678dd3 Mon Sep 17 00:00:00 2001 From: "Alexander G." Date: Fri, 4 Oct 2024 12:42:42 +0300 Subject: [PATCH 08/57] Update trigger.yaml --- templates/compose/trigger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/trigger.yaml b/templates/compose/trigger.yaml index 6181a6925..2e8e9f9a7 100644 --- a/templates/compose/trigger.yaml +++ b/templates/compose/trigger.yaml @@ -6,7 +6,7 @@ services: trigger: - image: ghcr.io/triggerdotdev/trigger.dev:latest + image: ghcr.io/triggerdotdev/trigger.dev:main environment: - SERVICE_FQDN_TRIGGER_3000 - LOGIN_ORIGIN=$SERVICE_FQDN_TRIGGER From ab8b36266bed9182eaa867eaf41ddc51a3e90056 Mon Sep 17 00:00:00 2001 From: "Alexander G." Date: Fri, 4 Oct 2024 12:44:19 +0300 Subject: [PATCH 09/57] Update trigger-with-external-database.yaml --- templates/compose/trigger-with-external-database.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/trigger-with-external-database.yaml b/templates/compose/trigger-with-external-database.yaml index dcd3e2b97..00702452b 100644 --- a/templates/compose/trigger-with-external-database.yaml +++ b/templates/compose/trigger-with-external-database.yaml @@ -6,7 +6,7 @@ services: trigger: - image: ghcr.io/triggerdotdev/trigger.dev:latest + image: ghcr.io/triggerdotdev/trigger.dev:main environment: - SERVICE_FQDN_TRIGGER_3000 - LOGIN_ORIGIN=$SERVICE_FQDN_TRIGGER From b84cecfd3f757d792017892c793f4bee017a22af Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Sat, 5 Oct 2024 10:21:14 +0300 Subject: [PATCH 10/57] Added missing services. --- templates/compose/trigger.yaml | 44 ++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/templates/compose/trigger.yaml b/templates/compose/trigger.yaml index 2e8e9f9a7..1064ef789 100644 --- a/templates/compose/trigger.yaml +++ b/templates/compose/trigger.yaml @@ -11,15 +11,23 @@ services: - SERVICE_FQDN_TRIGGER_3000 - LOGIN_ORIGIN=$SERVICE_FQDN_TRIGGER - APP_ORIGIN=$SERVICE_FQDN_TRIGGER + - ELECTRIC_ORIGIN=http://electric:3000 - MAGIC_LINK_SECRET=$SERVICE_PASSWORD_64_MAGIC - ENCRYPTION_KEY=$SERVICE_PASSWORD_64_ENCRYPTION - SESSION_SECRET=$SERVICE_PASSWORD_64_SESSION + - PROVIDER_SECRET=$SERVICE_PASSWORD_64_PROVIDER + - COORDINATOR_SECRET=$SERVICE_PASSWORD_64_COORDINATOR - POSTGRES_USER=$SERVICE_USER_POSTGRES - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - POSTGRES_DB=${POSTGRES_DB:-trigger} - POSTGRES_HOST=postgres - DATABASE_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB - DIRECT_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_TLS_DISABLED=true + - V3_ENABLED=${V3_ENABLED:-true} + - REMIX_APP_PORT=${REMIX_APP_PORT:-3000} - RUNTIME_PLATFORM=docker-compose - NODE_ENV=production - AUTH_GITHUB_CLIENT_ID=${AUTH_GITHUB_CLIENT_ID} @@ -30,10 +38,43 @@ services: depends_on: postgresql: condition: service_healthy + redis: + condition: service_healthy + electric: + condition: service_healthy healthcheck: - test: ["NONE"] + test: + - CMD-SHELL + - pwd + electric: + image: electricsql/electric + restart: always + environment: + DATABASE_URL: postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + depends_on: + postgresql: + condition: service_healthy + healthcheck: + test: + - CMD-SHELL + - pwd + redis: + image: "redis:7" + environment: + - ALLOW_EMPTY_PASSWORD=yes + restart: always + healthcheck: + test: + - CMD-SHELL + - "redis-cli -h localhost -p 6379 ping" + interval: 5s + timeout: 5s + retries: 3 + volumes: + - redis-data:/data postgresql: image: postgres:16-alpine + restart: always volumes: - postgresql-data:/var/lib/postgresql/data environment: @@ -45,4 +86,3 @@ services: interval: 5s timeout: 20s retries: 10 - From b1e91252f3ccb640c1d2cd29edc23454775e70db Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Wed, 9 Oct 2024 12:54:19 +0300 Subject: [PATCH 11/57] Updated trigger service --- templates/compose/trigger.yaml | 122 ++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 32 deletions(-) diff --git a/templates/compose/trigger.yaml b/templates/compose/trigger.yaml index 1064ef789..e33459535 100644 --- a/templates/compose/trigger.yaml +++ b/templates/compose/trigger.yaml @@ -4,37 +4,56 @@ # logo: svgs/trigger.png # port: 3000 +x-common-env: &common-env + PORT: 3030 + REMIX_APP_PORT: 3000 + NODE_ENV: production + RUNTIME_PLATFORM: docker-compose + V3_ENABLED: true + INTERNAL_OTEL_TRACE_DISABLED: 1 + INTERNAL_OTEL_TRACE_LOGGING_ENABLED: 0 + POSTGRES_USER: $SERVICE_USER_POSTGRES + POSTGRES_PASSWORD: $SERVICE_PASSWORD_POSTGRES + POSTGRES_DB: ${POSTGRES_DB:-trigger} + MAGIC_LINK_SECRET: $SERVICE_PASSWORD_64_MAGIC + SESSION_SECRET: $SERVICE_PASSWORD_64_SESSION + ENCRYPTION_KEY: $SERVICE_PASSWORD_64_ENCRYPTION + PROVIDER_SECRET: $SERVICE_PASSWORD_64_PROVIDER + COORDINATOR_SECRET: $SERVICE_PASSWORD_64_COORDINATOR + DATABASE_HOST: postgresql + DATABASE_URL: postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + DIRECT_URL: postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_TLS_DISABLED: true + COORDINATOR_HOST: 127.0.0.1 + COORDINATOR_PORT: 9020 + WHITELISTED_EMAILS: "" + ADMIN_EMAILS: "" + DEFAULT_ORG_EXECUTION_CONCURRENCY_LIMIT: 300 + DEFAULT_ENV_EXECUTION_CONCURRENCY_LIMIT: 100 + DEPLOY_REGISTRY_HOST: docker.io + DEPLOY_REGISTRY_NAMESPACE: trigger + REGISTRY_HOST: ${DEPLOY_REGISTRY_HOST} + REGISTRY_NAMESPACE: ${DEPLOY_REGISTRY_NAMESPACE} + AUTH_GITHUB_CLIENT_ID: ${AUTH_GITHUB_CLIENT_ID} + AUTH_GITHUB_CLIENT_SECRET: ${AUTH_GITHUB_CLIENT_SECRET} + RESEND_API_KEY: ${RESEND_API_KEY} + FROM_EMAIL: ${FROM_EMAIL} + REPLY_TO_EMAIL: ${REPLY_TO_EMAIL} + LOGIN_ORIGIN: $SERVICE_FQDN_TRIGGER_3000 + APP_ORIGIN: $SERVICE_FQDN_TRIGGER_3000 + DEV_OTEL_EXPORTER_OTLP_ENDPOINT: $SERVICE_FQDN_TRIGGER_3000/otel + OTEL_EXPORTER_OTLP_ENDPOINT: "http://trigger:3040/otel" + ELECTRIC_ORIGIN: http://electric:3000 + services: trigger: - image: ghcr.io/triggerdotdev/trigger.dev:main + image: ghcr.io/triggerdotdev/trigger.dev:v3 + restart: always environment: - - SERVICE_FQDN_TRIGGER_3000 - - LOGIN_ORIGIN=$SERVICE_FQDN_TRIGGER - - APP_ORIGIN=$SERVICE_FQDN_TRIGGER - - ELECTRIC_ORIGIN=http://electric:3000 - - MAGIC_LINK_SECRET=$SERVICE_PASSWORD_64_MAGIC - - ENCRYPTION_KEY=$SERVICE_PASSWORD_64_ENCRYPTION - - SESSION_SECRET=$SERVICE_PASSWORD_64_SESSION - - PROVIDER_SECRET=$SERVICE_PASSWORD_64_PROVIDER - - COORDINATOR_SECRET=$SERVICE_PASSWORD_64_COORDINATOR - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_DB=${POSTGRES_DB:-trigger} - - POSTGRES_HOST=postgres - - DATABASE_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB - - DIRECT_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB - - REDIS_HOST=redis - - REDIS_PORT=6379 - - REDIS_TLS_DISABLED=true - - V3_ENABLED=${V3_ENABLED:-true} - - REMIX_APP_PORT=${REMIX_APP_PORT:-3000} - - RUNTIME_PLATFORM=docker-compose - - NODE_ENV=production - - AUTH_GITHUB_CLIENT_ID=${AUTH_GITHUB_CLIENT_ID} - - AUTH_GITHUB_CLIENT_SECRET=${AUTH_GITHUB_CLIENT_SECRET} - - RESEND_API_KEY=${RESEND_API_KEY} - - FROM_EMAIL=${FROM_EMAIL} - - REPLY_TO_EMAIL=${REPLY_TO_EMAIL} + SERVICE_FQDN_TRIGGER_3000: "" + <<: *common-env depends_on: postgresql: condition: service_healthy @@ -50,7 +69,7 @@ services: image: electricsql/electric restart: always environment: - DATABASE_URL: postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + <<: *common-env depends_on: postgresql: condition: service_healthy @@ -78,11 +97,50 @@ services: volumes: - postgresql-data:/var/lib/postgresql/data environment: - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_DB=${POSTGRES_DB:-trigger} + <<: *common-env + command: + - -c + - wal_level=logical healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 20s retries: 10 + docker-provider: + image: ghcr.io/triggerdotdev/provider/docker:v3 + restart: always + volumes: + - /var/run/docker.sock:/var/run/docker.sock + user: root + depends_on: + trigger: + condition: service_healthy + environment: + <<: *common-env + PLATFORM_HOST: trigger + PLATFORM_WS_PORT: 3030 + SECURE_CONNECTION: "false" + PLATFORM_SECRET: $PROVIDER_SECRET + coordinator: + image: ghcr.io/triggerdotdev/coordinator:v3 + restart: always + volumes: + - /var/run/docker.sock:/var/run/docker.sock + user: root + depends_on: + trigger: + condition: service_healthy + environment: + <<: *common-env + PLATFORM_HOST: trigger + PLATFORM_WS_PORT: 3030 + SECURE_CONNECTION: "false" + PLATFORM_SECRET: $COORDINATOR_SECRET + healthcheck: + test: + - CMD-SHELL + - pwd + +volumes: + postgresql-data: + redis-data: From 08da5aaf04ffef8b567106a437400157fd884009 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:59:42 +0200 Subject: [PATCH 12/57] fix and improve OTP --- .../views/livewire/profile/index.blade.php | 70 ++++++++++++++++--- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/resources/views/livewire/profile/index.blade.php b/resources/views/livewire/profile/index.blade.php index 0648016b7..94bc73089 100644 --- a/resources/views/livewire/profile/index.blade.php +++ b/resources/views/livewire/profile/index.blade.php @@ -33,20 +33,70 @@ Please finish configuring two factor authentication below. Read the QR code or enter the secret key manually. -
+
@csrf - + Validate 2FA -
-
{!! request()->user()->twoFactorQrCodeSvg() !!}
-
- - Show secret key to manually - enter +
+
+ {!! request()->user()->twoFactorQrCodeSvg() !!} +
+
+
+
+ + +
+
+ + +
+
+ + Secret Key and OTP URL +
From 1d2e9b69461bafb9a79264981265cabafd2954c9 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:29:33 +0200 Subject: [PATCH 13/57] fix is required on shared variables --- app/Livewire/Project/Shared/EnvironmentVariable/Show.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php index 0538a6bdb..53c4374df 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php @@ -112,14 +112,20 @@ class Show extends Component $this->validate(); } - if ($this->env->is_required && str($this->env->real_value)->isEmpty()) { + if (! $this->isSharedVariable && $this->env->is_required && str($this->env->real_value)->isEmpty()) { $oldValue = $this->env->getOriginal('value'); $this->env->value = $oldValue; $this->dispatch('error', 'Required environment variable cannot be empty.'); return; } + $this->serialize(); + + if ($this->isSharedVariable) { + unset($this->env->is_required); + } + $this->env->save(); $this->dispatch('success', 'Environment variable updated.'); $this->dispatch('envsUpdated'); From ce4b6db041ffb976db4943cff5051d593376310e Mon Sep 17 00:00:00 2001 From: JakeKydd Date: Sun, 20 Oct 2024 01:17:26 +0200 Subject: [PATCH 14/57] add: wireguard-easy template --- public/svgs/wireguard.svg | 7 +++++++ templates/compose/wireguard-easy.yaml | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 public/svgs/wireguard.svg create mode 100644 templates/compose/wireguard-easy.yaml diff --git a/public/svgs/wireguard.svg b/public/svgs/wireguard.svg new file mode 100644 index 000000000..81823b3eb --- /dev/null +++ b/public/svgs/wireguard.svg @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/templates/compose/wireguard-easy.yaml b/templates/compose/wireguard-easy.yaml new file mode 100644 index 000000000..56d3c89ce --- /dev/null +++ b/templates/compose/wireguard-easy.yaml @@ -0,0 +1,27 @@ +# documentation: https://github.com/wg-easy/wg-easy +# slogan: The easiest way to run WireGuard VPN + Web-based Admin UI. +# tags: wireguard,vpn,web,admin +# logo: svgs/wireguard.svg +# port: 8000 +services: + wg-easy: + image: ghcr.io/wg-easy/wg-easy + container_name: wg-easy + environment: + - LANG=en + - WG_HOST=$SERVICE_FQDN_WIREGUARDEASY + - PASSWORD_HASH=$2y$10$2wrW.nOpZLjGSGaiocD8xOo6uLCa.CebkaqswyAz.hSd5PYKm2WVu + - PORT=8000 + - WG_PORT=51820 + volumes: + - ~/.wg-easy:/etc/wireguard + ports: + - "51820:51820/udp" + - "8000:8000/tcp" + cap_add: + - NET_ADMIN + - SYS_MODULE + sysctls: + - net.ipv4.conf.all.src_valid_mark=1 + - net.ipv4.ip_forward=1 + restart: unless-stopped From 1c1689d3288b973ce9a505edadc6e47245829454 Mon Sep 17 00:00:00 2001 From: "yokowasis@host2" Date: Sun, 20 Oct 2024 00:44:03 +0000 Subject: [PATCH 15/57] jupyterlab tempalte --- public/svgs/jupyterlab.svg | 90 +++++++++++++++++++++++++++++++ templates/compose/jupyterlab.yaml | 21 ++++++++ 2 files changed, 111 insertions(+) create mode 100644 public/svgs/jupyterlab.svg create mode 100644 templates/compose/jupyterlab.yaml diff --git a/public/svgs/jupyterlab.svg b/public/svgs/jupyterlab.svg new file mode 100644 index 000000000..ab2550874 --- /dev/null +++ b/public/svgs/jupyterlab.svg @@ -0,0 +1,90 @@ + +Group.svg +Created using Figma 0.90 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/compose/jupyterlab.yaml b/templates/compose/jupyterlab.yaml new file mode 100644 index 000000000..360067919 --- /dev/null +++ b/templates/compose/jupyterlab.yaml @@ -0,0 +1,21 @@ +# documentation: https://jupyterlab.readthedocs.io/en/latest/ +# slogan: JupyterLab Notebook with C++ (xeus-cling) and Javascript (Deno) Kernel +# tags: jupyter,notebook,python,cpp,deno,jupyterlab +# logo: svgs/jupyterlab.svg +# port: 8008 + +version: '3.8' + +services: + jupyterlab: + image: yokowasis/jupyterlab + expose: + - 8008 + environment: + - SERVICE_FQDN_JUPYTERLAB + - PORT=${PORT:-8008} + - TOKEN=${SERVICE_PASSWORD_TOKEN} + - CONDA_PACKAGES=${CONDA_PACKAGES:-pandas numpy matplotlib seaborn scikit-learn pytorch nltk openpyxl category_encoders scikit-learn tensorflow spacy} + - PIP_PACKAGES=${PIP_PACKAGES:-sastrawi} + volumes: + - jupyterlab_data:/home/mambauser/data From c3c1671b6cd07cdd3e222ca9d86f12695817e9fa Mon Sep 17 00:00:00 2001 From: "Alexander G." Date: Sun, 20 Oct 2024 14:24:13 +0300 Subject: [PATCH 16/57] Adding healthcheck to trigger --- templates/compose/trigger.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/compose/trigger.yaml b/templates/compose/trigger.yaml index e33459535..818f54eb4 100644 --- a/templates/compose/trigger.yaml +++ b/templates/compose/trigger.yaml @@ -62,9 +62,10 @@ services: electric: condition: service_healthy healthcheck: - test: - - CMD-SHELL - - pwd + test: "timeout 10s bash -c ':> /dev/tcp/127.0.0.1/3000' || exit 1" + interval: 10s + timeout: 5s + retries: 5 electric: image: electricsql/electric restart: always From d7852c334e007b270dbd19d2b047840c964c5c1d Mon Sep 17 00:00:00 2001 From: JakeKydd Date: Sun, 20 Oct 2024 14:22:00 +0200 Subject: [PATCH 17/57] fix: volume --- templates/compose/wireguard-easy.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/templates/compose/wireguard-easy.yaml b/templates/compose/wireguard-easy.yaml index 56d3c89ce..f0ada4dcf 100644 --- a/templates/compose/wireguard-easy.yaml +++ b/templates/compose/wireguard-easy.yaml @@ -6,15 +6,14 @@ services: wg-easy: image: ghcr.io/wg-easy/wg-easy - container_name: wg-easy environment: + - SERVICE_FQDN_WIREGUARDEASY_8000 - LANG=en - WG_HOST=$SERVICE_FQDN_WIREGUARDEASY - - PASSWORD_HASH=$2y$10$2wrW.nOpZLjGSGaiocD8xOo6uLCa.CebkaqswyAz.hSd5PYKm2WVu - PORT=8000 - WG_PORT=51820 volumes: - - ~/.wg-easy:/etc/wireguard + - wg-easy:/etc/wireguard ports: - "51820:51820/udp" - "8000:8000/tcp" From f0d5639956475516bd7c0bb85da22d4039747fdd Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 21 Oct 2024 22:40:43 +0200 Subject: [PATCH 18/57] fancier notifications --- app/Console/Commands/Emails.php | 18 ------ app/Models/InstanceSettings.php | 13 +++++ .../Application/DeploymentFailed.php | 28 ++++++++-- .../Application/DeploymentSuccess.php | 29 ++++++---- .../Application/StatusChanged.php | 6 +- .../Container/ContainerRestarted.php | 8 ++- .../Container/ContainerStopped.php | 12 +++- app/Notifications/Database/BackupFailed.php | 6 +- app/Notifications/Database/BackupSuccess.php | 6 +- app/Notifications/Database/DailyBackup.php | 55 ------------------- app/Notifications/Dto/DiscordMessage.php | 12 +++- .../ScheduledTask/TaskFailed.php | 8 ++- app/Notifications/Server/DockerCleanup.php | 2 +- app/Notifications/Server/ForceDisabled.php | 6 +- app/Notifications/Server/ForceEnabled.php | 4 +- app/Notifications/Server/HighDiskUsage.php | 6 +- app/Notifications/Server/Revived.php | 2 +- app/Notifications/Server/Unreachable.php | 4 +- app/Notifications/Test.php | 6 +- 19 files changed, 106 insertions(+), 125 deletions(-) delete mode 100644 app/Notifications/Database/DailyBackup.php diff --git a/app/Console/Commands/Emails.php b/app/Console/Commands/Emails.php index 36722564c..ded729114 100644 --- a/app/Console/Commands/Emails.php +++ b/app/Console/Commands/Emails.php @@ -15,7 +15,6 @@ use App\Notifications\Application\DeploymentSuccess; use App\Notifications\Application\StatusChanged; use App\Notifications\Database\BackupFailed; use App\Notifications\Database\BackupSuccess; -use App\Notifications\Database\DailyBackup; use App\Notifications\Test; use Exception; use Illuminate\Console\Command; @@ -121,23 +120,6 @@ class Emails extends Command $this->mail = (new Test)->toMail(); $this->sendEmail(); break; - case 'database-backup-statuses-daily': - $scheduled_backups = ScheduledDatabaseBackup::all(); - $databases = collect(); - foreach ($scheduled_backups as $scheduled_backup) { - $last_days_backups = $scheduled_backup->get_last_days_backup_status(); - if ($last_days_backups->isEmpty()) { - continue; - } - $failed = $last_days_backups->where('status', 'failed'); - $database = $scheduled_backup->database; - $databases->put($database->name, [ - 'failed_count' => $failed->count(), - ]); - } - $this->mail = (new DailyBackup($databases))->toMail(); - $this->sendEmail(); - break; case 'application-deployment-success-daily': $applications = Application::all(); foreach ($applications as $application) { diff --git a/app/Models/InstanceSettings.php b/app/Models/InstanceSettings.php index 8ac6e892a..339daed2a 100644 --- a/app/Models/InstanceSettings.php +++ b/app/Models/InstanceSettings.php @@ -101,4 +101,17 @@ class InstanceSettings extends Model implements SendsEmail return "[{$instanceName}]"; } + + // public function helperVersion(): Attribute + // { + // return Attribute::make( + // get: function ($value) { + // if (isDev()) { + // return 'latest'; + // } + + // return $value; + // } + // ); + // } } diff --git a/app/Notifications/Application/DeploymentFailed.php b/app/Notifications/Application/DeploymentFailed.php index b255cc667..242980e00 100644 --- a/app/Notifications/Application/DeploymentFailed.php +++ b/app/Notifications/Application/DeploymentFailed.php @@ -77,22 +77,38 @@ class DeploymentFailed extends Notification implements ShouldQueue { if ($this->preview) { $message = new DiscordMessage( - title: 'Coolify: Deployment failed of pull request #'.$this->preview->pull_request_id.' of '.$this->application_name, - description: 'Check in the link below', + title: ':cross_mark: Deployment failed', + description: 'Pull request: '.$this->preview->pull_request_id, color: DiscordMessage::errorColor(), isCritical: true, ); - $message->addField('Deployment Logs', '[Here]('.$this->deployment_url.')'); + $message->addField('Project', data_get($this->application, 'environment.project.name'), true); + $message->addField('Environment', $this->environment_name, true); + $message->addField('Name', $this->application_name, true); + + $message->addField('Deployment Logs', '[Link]('.$this->deployment_url.')'); + if ($this->fqdn) { + $message->addField('Domain', $this->fqdn, true); + } } else { + if ($this->fqdn) { + $description = '[Open application]('.$this->fqdn.')'; + } else { + $description = ''; + } $message = new DiscordMessage( - title: 'Coolify: Deployment failed of '.$this->application_name, - description: 'Check in the link below', + title: ':cross_mark: Deployment failed', + description: $description, color: DiscordMessage::errorColor(), isCritical: true, ); - $message->addField('Deployment Logs', '[Here]('.$this->deployment_url.')'); + $message->addField('Project', data_get($this->application, 'environment.project.name'), true); + $message->addField('Environment', $this->environment_name, true); + $message->addField('Name', $this->application_name, true); + + $message->addField('Deployment Logs', '[Link]('.$this->deployment_url.')'); } return $message; diff --git a/app/Notifications/Application/DeploymentSuccess.php b/app/Notifications/Application/DeploymentSuccess.php index 96ec2ce82..a2674ad76 100644 --- a/app/Notifications/Application/DeploymentSuccess.php +++ b/app/Notifications/Application/DeploymentSuccess.php @@ -83,28 +83,35 @@ class DeploymentSuccess extends Notification implements ShouldQueue { if ($this->preview) { $message = new DiscordMessage( - title: "Coolify: New PR{$this->preview->pull_request_id} version successfully deployed of {$this->application_name}", - description: 'Check in the links below.', + title: ':white_check_mark: Preview deployment successful', + description: 'Pull request: '.$this->preview->pull_request_id, color: DiscordMessage::successColor(), ); if ($this->preview->fqdn) { - $message->addField('Open Application', '[Here]('.$this->preview->fqdn.')'); + $message->addField('Application', '[Link]('.$this->preview->fqdn.')'); } - $message->addField('Deployment logs', '[Here]('.$this->deployment_url.')'); + $message->addField('Project', data_get($this->application, 'environment.project.name'), true); + $message->addField('Environment', $this->environment_name, true); + $message->addField('Name', $this->application_name, true); + $message->addField('Deployment logs', '[Link]('.$this->deployment_url.')'); } else { + if ($this->fqdn) { + $description = '[Open application]('.$this->fqdn.')'; + } else { + $description = ''; + } $message = new DiscordMessage( - title: "Coolify: New version successfully deployed of {$this->application_name}", - description: 'Check in the links below.', + title: ':white_check_mark: New version successfully deployed', + description: $description, color: DiscordMessage::successColor(), ); + $message->addField('Project', data_get($this->application, 'environment.project.name'), true); + $message->addField('Environment', $this->environment_name, true); + $message->addField('Name', $this->application_name, true); - if ($this->fqdn) { - $message->addField('Open Application', '[Here]('.$this->fqdn.')'); - } - - $message->addField('Deployment logs', '[Here]('.$this->deployment_url.')'); + $message->addField('Deployment logs', '[Link]('.$this->deployment_url.')'); } return $message; diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index abc93a3a4..a080fcabe 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -59,14 +59,12 @@ class StatusChanged extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: "Coolify: {$this->resource_name} has been stopped", - description: 'Check the application in Coolify', + title: ':cross_mark: Application stopped', + description: '[Open Application in Coolify]('.$this->resource_url.')', color: DiscordMessage::errorColor(), isCritical: true, ); - $message->addField('Link', '[Open Application in Coolify]('.$this->resource_url.')'); - return $message; } diff --git a/app/Notifications/Container/ContainerRestarted.php b/app/Notifications/Container/ContainerRestarted.php index 49c2cecf0..182a1f5fc 100644 --- a/app/Notifications/Container/ContainerRestarted.php +++ b/app/Notifications/Container/ContainerRestarted.php @@ -38,11 +38,15 @@ class ContainerRestarted extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: "Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}", - description: 'Please check the output below for more information.', + title: ':warning: Resource restarted', + description: "{$this->name} has been restarted automatically on {$this->server->name}.", color: DiscordMessage::infoColor(), ); + if ($this->url) { + $message->addField('Resource', '[Link]('.$this->url.')'); + } + return $message; } diff --git a/app/Notifications/Container/ContainerStopped.php b/app/Notifications/Container/ContainerStopped.php index d8ed2316b..33a55c65a 100644 --- a/app/Notifications/Container/ContainerStopped.php +++ b/app/Notifications/Container/ContainerStopped.php @@ -37,11 +37,17 @@ class ContainerStopped extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { - return new DiscordMessage( - title: "Coolify: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}", - description: 'Please check the output below for more information.', + $message = new DiscordMessage( + title: ':cross_mark: Resource stopped', + description: "{$this->name} has been stopped unexpectedly on {$this->server->name}.", color: DiscordMessage::errorColor(), ); + + if ($this->url) { + $message->addField('Resource', '[Link]('.$this->url.')'); + } + + return $message; } public function toTelegram(): array diff --git a/app/Notifications/Database/BackupFailed.php b/app/Notifications/Database/BackupFailed.php index ef6128c5f..8e2733339 100644 --- a/app/Notifications/Database/BackupFailed.php +++ b/app/Notifications/Database/BackupFailed.php @@ -49,13 +49,13 @@ class BackupFailed extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: "Coolify: Database backup for {$this->name} (db:{$this->database_name}) has FAILED.", - description: 'Please check the output below for more information.', + title: ':cross_mark: Database backup failed', + description: "Database backup for {$this->name} (db:{$this->database_name}) has FAILED.", color: DiscordMessage::errorColor(), isCritical: true, ); - $message->addField('Frequency', $this->frequency); + $message->addField('Frequency', $this->frequency, true); $message->addField('Output', $this->output); return $message; diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php index fa9eb616c..4bd6b97b8 100644 --- a/app/Notifications/Database/BackupSuccess.php +++ b/app/Notifications/Database/BackupSuccess.php @@ -48,12 +48,12 @@ class BackupSuccess extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: "Coolify: Database backup for {$this->name} (db:{$this->database_name}) was successful.", - description: 'Please check the output below for more information.', + title: ':white_check_mark: Database backup successful', + description: "Database backup for {$this->name} (db:{$this->database_name}) was successful.", color: DiscordMessage::successColor(), ); - $message->addField('Frequency', $this->frequency); + $message->addField('Frequency', $this->frequency, true); return $message; } diff --git a/app/Notifications/Database/DailyBackup.php b/app/Notifications/Database/DailyBackup.php deleted file mode 100644 index b53a56903..000000000 --- a/app/Notifications/Database/DailyBackup.php +++ /dev/null @@ -1,55 +0,0 @@ -subject('Coolify: Daily backup statuses'); - $mail->view('emails.daily-backup', [ - 'databases' => $this->databases, - ]); - - return $mail; - } - - public function toDiscord(): DiscordMessage - { - return new DiscordMessage( - title: 'Coolify: Daily backup statuses', - description: 'Nothing to report.', - color: DiscordMessage::infoColor(), - ); // todo: is this necessary notification? what is the purpose of this notification? - } - - public function toTelegram(): array - { - $message = 'Coolify: Daily backup statuses'; - - return [ - 'message' => $message, - ]; - } -} diff --git a/app/Notifications/Dto/DiscordMessage.php b/app/Notifications/Dto/DiscordMessage.php index 0d0028f56..856753dca 100644 --- a/app/Notifications/Dto/DiscordMessage.php +++ b/app/Notifications/Dto/DiscordMessage.php @@ -33,11 +33,12 @@ class DiscordMessage return hexdec('4f545c'); } - public function addField(string $name, string $value): self + public function addField(string $name, string $value, bool $inline = false): self { $this->fields[] = [ 'name' => $name, 'value' => $value, + 'inline' => $inline, ]; return $this; @@ -45,6 +46,10 @@ class DiscordMessage public function toPayload(): array { + $footerText = 'Coolify v'.config('version'); + if (isCloud()) { + $footerText = 'Coolify Cloud'; + } $payload = [ 'embeds' => [ [ @@ -52,10 +57,12 @@ class DiscordMessage 'description' => $this->description, 'color' => $this->color, 'fields' => $this->addTimestampToFields($this->fields), + 'footer' => [ + 'text' => $footerText, + ], ], ], ]; - if ($this->isCritical) { $payload['content'] = '@here'; } @@ -68,6 +75,7 @@ class DiscordMessage $fields[] = [ 'name' => 'Time', 'value' => 'timestamp.':R>', + 'inline' => true, ]; return $fields; diff --git a/app/Notifications/ScheduledTask/TaskFailed.php b/app/Notifications/ScheduledTask/TaskFailed.php index aac665fb6..2cc33f2ba 100644 --- a/app/Notifications/ScheduledTask/TaskFailed.php +++ b/app/Notifications/ScheduledTask/TaskFailed.php @@ -50,12 +50,14 @@ class TaskFailed extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: "Coolify: Scheduled task ({$this->task->name}) failed.", - description: "Output: {$this->output}", + title: ':cross_mark: Scheduled task failed', + description: "Scheduled task ({$this->task->name}) failed.", color: DiscordMessage::errorColor(), ); - $message->addField('Link', '[Open task in Coolify]('.$this->url.')'); + if ($this->url) { + $message->addField('Scheduled task', '[Link]('.$this->url.')'); + } return $message; } diff --git a/app/Notifications/Server/DockerCleanup.php b/app/Notifications/Server/DockerCleanup.php index 68d35b15e..7ea1b84c2 100644 --- a/app/Notifications/Server/DockerCleanup.php +++ b/app/Notifications/Server/DockerCleanup.php @@ -53,7 +53,7 @@ class DockerCleanup extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { return new DiscordMessage( - title: "Coolify: Server '{$this->server->name}' cleanup job done!", + title: ':white_check_mark: Server cleanup job done', description: $this->message, color: DiscordMessage::successColor(), ); diff --git a/app/Notifications/Server/ForceDisabled.php b/app/Notifications/Server/ForceDisabled.php index a02228dc3..a26c803ee 100644 --- a/app/Notifications/Server/ForceDisabled.php +++ b/app/Notifications/Server/ForceDisabled.php @@ -54,12 +54,12 @@ class ForceDisabled extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: "Coolify: Server ({$this->server->name}) disabled because it is not paid!", - description: 'All automations and integrations are stopped.', + title: ':cross_mark: Server disabled', + description: "Server ({$this->server->name}) disabled because it is not paid!", color: DiscordMessage::errorColor(), ); - $message->addField('Link', 'Please update your subscription to enable the server again [here](https://app.coolify.io/subscriptions).'); + $message->addField('Please update your subscription to enable the server again!', '[Link](https://app.coolify.io/subscriptions)'); return $message; } diff --git a/app/Notifications/Server/ForceEnabled.php b/app/Notifications/Server/ForceEnabled.php index c5c3e42b3..65b65a10c 100644 --- a/app/Notifications/Server/ForceEnabled.php +++ b/app/Notifications/Server/ForceEnabled.php @@ -54,8 +54,8 @@ class ForceEnabled extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { return new DiscordMessage( - title: "Coolify: Server '{$this->server->name}' enabled again!", - description: 'All automations and integrations are started.', + title: ':white_check_mark: Server enabled', + description: "Server '{$this->server->name}' enabled again!", color: DiscordMessage::successColor(), ); } diff --git a/app/Notifications/Server/HighDiskUsage.php b/app/Notifications/Server/HighDiskUsage.php index c91b8c266..54fd7b160 100644 --- a/app/Notifications/Server/HighDiskUsage.php +++ b/app/Notifications/Server/HighDiskUsage.php @@ -56,14 +56,14 @@ class HighDiskUsage extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: "Coolify: Server '{$this->server->name}' high disk usage detected!", - description: 'Please cleanup your disk to prevent data-loss.', + title: ':cross_mark: High disk usage detected', + description: "Server '{$this->server->name}' high disk usage detected!", color: DiscordMessage::errorColor(), ); $message->addField('Disk usage', "{$this->disk_usage}%"); $message->addField('Threshold', "{$this->docker_cleanup_threshold}%"); - $message->addField('Link', 'Here are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.'); + $message->addField('Tips', '[Link](https://coolify.io/docs/knowledge-base/server/automated-cleanup)'); return $message; } diff --git a/app/Notifications/Server/Revived.php b/app/Notifications/Server/Revived.php index c3a3f389a..8d1ceeaef 100644 --- a/app/Notifications/Server/Revived.php +++ b/app/Notifications/Server/Revived.php @@ -76,7 +76,7 @@ class Revived extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { return new DiscordMessage( - title: "Coolify: Server '{$this->server->name}' revived.", + title: ":white_check_mark: Server '{$this->server->name}' revived", description: 'All automations & integrations are turned on again!', color: DiscordMessage::successColor(), ); diff --git a/app/Notifications/Server/Unreachable.php b/app/Notifications/Server/Unreachable.php index 7e56123e4..65ea6a2ff 100644 --- a/app/Notifications/Server/Unreachable.php +++ b/app/Notifications/Server/Unreachable.php @@ -67,8 +67,8 @@ class Unreachable extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: "Coolify: Your server '{$this->server->name}' is unreachable.", - description: 'All automations & integrations are turned off! Please check your server!', + title: ':cross_mark: Server unreachable', + description: "Your server '{$this->server->name}' is unreachable.", color: DiscordMessage::errorColor(), ); diff --git a/app/Notifications/Test.php b/app/Notifications/Test.php index 641a99fdb..0446f8e52 100644 --- a/app/Notifications/Test.php +++ b/app/Notifications/Test.php @@ -33,12 +33,12 @@ class Test extends Notification implements ShouldQueue public function toDiscord(): DiscordMessage { $message = new DiscordMessage( - title: 'Coolify: This is a test Discord notification from Coolify.', - description: 'This is a test Discord notification from Coolify.', + title: ':white_check_mark: Test Success', + description: 'This is a test Discord notification from Coolify. :cross_mark: :warning: :information_source:', color: DiscordMessage::successColor(), ); - $message->addField('Link', '[Go to your dashboard]('.base_url().')'); + $message->addField(name: 'Dashboard', value: '[Link]('.base_url().')', inline: true); return $message; } From 3e729ee92840be5dbc3dc4585ef5825ea2d15c5a Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 21 Oct 2024 22:57:00 +0200 Subject: [PATCH 19/57] fix: metrics for dbs --- app/Models/StandaloneClickhouse.php | 59 +++++++++------ app/Models/StandaloneDragonfly.php | 59 +++++++++------ app/Models/StandaloneKeydb.php | 59 +++++++++------ app/Models/StandaloneMariadb.php | 59 +++++++++------ app/Models/StandaloneMongodb.php | 59 +++++++++------ app/Models/StandaloneMysql.php | 59 +++++++++------ app/Models/StandalonePostgresql.php | 73 +++++++++++-------- app/Models/StandaloneRedis.php | 59 +++++++++------ .../livewire/project/shared/metrics.blade.php | 4 +- 9 files changed, 305 insertions(+), 185 deletions(-) diff --git a/app/Models/StandaloneClickhouse.php b/app/Models/StandaloneClickhouse.php index 6274f51b2..c9d3ea031 100644 --- a/app/Models/StandaloneClickhouse.php +++ b/app/Models/StandaloneClickhouse.php @@ -266,33 +266,48 @@ class StandaloneClickhouse extends BaseModel return $this->morphMany(ScheduledDatabaseBackup::class, 'database'); } - public function getMetrics(int $mins = 5) + public function getCpuMetrics(int $mins = 5) { $server = $this->destination->server; $container_name = $this->uuid; - if ($server->isMetricsEnabled()) { - $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); - if (str($metrics)->contains('error')) { - $error = json_decode($metrics, true); - $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { - $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; - } - throw new \Exception($error); + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } - $metrics = str($metrics)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($metrics)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 2); - - return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage]; - }); - }); - - return $parsedCollection->toArray(); + throw new \Exception($error); } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['percent']]; + }); + + return $parsedCollection->toArray(); + } + + public function getMemoryMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['used']]; + }); + + return $parsedCollection->toArray(); } public function isBackupSolutionAvailable() diff --git a/app/Models/StandaloneDragonfly.php b/app/Models/StandaloneDragonfly.php index 3555e7afd..2bde51080 100644 --- a/app/Models/StandaloneDragonfly.php +++ b/app/Models/StandaloneDragonfly.php @@ -266,33 +266,48 @@ class StandaloneDragonfly extends BaseModel return $this->morphMany(ScheduledDatabaseBackup::class, 'database'); } - public function getMetrics(int $mins = 5) + public function getCpuMetrics(int $mins = 5) { $server = $this->destination->server; $container_name = $this->uuid; - if ($server->isMetricsEnabled()) { - $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); - if (str($metrics)->contains('error')) { - $error = json_decode($metrics, true); - $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { - $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; - } - throw new \Exception($error); + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } - $metrics = str($metrics)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($metrics)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 2); - - return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage]; - }); - }); - - return $parsedCollection->toArray(); + throw new \Exception($error); } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['percent']]; + }); + + return $parsedCollection->toArray(); + } + + public function getMemoryMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['used']]; + }); + + return $parsedCollection->toArray(); } public function isBackupSolutionAvailable() diff --git a/app/Models/StandaloneKeydb.php b/app/Models/StandaloneKeydb.php index 4725ca533..fbee9789a 100644 --- a/app/Models/StandaloneKeydb.php +++ b/app/Models/StandaloneKeydb.php @@ -266,33 +266,48 @@ class StandaloneKeydb extends BaseModel return $this->morphMany(ScheduledDatabaseBackup::class, 'database'); } - public function getMetrics(int $mins = 5) + public function getCpuMetrics(int $mins = 5) { $server = $this->destination->server; $container_name = $this->uuid; - if ($server->isMetricsEnabled()) { - $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); - if (str($metrics)->contains('error')) { - $error = json_decode($metrics, true); - $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { - $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; - } - throw new \Exception($error); + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } - $metrics = str($metrics)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($metrics)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 2); - - return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage]; - }); - }); - - return $parsedCollection->toArray(); + throw new \Exception($error); } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['percent']]; + }); + + return $parsedCollection->toArray(); + } + + public function getMemoryMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['used']]; + }); + + return $parsedCollection->toArray(); } public function isBackupSolutionAvailable() diff --git a/app/Models/StandaloneMariadb.php b/app/Models/StandaloneMariadb.php index 8f1a2c1ee..00f635faf 100644 --- a/app/Models/StandaloneMariadb.php +++ b/app/Models/StandaloneMariadb.php @@ -266,33 +266,48 @@ class StandaloneMariadb extends BaseModel return $this->morphMany(ScheduledDatabaseBackup::class, 'database'); } - public function getMetrics(int $mins = 5) + public function getCpuMetrics(int $mins = 5) { $server = $this->destination->server; $container_name = $this->uuid; - if ($server->isMetricsEnabled()) { - $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); - if (str($metrics)->contains('error')) { - $error = json_decode($metrics, true); - $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { - $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; - } - throw new \Exception($error); + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } - $metrics = str($metrics)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($metrics)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 2); - - return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage]; - }); - }); - - return $parsedCollection->toArray(); + throw new \Exception($error); } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['percent']]; + }); + + return $parsedCollection->toArray(); + } + + public function getMemoryMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['used']]; + }); + + return $parsedCollection->toArray(); } public function isBackupSolutionAvailable() diff --git a/app/Models/StandaloneMongodb.php b/app/Models/StandaloneMongodb.php index 41b2ce9eb..c225011c5 100644 --- a/app/Models/StandaloneMongodb.php +++ b/app/Models/StandaloneMongodb.php @@ -286,33 +286,48 @@ class StandaloneMongodb extends BaseModel return $this->morphMany(ScheduledDatabaseBackup::class, 'database'); } - public function getMetrics(int $mins = 5) + public function getCpuMetrics(int $mins = 5) { $server = $this->destination->server; $container_name = $this->uuid; - if ($server->isMetricsEnabled()) { - $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); - if (str($metrics)->contains('error')) { - $error = json_decode($metrics, true); - $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { - $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; - } - throw new \Exception($error); + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } - $metrics = str($metrics)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($metrics)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 2); - - return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage]; - }); - }); - - return $parsedCollection->toArray(); + throw new \Exception($error); } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['percent']]; + }); + + return $parsedCollection->toArray(); + } + + public function getMemoryMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['used']]; + }); + + return $parsedCollection->toArray(); } public function isBackupSolutionAvailable() diff --git a/app/Models/StandaloneMysql.php b/app/Models/StandaloneMysql.php index da2ac070f..52725ffc7 100644 --- a/app/Models/StandaloneMysql.php +++ b/app/Models/StandaloneMysql.php @@ -267,33 +267,48 @@ class StandaloneMysql extends BaseModel return $this->morphMany(ScheduledDatabaseBackup::class, 'database'); } - public function getMetrics(int $mins = 5) + public function getCpuMetrics(int $mins = 5) { $server = $this->destination->server; $container_name = $this->uuid; - if ($server->isMetricsEnabled()) { - $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); - if (str($metrics)->contains('error')) { - $error = json_decode($metrics, true); - $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { - $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; - } - throw new \Exception($error); + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } - $metrics = str($metrics)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($metrics)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 2); - - return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage]; - }); - }); - - return $parsedCollection->toArray(); + throw new \Exception($error); } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['percent']]; + }); + + return $parsedCollection->toArray(); + } + + public function getMemoryMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['used']]; + }); + + return $parsedCollection->toArray(); } public function isBackupSolutionAvailable() diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index e0f42269d..ccab7d658 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -268,37 +268,52 @@ class StandalonePostgresql extends BaseModel return $this->morphMany(ScheduledDatabaseBackup::class, 'database'); } - public function getMetrics(int $mins = 5) - { - $server = $this->destination->server; - $container_name = $this->uuid; - if ($server->isMetricsEnabled()) { - $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); - if (str($metrics)->contains('error')) { - $error = json_decode($metrics, true); - $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { - $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; - } - throw new \Exception($error); - } - $metrics = str($metrics)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($metrics)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 2); - - return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage]; - }); - }); - - return $parsedCollection->toArray(); - } - } - public function isBackupSolutionAvailable() { return true; } + + public function getCpuMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['percent']]; + }); + + return $parsedCollection->toArray(); + } + + public function getMemoryMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['used']]; + }); + + return $parsedCollection->toArray(); + } } diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index 097d6b0de..5b6993b9a 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -277,33 +277,48 @@ class StandaloneRedis extends BaseModel return $this->morphMany(ScheduledDatabaseBackup::class, 'database'); } - public function getMetrics(int $mins = 5) + public function getCpuMetrics(int $mins = 5) { $server = $this->destination->server; $container_name = $this->uuid; - if ($server->isMetricsEnabled()) { - $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); - if (str($metrics)->contains('error')) { - $error = json_decode($metrics, true); - $error = data_get($error, 'error', 'Something is not okay, are you okay?'); - if ($error == 'Unauthorized') { - $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; - } - throw new \Exception($error); + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; } - $metrics = str($metrics)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($metrics)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 2); - - return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage]; - }); - }); - - return $parsedCollection->toArray(); + throw new \Exception($error); } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['percent']]; + }); + + return $parsedCollection->toArray(); + } + + public function getMemoryMetrics(int $mins = 5) + { + $server = $this->destination->server; + $container_name = $this->uuid; + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false); + if (str($metrics)->contains('error')) { + $error = json_decode($metrics, true); + $error = data_get($error, 'error', 'Something is not okay, are you okay?'); + if ($error == 'Unauthorized') { + $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.'; + } + throw new \Exception($error); + } + $metrics = json_decode($metrics, true); + $parsedCollection = collect($metrics)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['used']]; + }); + + return $parsedCollection->toArray(); } public function isBackupSolutionAvailable() diff --git a/resources/views/livewire/project/shared/metrics.blade.php b/resources/views/livewire/project/shared/metrics.blade.php index ce5481ac4..cfe83ded6 100644 --- a/resources/views/livewire/project/shared/metrics.blade.php +++ b/resources/views/livewire/project/shared/metrics.blade.php @@ -5,8 +5,8 @@
Basic metrics for your container.
@if ($resource->getMorphClass() === 'App\Models\Application' && $resource->build_pack === 'dockercompose')
Metrics are not available for Docker Compose applications yet!
- @elseif(!$resource->destination->server->isSentinelEnabled()) -
Metrics are only available for servers with Sentinel enabled!
+ @elseif(!$resource->destination->server->isMetricsEnabled()) +
Metrics are only available for servers with Sentinel & Metrics enabled!
Go to Server settings to enable From e8854c3101085342627f69871ed7c5a311690786 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 22 Oct 2024 08:31:53 +0200 Subject: [PATCH 20/57] fix: sentinel start fixed --- app/Models/ServerSetting.php | 9 ++------- config/debugbar.php | 1 + resources/views/livewire/server/form.blade.php | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index b1ed92d95..d98647fce 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -64,12 +64,7 @@ class ServerSetting extends Model $setting->generateSentinelToken(save: false); } if (str($setting->sentinel_custom_url)->isEmpty()) { - $url = $setting->generateSentinelUrl(save: false); - if (str($url)->isEmpty()) { - $setting->is_sentinel_enabled = false; - } else { - $setting->is_sentinel_enabled = true; - } + $setting->generateSentinelUrl(save: false); } } catch (\Throwable $e) { loggy('Error creating server setting: '.$e->getMessage()); @@ -89,7 +84,7 @@ class ServerSetting extends Model $this->save(); } - return $encrypted; + return $token; } public function generateSentinelUrl(bool $save = true) diff --git a/config/debugbar.php b/config/debugbar.php index eae406ba7..daeea96b6 100644 --- a/config/debugbar.php +++ b/config/debugbar.php @@ -18,6 +18,7 @@ return [ 'except' => [ 'telescope*', 'horizon*', + 'api*', ], /* diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index f75b9762f..a184a308a 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -176,7 +176,7 @@
- + @if ($server->isSentinelEnabled()) From 028a0bf513c905fdb8986adecd47f93685399680 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 22 Oct 2024 10:45:12 +0200 Subject: [PATCH 21/57] fix: Validate sentinel custom URL when enabling sentinel --- app/Livewire/Server/Form.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index a2f04074a..5687bbf39 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -136,7 +136,6 @@ class Form extends Component public function updatedServerSettingsIsSentinelEnabled($value) { - $this->validate(); $this->validate([ 'server.settings.sentinel_custom_url' => 'required|url', ]); From 388929be302c14dfabf73d3bfdb23f0aa0f7dec5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 22 Oct 2024 10:58:23 +0200 Subject: [PATCH 22/57] Refactor status component to use title instead of lastDeploymentInfo --- resources/views/components/resources/breadcrumbs.blade.php | 2 +- resources/views/components/status/index.blade.php | 6 +++--- resources/views/components/status/restarting.blade.php | 4 ++-- resources/views/components/status/running.blade.php | 4 ++-- .../views/livewire/project/application/heading.blade.php | 2 +- resources/views/livewire/server/form.blade.php | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/resources/views/components/resources/breadcrumbs.blade.php b/resources/views/components/resources/breadcrumbs.blade.php index ea12495a1..f9733f63a 100644 --- a/resources/views/components/resources/breadcrumbs.blade.php +++ b/resources/views/components/resources/breadcrumbs.blade.php @@ -44,7 +44,7 @@ @if ($resource->getMorphClass() == 'App\Models\Service') @else - + @endif diff --git a/resources/views/components/status/index.blade.php b/resources/views/components/status/index.blade.php index 0ef652897..fcc2688e1 100644 --- a/resources/views/components/status/index.blade.php +++ b/resources/views/components/status/index.blade.php @@ -1,14 +1,14 @@ @props([ - 'lastDeploymentInfo' => null, + 'title' => null, 'lastDeploymentLink' => null, 'resource' => null, ]) @if (str($resource->status)->startsWith('running')) - + @elseif(str($resource->status)->startsWith('restarting') || str($resource->status)->startsWith('starting') || str($resource->status)->startsWith('degraded')) - + @else @endif diff --git a/resources/views/components/status/restarting.blade.php b/resources/views/components/status/restarting.blade.php index c9b6c2127..4314efa8b 100644 --- a/resources/views/components/status/restarting.blade.php +++ b/resources/views/components/status/restarting.blade.php @@ -1,6 +1,6 @@ @props([ 'status' => 'Restarting', - 'lastDeploymentInfo' => null, + 'title' => null, 'lastDeploymentLink' => null, 'noLoading' => false, ]) @@ -10,7 +10,7 @@ @endif
-
+
@if ($lastDeploymentLink) {{ str($status)->before(':')->headline() }} diff --git a/resources/views/components/status/running.blade.php b/resources/views/components/status/running.blade.php index 8bb45b884..0e0f08fa4 100644 --- a/resources/views/components/status/running.blade.php +++ b/resources/views/components/status/running.blade.php @@ -1,6 +1,6 @@ @props([ 'status' => 'Running', - 'lastDeploymentInfo' => null, + 'title' => null, 'lastDeploymentLink' => null, 'noLoading' => false, ]) @@ -10,7 +10,7 @@ @endif
-
+
@if ($lastDeploymentLink) {{ str($status)->before(':')->headline() }} diff --git a/resources/views/livewire/project/application/heading.blade.php b/resources/views/livewire/project/application/heading.blade.php index 04b65eef9..8f3d1d15c 100644 --- a/resources/views/livewire/project/application/heading.blade.php +++ b/resources/views/livewire/project/application/heading.blade.php @@ -1,5 +1,5 @@