From 7caf70941381ffe6320875c7c9d147eb08254a37 Mon Sep 17 00:00:00 2001 From: Jere Salonen Date: Tue, 23 Apr 2024 19:59:16 +0200 Subject: [PATCH 001/120] feat: Add EdgeDB edgedb.svg includes EdgeDB logo and add edgedb.yaml the configuration for edgedb and postgres services. Commit includes setting environment variables, volumes, health checks, and ports. --- public/svgs/edgedb.svg | 3 +++ templates/compose/edgedb.yaml | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 public/svgs/edgedb.svg create mode 100644 templates/compose/edgedb.yaml diff --git a/public/svgs/edgedb.svg b/public/svgs/edgedb.svg new file mode 100644 index 000000000..a906f7f7e --- /dev/null +++ b/public/svgs/edgedb.svg @@ -0,0 +1,3 @@ + + + diff --git a/templates/compose/edgedb.yaml b/templates/compose/edgedb.yaml new file mode 100644 index 000000000..62c6e8000 --- /dev/null +++ b/templates/compose/edgedb.yaml @@ -0,0 +1,43 @@ +# documentation: https://www.edgedb.com +# slogan: An open-source database designed as a spiritual successor to SQL and the relational paradigm. Powered by the Postgres query engine under the hood. +# tags: db database sql +# logo: svgs/edgedb.svg + +services: + edgedb: + image: edgedb/edgedb + environment: + - EDGEDB_SERVER_ADMIN_UI=${EDGEDB_SERVER_ADMIN_UI:-enabled} + - EDGEDB_SERVER_BACKEND_DSN=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + - EDGEDB_SERVER_SECURITY=strict + - EDGEDB_SERVER_PASSWORD=$SERVICE_EDGEDB_SERVER_PASSWORD + - EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed + # - EDGEDB_SERVER_TLS_CERT_FILE= # Ideally Coolify should generate its own certificates + # - EDGEDB_SERVER_TLS_KEY_FILE= # -- || -- + - POSTGRES_DB=${POSTGRES_DB:-edgedb} + + depends_on: + postgresql: + condition: service_healthy + volumes: + - "./dbschema:/dbschema" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5656/server/status/alive"] + interval: 5s + timeout: 20s + retries: 10 + ports: + - "5656:5656" + postgresql: + image: postgres:16-alpine + volumes: + - postgresql-data:/var/lib/postgresql/data + environment: + - POSTGRES_USER=$SERVICE_USER_POSTGRES + - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - POSTGRES_DB=${POSTGRES_DB:-edgedb} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 5s + timeout: 20s + retries: 10 \ No newline at end of file From 03d347f082b86a4b8c980186884bc83b415d5c7e Mon Sep 17 00:00:00 2001 From: Jere Salonen Date: Tue, 23 Apr 2024 20:08:08 +0200 Subject: [PATCH 002/120] fix: Add port metadata and Coolify magic to generate the domain --- templates/compose/edgedb.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/compose/edgedb.yaml b/templates/compose/edgedb.yaml index 62c6e8000..a4e127fa5 100644 --- a/templates/compose/edgedb.yaml +++ b/templates/compose/edgedb.yaml @@ -2,11 +2,13 @@ # slogan: An open-source database designed as a spiritual successor to SQL and the relational paradigm. Powered by the Postgres query engine under the hood. # tags: db database sql # logo: svgs/edgedb.svg +# port: 5656 services: edgedb: image: edgedb/edgedb environment: + - SERVICE_FQDN_EDGEDB - EDGEDB_SERVER_ADMIN_UI=${EDGEDB_SERVER_ADMIN_UI:-enabled} - EDGEDB_SERVER_BACKEND_DSN=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB - EDGEDB_SERVER_SECURITY=strict From e77e807cdd830b71e0d6885b417c0ab14ef7de0f Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:54:16 +0200 Subject: [PATCH 003/120] Add UI --- .../project/database/redis/general.blade.php | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index ceb12a802..35ee90583 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -9,48 +9,41 @@
- + +
+
+ +

Network

- +
- + @if ($db_url_public) - + @endif

Proxy

- + Proxy Logs - + - Proxy Logs + Proxy Logs
- +

Advanced

- +
+ From a2ba67ea34f33cad2bfeacf928ead01fa9a90baf Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:19:36 +0200 Subject: [PATCH 004/120] Add redis username --- app/Actions/Database/StartRedis.php | 16 +++++++++++- .../Project/Database/Redis/General.php | 25 ++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index f10afef5e..b3f240942 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -166,6 +166,14 @@ private function generate_environment_variables() $environment_variables->push("$env->key=$env->real_value"); } + $redis_version = $this->get_redis_version(); + + if (version_compare($redis_version, '6.0', '>=')) { + if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_USERNAME'))->isEmpty()) { + $environment_variables->push("REDIS_USERNAME={$this->database->redis_username}"); + } + } + if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) { $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); } @@ -173,6 +181,12 @@ private function generate_environment_variables() return $environment_variables->all(); } + private function get_redis_version() + { + $image_parts = explode(':', $this->database->image); + return $image_parts[1] ?? '0.0'; + } + private function add_custom_redis() { if (is_null($this->database->redis_conf) || empty($this->database->redis_conf)) { @@ -184,4 +198,4 @@ private function add_custom_redis() instant_scp($path, "{$this->configuration_dir}/{$filename}", $this->database->destination->server); Storage::disk('local')->delete("tmp/redis.conf_{$this->database->uuid}"); } -} +} \ No newline at end of file diff --git a/app/Livewire/Project/Database/Redis/General.php b/app/Livewire/Project/Database/Redis/General.php index a7ce0161a..6acd1095f 100644 --- a/app/Livewire/Project/Database/Redis/General.php +++ b/app/Livewire/Project/Database/Redis/General.php @@ -25,6 +25,7 @@ class General extends Component 'database.name' => 'required', 'database.description' => 'nullable', 'database.redis_conf' => 'nullable', + 'database.redis_username' => 'required', 'database.redis_password' => 'required', 'database.image' => 'required', 'database.ports_mappings' => 'nullable', @@ -37,6 +38,7 @@ class General extends Component 'database.name' => 'Name', 'database.description' => 'Description', 'database.redis_conf' => 'Redis Configuration', + 'database.redis_username' => 'Redis Username', 'database.redis_password' => 'Redis Password', 'database.image' => 'Image', 'database.ports_mappings' => 'Port Mapping', @@ -73,16 +75,33 @@ public function submit() { try { $this->validate(); - if ($this->database->redis_conf === '') { - $this->database->redis_conf = null; + + $redis_version = $this->get_redis_version(); + + if (version_compare($redis_version, '6.0', '>=')) { + if ($this->database->isDirty('redis_username')) { + $this->database->redis_username = $this->database->redis_username; + } } + + if ($this->database->isDirty('redis_password')) { + $this->database->redis_password = $this->database->redis_password; + } + $this->database->save(); + $this->dispatch('success', 'Database updated.'); } catch (Exception $e) { return handleError($e, $this); } } + private function get_redis_version() + { + $image_parts = explode(':', $this->database->image); + return $image_parts[1] ?? '0.0'; + } + public function instantSave() { try { @@ -123,4 +142,4 @@ public function render() { return view('livewire.project.database.redis.general'); } -} +} \ No newline at end of file From 388f8c4e9533bdaa5f21398bde0119dded3095e5 Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:20:03 +0200 Subject: [PATCH 005/120] Security fix redis password and username logic --- app/Models/StandaloneRedis.php | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index 8a202ea9e..b08825bd4 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -16,6 +16,14 @@ class StandaloneRedis extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + protected $casts = [ + 'redis_password' => 'encrypted', + ]; + + protected $attributes = [ + 'redis_username' => 'redis', + ]; + protected static function booted() { static::created(function ($database) { @@ -205,7 +213,11 @@ public function databaseType(): Attribute protected function internalDbUrl(): Attribute { return new Attribute( - get: fn () => "redis://:{$this->redis_password}@{$this->uuid}:6379/0", + get: function () { + $redis_version = $this->get_redis_version(); + $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ""; + return "redis://{$username_part}{$this->redis_password}@{$this->uuid}:6379/0"; + } ); } @@ -214,14 +226,21 @@ protected function externalDbUrl(): Attribute return new Attribute( get: function () { if ($this->is_public && $this->public_port) { - return "redis://:{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0"; + $redis_version = $this->get_redis_version(); + $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ""; + return "redis://{$username_part}{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0"; } - return null; } ); } + private function get_redis_version() + { + $image_parts = explode(':', $this->image); + return $image_parts[1] ?? '0.0'; + } + public function environment() { return $this->belongsTo(Environment::class); @@ -285,4 +304,4 @@ public function getMetrics(int $mins = 5) return $parsedCollection->toArray(); } } -} +} \ No newline at end of file From ae7e5487791c08a0f0a40ad5554af81050346876 Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:20:15 +0200 Subject: [PATCH 006/120] DB migration for redis username --- ...dis_username_to_standalone_redis_table.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 database/migrations/2024_08_21_165435_add_redis_username_to_standalone_redis_table.php diff --git a/database/migrations/2024_08_21_165435_add_redis_username_to_standalone_redis_table.php b/database/migrations/2024_08_21_165435_add_redis_username_to_standalone_redis_table.php new file mode 100644 index 000000000..397c6a68f --- /dev/null +++ b/database/migrations/2024_08_21_165435_add_redis_username_to_standalone_redis_table.php @@ -0,0 +1,22 @@ +string('redis_username')->default('redis')->after('description'); + }); + } + + public function down(): void + { + Schema::table('standalone_redis', function (Blueprint $table) { + $table->dropColumn('redis_username'); + }); + } +}; From 68060ef37dbe94c675925ad01b09ed05fbaab5ac Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:20:28 +0200 Subject: [PATCH 007/120] typo in redis seeder --- database/seeders/StandaloneRedisSeeder.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/database/seeders/StandaloneRedisSeeder.php b/database/seeders/StandaloneRedisSeeder.php index e7bf3373e..7c64b17a2 100644 --- a/database/seeders/StandaloneRedisSeeder.php +++ b/database/seeders/StandaloneRedisSeeder.php @@ -11,8 +11,9 @@ class StandaloneRedisSeeder extends Seeder public function run(): void { StandaloneRedis::create([ - 'name' => 'Local PostgreSQL', - 'description' => 'Local PostgreSQL for testing', + 'name' => 'Local Redis', + 'description' => 'Local Redis for testing', + 'redis_username' => 'redis', 'redis_password' => 'redis', 'environment_id' => 1, 'destination_id' => 0, From 462acda233507c19acd541f9b3d6a2893e2a7a8a Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:20:46 +0200 Subject: [PATCH 008/120] Feat: add UI for redis password and username --- .../livewire/project/database/redis/general.blade.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index 35ee90583..e062a4bcd 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -12,8 +12,13 @@
- - + @php + $redis_version = explode(':', $database->image)[1] ?? '0.0'; + @endphp + @if (version_compare($redis_version, '6.0', '>=')) + + @endif +

Network

@@ -46,4 +51,4 @@
- + \ No newline at end of file From 3d7a467abf936f50167cf06445c4b61d008c2ae3 Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:00:18 +0200 Subject: [PATCH 009/120] WIP WIP --- app/Actions/Database/StartRedis.php | 56 +++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index b3f240942..6d1548357 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -20,10 +20,42 @@ class StartRedis public function handle(StandaloneRedis $database) { $this->database = $database; + //$this->configuration_dir = database_configuration_dir().'/'.$this->database->uuid; + + //$this->add_custom_redis(); + + // $startCommand = "redis-server"; + // $additionalArgs = []; + + // if (!is_null($this->database->redis_conf) && !empty($this->database->redis_conf)) { + // ray("Using custom Redis configuration"); + // $additionalArgs[] = "{$this->configuration_dir}/redis.conf"; + + // // Check if the custom config contains a requirepass directive + // $configContent = file_get_contents("{$this->configuration_dir}/redis.conf"); + // if (strpos($configContent, 'requirepass') === false) { + // $additionalArgs[] = "--requirepass {$this->database->redis_password}"; + // ray("No requirepass in custom config, adding it as an argument"); + // } else { + // ray("requirepass found in custom config"); + // } + // } else { + // $additionalArgs[] = "--requirepass {$this->database->redis_password}"; + // $additionalArgs[] = "--appendonly yes"; + // ray("No custom config, using default arguments"); + // } + + // if (!empty($additionalArgs)) { + // $startCommand .= " " . implode(" ", $additionalArgs); + // } + + // ray("Final start command: " . $startCommand); $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; + $container_name = $this->database->uuid; + $this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->commands = [ @@ -31,12 +63,14 @@ public function handle(StandaloneRedis $database) "mkdir -p $this->configuration_dir", ]; + $persistent_storages = $this->generate_local_persistent_volumes(); $persistent_file_volumes = $this->database->fileStorages()->get(); $volume_names = $this->generate_local_persistent_volumes_only_volume_names(); $environment_variables = $this->generate_environment_variables(); $this->add_custom_redis(); + $docker_compose = [ 'services' => [ $container_name => [ @@ -113,6 +147,7 @@ public function handle(StandaloneRedis $database) 'read_only' => true, ]; $docker_compose['services'][$container_name]['command'] = "redis-server /usr/local/etc/redis/redis.conf --requirepass {$this->database->redis_password} --appendonly yes"; + } $docker_compose = Yaml::dump($docker_compose, 10); $docker_compose_base64 = base64_encode($docker_compose); @@ -178,13 +213,20 @@ private function generate_environment_variables() $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); } - return $environment_variables->all(); - } + ray('Initial environment variables:', $environment_variables->toArray()); - private function get_redis_version() - { - $image_parts = explode(':', $this->database->image); - return $image_parts[1] ?? '0.0'; + // Overwrite with UI-set environment variables + $ui_variables = $this->database->environment_variables()->get();//this is working + ray('UI-set environment variables:', $ui_variables->toArray()); + + foreach ($ui_variables as $ui_variable) { //the overwrite is not working it is set wrong + $environment_variables = $environment_variables->reject(fn ($env) => str($env)->startsWith("{$ui_variable->key}=")); + $environment_variables->push("{$ui_variable->key}={$ui_variable->real_value}"); + } + + ray('Final environment variables:', $environment_variables->toArray()); + + return $environment_variables->all(); } private function add_custom_redis() @@ -194,7 +236,7 @@ private function add_custom_redis() } $filename = 'redis.conf'; Storage::disk('local')->put("tmp/redis.conf_{$this->database->uuid}", $this->database->redis_conf); - $path = Storage::path("tmp/redis.conf_{$this->database->uuid}"); + $path = Storage::path("tmp/redis.conf_{$this->database->uuid}"); instant_scp($path, "{$this->configuration_dir}/{$filename}", $this->database->destination->server); Storage::disk('local')->delete("tmp/redis.conf_{$this->database->uuid}"); } From cddd4b59f90dbeee57039e15cbdd1aa0fea57be0 Mon Sep 17 00:00:00 2001 From: ALsJourney <63744576+ALsJourney@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:16:40 +0200 Subject: [PATCH 010/120] Added a basic login test and also added 2 small variables to dev .env file Small test just to see if you wish to continue this way of me writing tests in this shape and form. you can run them locally with php artisan dusk:chrome-driver --detect, run it with ./vendor/laravel/dusk/bin/chromedriver-mac-arm --port=9515 then run tests with php artisan dusk --- .env.development.example | 2 ++ config/testing.php | 6 ++++++ tests/Browser/ExampleTest.php | 20 -------------------- tests/Browser/LoginTest.php | 30 ++++++++++++++++++++++++++++++ tests/DuskTestCase.php | 5 ++++- 5 files changed, 42 insertions(+), 21 deletions(-) create mode 100644 config/testing.php delete mode 100644 tests/Browser/ExampleTest.php create mode 100644 tests/Browser/LoginTest.php diff --git a/.env.development.example b/.env.development.example index f9bcd361a..0f9e4c72e 100644 --- a/.env.development.example +++ b/.env.development.example @@ -13,6 +13,8 @@ TELESCOPE_ENABLED=false # Selenium Driver URL for Dusk DUSK_DRIVER_URL=http://selenium:4444 +DUSK_EMAIL=test@example.com +DUSK_PASSWORD=password # PostgreSQL Database Configuration DB_DATABASE=coolify diff --git a/config/testing.php b/config/testing.php new file mode 100644 index 000000000..41b8eadf0 --- /dev/null +++ b/config/testing.php @@ -0,0 +1,6 @@ + env('DUSK_TEST_EMAIL', 'test@example.com'), + 'dusk_test_password' => env('DUSK_TEST_PASSWORD', 'password'), +]; diff --git a/tests/Browser/ExampleTest.php b/tests/Browser/ExampleTest.php deleted file mode 100644 index 15dc8f5f1..000000000 --- a/tests/Browser/ExampleTest.php +++ /dev/null @@ -1,20 +0,0 @@ -browse(function (Browser $browser) { - $browser->visit('/') - ->assertSee('Laravel'); - }); - } -} diff --git a/tests/Browser/LoginTest.php b/tests/Browser/LoginTest.php new file mode 100644 index 000000000..ffa83d09b --- /dev/null +++ b/tests/Browser/LoginTest.php @@ -0,0 +1,30 @@ +browse(function (Browser $browser) use ($password, $email) { + $browser->visit('/login') + ->type('email', $email) + ->type('password', $password) + ->press('Login') + ->assertPathIs('/'); + }); + } +} diff --git a/tests/DuskTestCase.php b/tests/DuskTestCase.php index 8628871a1..d909d1c21 100644 --- a/tests/DuskTestCase.php +++ b/tests/DuskTestCase.php @@ -67,6 +67,9 @@ protected function hasHeadlessDisabled(): bool protected function baseUrl() { - return rtrim(config('app.url'), '/'); + $app_url = config('app.url'); + $port = config('app.port'); + + return $app_url.':'.$port; } } From 38d4e4a035a050e9038a12ea04b016a399568f6d Mon Sep 17 00:00:00 2001 From: ALsJourney <63744576+ALsJourney@users.noreply.github.com> Date: Sun, 8 Sep 2024 21:41:56 +0200 Subject: [PATCH 011/120] Added a HowTo Markdown on how to run tests --- tests/How_To_Use_Dusk.md | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/How_To_Use_Dusk.md diff --git a/tests/How_To_Use_Dusk.md b/tests/How_To_Use_Dusk.md new file mode 100644 index 000000000..fc10bff8c --- /dev/null +++ b/tests/How_To_Use_Dusk.md @@ -0,0 +1,53 @@ +# How to use Laravel Dusk in local development + +## Pre-requisites + +- Google Chrome installed on your machine (for the Chrome driver) +- everything else is already set up in the project + + +## Running Dusk in local development + +In order to use Laravel Dusk in local development, you need to run these commands: + +```bash +docker exec -it coolify php artisan dusk:chrome-driver --detect +``` + +The chrome driver will be installed under `./vendor/laravel/dusk/bin/chromedriver-linux`. + +Then you need to run the chrome-driver by hand. You can find the driver in the following path: +```bash +docker exec -it coolify ./vendor/laravel/dusk/bin/chromedriver-linux --port=9515 +``` + +### Running the tests on Apple Silicon + +If you are using an Apple Silicon machine, you need to install the Chrome driver locally on your machine with the following command: + +```bash +php artisan dusk:chrome-driver --detect +# then run it with the following command +./vendor/laravel/dusk/bin/chromedriver-mac-arm --port=9515 130 ↵ +``` + +### Running the tests + +Finally, you can run the tests with the following command: +```bash +docker exec -it coolify php artisan dusk +``` + +That's it. You should see the tests running in the terminal. +For proof, you can check the screenshot in the `tests/Browser/screenshots` folder. + +``` + + PASS Tests\Browser\LoginTest + ✓ login 3.63s + + Tests: 1 passed (1 assertions) + Duration: 3.79s + + +``` \ No newline at end of file From 1ae145bf13de253107537b3b0018e9b433b95418 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 26 Sep 2024 19:49:33 +0200 Subject: [PATCH 012/120] Revert "typo in redis seeder" This reverts commit 68060ef37dbe94c675925ad01b09ed05fbaab5ac. --- database/seeders/StandaloneRedisSeeder.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/database/seeders/StandaloneRedisSeeder.php b/database/seeders/StandaloneRedisSeeder.php index 7c64b17a2..e7bf3373e 100644 --- a/database/seeders/StandaloneRedisSeeder.php +++ b/database/seeders/StandaloneRedisSeeder.php @@ -11,9 +11,8 @@ class StandaloneRedisSeeder extends Seeder public function run(): void { StandaloneRedis::create([ - 'name' => 'Local Redis', - 'description' => 'Local Redis for testing', - 'redis_username' => 'redis', + 'name' => 'Local PostgreSQL', + 'description' => 'Local PostgreSQL for testing', 'redis_password' => 'redis', 'environment_id' => 1, 'destination_id' => 0, From e5b798964dce9489d0391b7337f850789801e658 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 26 Sep 2024 20:01:35 +0200 Subject: [PATCH 013/120] Update StartRedis.php --- app/Actions/Database/StartRedis.php | 74 ++++------------------------- 1 file changed, 9 insertions(+), 65 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 6d1548357..eeddab924 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -20,42 +20,10 @@ class StartRedis public function handle(StandaloneRedis $database) { $this->database = $database; - //$this->configuration_dir = database_configuration_dir().'/'.$this->database->uuid; - - //$this->add_custom_redis(); - - // $startCommand = "redis-server"; - // $additionalArgs = []; - - // if (!is_null($this->database->redis_conf) && !empty($this->database->redis_conf)) { - // ray("Using custom Redis configuration"); - // $additionalArgs[] = "{$this->configuration_dir}/redis.conf"; - - // // Check if the custom config contains a requirepass directive - // $configContent = file_get_contents("{$this->configuration_dir}/redis.conf"); - // if (strpos($configContent, 'requirepass') === false) { - // $additionalArgs[] = "--requirepass {$this->database->redis_password}"; - // ray("No requirepass in custom config, adding it as an argument"); - // } else { - // ray("requirepass found in custom config"); - // } - // } else { - // $additionalArgs[] = "--requirepass {$this->database->redis_password}"; - // $additionalArgs[] = "--appendonly yes"; - // ray("No custom config, using default arguments"); - // } - - // if (!empty($additionalArgs)) { - // $startCommand .= " " . implode(" ", $additionalArgs); - // } - - // ray("Final start command: " . $startCommand); $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; - $container_name = $this->database->uuid; - $this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->commands = [ @@ -63,14 +31,12 @@ public function handle(StandaloneRedis $database) "mkdir -p $this->configuration_dir", ]; - $persistent_storages = $this->generate_local_persistent_volumes(); $persistent_file_volumes = $this->database->fileStorages()->get(); $volume_names = $this->generate_local_persistent_volumes_only_volume_names(); $environment_variables = $this->generate_environment_variables(); $this->add_custom_redis(); - $docker_compose = [ 'services' => [ $container_name => [ @@ -116,14 +82,7 @@ public function handle(StandaloneRedis $database) data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); } if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { - $docker_compose['services'][$container_name]['logging'] = [ - 'driver' => 'fluentd', - 'options' => [ - 'fluentd-address' => 'tcp://127.0.0.1:24224', - 'fluentd-async' => 'true', - 'fluentd-sub-second-precision' => 'true', - ], - ]; + $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration(); } if (count($this->database->ports_mappings_array) > 0) { $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array; @@ -147,8 +106,12 @@ public function handle(StandaloneRedis $database) 'read_only' => true, ]; $docker_compose['services'][$container_name]['command'] = "redis-server /usr/local/etc/redis/redis.conf --requirepass {$this->database->redis_password} --appendonly yes"; - } + + // Add custom docker run options + $docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options); + $docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network); + $docker_compose = Yaml::dump($docker_compose, 10); $docker_compose_base64 = base64_encode($docker_compose); $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; @@ -201,30 +164,11 @@ private function generate_environment_variables() $environment_variables->push("$env->key=$env->real_value"); } - $redis_version = $this->get_redis_version(); - - if (version_compare($redis_version, '6.0', '>=')) { - if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_USERNAME'))->isEmpty()) { - $environment_variables->push("REDIS_USERNAME={$this->database->redis_username}"); - } - } - if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) { $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); } - ray('Initial environment variables:', $environment_variables->toArray()); - - // Overwrite with UI-set environment variables - $ui_variables = $this->database->environment_variables()->get();//this is working - ray('UI-set environment variables:', $ui_variables->toArray()); - - foreach ($ui_variables as $ui_variable) { //the overwrite is not working it is set wrong - $environment_variables = $environment_variables->reject(fn ($env) => str($env)->startsWith("{$ui_variable->key}=")); - $environment_variables->push("{$ui_variable->key}={$ui_variable->real_value}"); - } - - ray('Final environment variables:', $environment_variables->toArray()); + add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables); return $environment_variables->all(); } @@ -236,8 +180,8 @@ private function add_custom_redis() } $filename = 'redis.conf'; Storage::disk('local')->put("tmp/redis.conf_{$this->database->uuid}", $this->database->redis_conf); - $path = Storage::path("tmp/redis.conf_{$this->database->uuid}"); + $path = Storage::path("tmp/redis.conf_{$this->database->uuid}"); instant_scp($path, "{$this->configuration_dir}/{$filename}", $this->database->destination->server); Storage::disk('local')->delete("tmp/redis.conf_{$this->database->uuid}"); } -} \ No newline at end of file +} From 67b17e871fe75e04a872da0f06c79ecb6df0aa39 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Thu, 3 Oct 2024 13:26:27 -0400 Subject: [PATCH 014/120] adding mindsDB --- public/svgs/mindsdb.svg | 12 ++++++++++++ templates/compose/mindsdb.yaml | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 public/svgs/mindsdb.svg create mode 100644 templates/compose/mindsdb.yaml diff --git a/public/svgs/mindsdb.svg b/public/svgs/mindsdb.svg new file mode 100644 index 000000000..53799dd1c --- /dev/null +++ b/public/svgs/mindsdb.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/templates/compose/mindsdb.yaml b/templates/compose/mindsdb.yaml new file mode 100644 index 000000000..44bae7719 --- /dev/null +++ b/templates/compose/mindsdb.yaml @@ -0,0 +1,35 @@ +# documentation: https://docs.mindsdb.com/what-is-mindsdb +# slogan: MindsDB is the platform for building AI from enterprise data, enabling smarter organizations. +# tags: mysql, postgresdb, machine-learning, ai +# logo: svgs/mindsdb.png +# port: 47334 + +services: + mindsdb: + image: mindsdb/mindsdb + restart: always + environment: + - SERVICE_FQDN_MINDSDB_47334 + - MINDSDB_DOCKER_ENV=true + - MINDSDB_STORAGE_DIR=/mindsdb/var + - FLASK_DEBUG=1 # This will make sure http requests are logged regardless of log level + - OPENAI_API_KEY=$OPENAI_API_KEY + - LANGFUSE_HOST=$LANGFUSE_HOST + - LANGFUSE_PUBLIC_KEY=$LANGFUSE_PUBLIC_KEY + - LANGFUSE_SECRET_KEY=$LANGFUSE_SECRET_KEY + - LANGFUSE_RELEASE="local" + # - LANGFUSE_DEBUG="True" + - LANGFUSE_TIMEOUT="10" + - LANGFUSE_SAMPLE_RATE="1.0" + ports: + - 47335:47335 + - 47336:47336 + volumes: + - type: bind + source: . + target: /mindsdb + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:47334/api/util/ping"] + interval: 30s + timeout: 4s + retries: 100 From a094eceb624b024ef46efd1e98a6769003555c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Smitka?= Date: Wed, 9 Oct 2024 18:34:17 +0200 Subject: [PATCH 015/120] Expose port 443/udp with Caddy proxy --- bootstrap/helpers/proxy.php | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 5d1ad5390..9fa93e2e9 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -239,6 +239,7 @@ function generate_default_proxy_configuration(Server $server) 'ports' => [ '80:80', '443:443', + '443:443/udp', ], 'labels' => [ 'coolify.managed=true', From f95f44f4ccee167a1cfa491d6e5824ab44dd9955 Mon Sep 17 00:00:00 2001 From: MarioCake Date: Wed, 9 Oct 2024 23:45:57 +0200 Subject: [PATCH 016/120] Add settings button to projects page. --- app/Livewire/Project/Index.php | 6 +++++- resources/views/livewire/project/index.blade.php | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/Livewire/Project/Index.php b/app/Livewire/Project/Index.php index 0e4f15a5c..9ba082a8c 100644 --- a/app/Livewire/Project/Index.php +++ b/app/Livewire/Project/Index.php @@ -18,7 +18,11 @@ class Index extends Component public function mount() { $this->private_keys = PrivateKey::ownedByCurrentTeam()->get(); - $this->projects = Project::ownedByCurrentTeam()->get(); + $this->projects = Project::ownedByCurrentTeam()->get()->map(function ($project) { + $project->route = route('project.edit', ['project_uuid' => $project->uuid]); + + return $project; + }); $this->servers = Server::ownedByCurrentTeam()->count(); } diff --git a/resources/views/livewire/project/index.blade.php b/resources/views/livewire/project/index.blade.php index 10719456e..bebe15258 100644 --- a/resources/views/livewire/project/index.blade.php +++ b/resources/views/livewire/project/index.blade.php @@ -24,6 +24,12 @@
+ From 62e67eff8931bd0c136235831f3e77218e786980 Mon Sep 17 00:00:00 2001 From: MarioCake Date: Wed, 9 Oct 2024 23:49:54 +0200 Subject: [PATCH 017/120] Remove click handler for settings div. --- resources/views/livewire/project/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/project/index.blade.php b/resources/views/livewire/project/index.blade.php index bebe15258..d53535582 100644 --- a/resources/views/livewire/project/index.blade.php +++ b/resources/views/livewire/project/index.blade.php @@ -24,7 +24,7 @@
-
+
Settings From 0155af211653270247149447e99e9b87b926d760 Mon Sep 17 00:00:00 2001 From: loudar Date: Thu, 10 Oct 2024 01:01:11 +0200 Subject: [PATCH 018/120] limit randomly generated github app name length --- app/Livewire/Source/Github/Create.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Livewire/Source/Github/Create.php b/app/Livewire/Source/Github/Create.php index f85e8646e..103c5c9fb 100644 --- a/app/Livewire/Source/Github/Create.php +++ b/app/Livewire/Source/Github/Create.php @@ -23,7 +23,7 @@ class Create extends Component public function mount() { - $this->name = generate_random_name(); + $this->name = substr(generate_random_name(), 0, 34); // GitHub Apps names can only be 34 characters long } public function createGitHubApp() From 76d631d7ba7699d07ec53168a0c12718f842d2ed Mon Sep 17 00:00:00 2001 From: MarioCake Date: Thu, 10 Oct 2024 09:45:13 +0200 Subject: [PATCH 019/120] Rename route attribute to settingsRoute attribute. --- app/Livewire/Project/Index.php | 2 +- resources/views/livewire/project/index.blade.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Livewire/Project/Index.php b/app/Livewire/Project/Index.php index 9ba082a8c..f8eb838be 100644 --- a/app/Livewire/Project/Index.php +++ b/app/Livewire/Project/Index.php @@ -19,7 +19,7 @@ public function mount() { $this->private_keys = PrivateKey::ownedByCurrentTeam()->get(); $this->projects = Project::ownedByCurrentTeam()->get()->map(function ($project) { - $project->route = route('project.edit', ['project_uuid' => $project->uuid]); + $project->settingsRoute = route('project.edit', ['project_uuid' => $project->uuid]); return $project; }); diff --git a/resources/views/livewire/project/index.blade.php b/resources/views/livewire/project/index.blade.php index d53535582..cb8e1bbed 100644 --- a/resources/views/livewire/project/index.blade.php +++ b/resources/views/livewire/project/index.blade.php @@ -26,7 +26,7 @@
From 3b13446e6536625d85086824c4ce16dfe118d2d9 Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Thu, 10 Oct 2024 19:18:35 +0100 Subject: [PATCH 020/120] Added mosquitto --- public/svgs/mosquitto.png | Bin 0 -> 16118 bytes templates/compose/mosquitto.yaml | 47 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 public/svgs/mosquitto.png create mode 100644 templates/compose/mosquitto.yaml diff --git a/public/svgs/mosquitto.png b/public/svgs/mosquitto.png new file mode 100644 index 0000000000000000000000000000000000000000..eb287a7cdd7e2d0a0bbacbd375f6ae6b065df280 GIT binary patch literal 16118 zcmche1y@_m7w!X;(n5ja6fZ8t-D!)vThQQM2=370?(Xgm4gR9V-QAtwE;sz|XSkQO zSm&H%GC5~wX3sNw|8|I?yaXyT0WtspK$VgdRR#dyV5e|^5AR_I9fx95*x?=chm`6E z*q`SI<6zkJ$6u0KU|9Raw|_W0d4X%#i(eeYG#yp!OdVYe9ZUc&E-p+KwpL&x!(S#$ zb`EA~rvd~302x3^^t-BS`bmbHL55n&tMHhI-DDwQeL14By`hB`ky5stG6K1FLxI!> zdjC!qe?HqYtii?fdTT^(d~u{-aQ5jj(fPibqWB>26tX|E^bwD3d;wW~z^TotSJoOS zgwdjI<(8LQYAJn8KYDd9JudB50IHR__b5X4`NKPSzyJ4#6}Y|JPy!cRvY&$SBAr+z z#Wr`8qhdb=qcbH@uL15N^wg?eNPk~!B-GoCmRZ%%+ZyXRxu<_4zl&8?+nGdaD>_75 zZ~m>nv%W)GsGx2C$d3QLz#91*vM7O6i~j?XEbh9$~E&g&CJLT8(kuUh=7Mkw!)cY0Fh zPVoBEy#3fJj>ZsI!DlgQ9!#%BN8LX;8;KVzh(t^(TE6_PPx4u1p1iw4h^l;82$KP7 zpzi*K_oI|80YhbFo_JUw{pcTPhy_YYt?z4RC6HW<1?yCJd_xZd7dq3ug}A;Jcpi=q zsHN;BHMXQzl`b3p)?wIJ7r+iDDkG zc|3g<&vtQKmR5WD_3L|gYd?`3)#+vxvHLG9IU;fBBy1&z%tJ{HLj2KNhf!ah00}eT zwJ38e#n{er?7O?K5}B=_ds3heyU0)2(-!6yZV;{OWq%i6Zt?P57oiyQsaLg9wkPqO^2oGXC1hm89G=%xCN{GX}d~ zuZDRehCg2+vBl*O+uX@>%3slTK=`Hx;-MsaCZ?`&c)zY+Or@TQK{g$+@*{#+QSEMX2tBdzPq$l< z>#y{9jSbUlyox6-M|RbGsoH`r($inaSV6um?pl8iY~*Yut2E$S@TN-lh;d|24cFJ< zPD>GX;$_2zKK&BzB;)lhnXz4yyd!3@XL&$S|2Q$+xXXL;ds^RsyRg>O7J?}(vf=X7 z-bz_A>0@ctdePu_YR)nWpbWhu`OSR~M@@TfgfoNc^n2dSfIGjodBc(F1@Y|-v}xC& zl}}wL?wwlz`Z7YM_w796&sQP@IlIwPG#!neT1P5B$9)X&igKGbJVl{~>rEAc=ao%z zrS8uGCKU>3#xw|rfWi!+Tl|Qt4!=jg= zu1<$8Px{bQNwIFz%5a;ytxcgfqasW^`MNcs9?kju-jsdGCHhnR%XZ<2AvH2~_OT(a^Wb$r6v2bMfqRQig8C-x13W#bRyywlWILs z(C?M+%E~-@#$Wn^(s!X4D8dX?7POWi34^^N*v#0fIb#oHzvovRJ+iq#Fit%J z`r3Ki#7zc6iG4Osq~19`w1I4@?-q9 zwA}vrhHzf6xY$`A^Qs@4rqisg&%wR0_qnF+|Pyjts5MUMQ|#Sy#% zH7`E8SH+FI6S>ND$*Dm;ZYi*U7~6d{v0EJl(4hwlU1z6)Ts2;@^EZu}7x2%mJ7=zE zLq)+$4kb17H!H9E@jT)2{L(2nJ4OJ;Ai7Yg<;9Xhx%(Nk!)oNA5pUitS!Yi=N}%@8 z_Rkn@$v{VrXLj4dvrx#yML|UsvBUNN;b)=kiQ9kiJy?maHP>)aT)yPiaE0n)8RT6> z0%;awMEy3n-C_}QPc~tR@;J1KJr`eytz2nUDHgqoOTk8cdw=!Mz2%!OR3#dXrD4_? z04+PGufjh~TD|LX!)X93Tv;OMBdzOTOL;PQ14EpY=$#^?3fJNoH7bWaZgRh^Aj;Fx zZN-A>aq!*wYITr3|4NROe86*M?8pcM)4d>SLRlj}M05n~ajg!)slH^^b=nV~& zRGr6)Wh&oBumx-uDA2EEC8u&!(b^yerXx(o?ZOMwDuXc@T;xg~1II`*sUl9tf^~Ly z6XWR1GUiYd7vP9sBY~=vCu`KN2rZb}tG^Ca8N&IhCz?_SHICe3kBBe}4DD(82s`ew zjhw>g@T7XczhaxrEpIH1_Usog0jd^p>4z&y9d@mObqKUT$foBL`HKTQ-o1SNh2^c* zx@Q(wWA2$l_lRUrI zDXWl8JvXH2-IMx%gXsrTcAUK&$wVTja`!~fcp}GPKH;)a<+s&l4_815^T^jOsE`xG zYnzYzB;v-1@VD`hiTtsz9Jo0ZF%VVH+igCL!zoGnU4kd&AapHu%LEI~*m<~g=h2Zo zwJQf1GoX_3XkJ88$H7z|Y+;&%>wl<^**l-18%6ba+4yO+l>(_Dq)z`0RU^vSgWCeT z65}^9{j&32b4#Vw&_<)i;`c>8n$`DJ*v>e6L{OISnzJ6`YV!;8TKspZ!&hipT~_lh zFf#z9qdsMXqSViyLg8_}>`eqfr$pRwTmWNk9IULwRf5bVO5{k2Flj}RmdX*YC4`ay*C@PB7kD(^Q8|HFrMi23rEw)Ye;+ z7dXM51pn&)2Kn_@+#o}BVszExdZ-tGsxw1BEwJ6ZzV9@gwkiIJb596c(%yB2zGl~{ z>xfmfG}VsE(TjWdy_A%Lg4L7aa%KS+|xH3Thck!oVL4cD%hGrJuqEwYkgi zPmr2bw2n+q6btqQ3u+4*N=Hxh!*8~%7xv!098U#yJ^LX#J8)#pv#-nht z`Sq3d(5Uk zrZ+3eE87YC6s{vFk{pj?h&NN*YHCaw8J!N{y@EKn4cz>f#1>)|9{huBPXZ3q;BU~| zh%1IHUZ3)KYn^zq^L>v4HP6O|8AN*wgnKinurCTS$Gse1?<0_Kg)htda>kFXQ;KB7 zI#P;M=^yYfH@(#|D1c7<5^t)Er@X_gY7Ixk*?+jRsJ7~^?fGDs=PKoikX-7y4!T`c z>R=&d*UD`;yMegSX8v&|I2Qc$iJQI!j}cqw9&R-*0y0O#kH$xV2=2P?q>eHb7d39{ zT2VSr;YV_k-SckaczQXUxT1;F1QD*OUvOLhKMe>ZmW~Ma7`MNjv-cfd)UsIGS zJ}M#MOmpT_QxgB5r*H7;_}y!G2bJ7u)Q5Jyr>sonqv0PAoBo5} zo%-cB@Xw~dcocu@RMhVW6sm;(3ledzJ1 zY{t%NMucYguRnG`e?6eq(mF-!z?6&5bPl6BB=3FG& z#eB|dx0orZ2EB>EFt@ApA-XP=`LaW4R>>RVwjVl!EZn#lb|V<%;RH}I8}SHo-+wL% z+V84wb_=4r?k`oJ+gVv+bzVZY~*+aStbOlMIrL}vea zw8{7VU7}sCLN9a&*+4{^4WXd;rMR^Z)dMm2g5VbC0DBLgmyGy>8pCFRp8ZS3$f?+Q z945oWd}jCL>all#pp8~7d0V^e<2?M`x7Qt}vYiqq?$exKnGiG06!ng>ehag|CB=MM zT*zdYcc!o{Y0AbI7RrQ%Q&T@XHh@}b)6W#3-j*jC&V(FAC6c<<3DvIuMapIWA`;o| zB}c;Qohl8u!q^8TYFpt_z_IGQ?V zgzOcCMmE?ti*M{J0h^Hw;y|SyV(o;wp*h1=odauEcHs@Zr=@3PmV4V*XN*C! zQBr=PeuXg2f+EF8l7``1X6acDN^=7 zFZCshnN#CVZxi@6Pf!lK#;3|+FcQTfA(HLR@7UFO_s!v>8^YWdq;xDZy{4>u?nZc0 zqR9?dQBO$~ zy(1xi{dJ`p9$5!SV+kjCje8n_4p+r$w;g>)<0|tzZ*sbl(#fzB{N>nul;=a!ZeTs9 z-aWy%>9NapF($8DKdCbq02=!)o?u#L!$mVQzt&zOd8lr+#)B8KHv$(uq>(`c^c1)II6^+bx%}x`dHpPx7hlc7W$fU4_w5nQp_3>zmjYy$_Ih-P1(%+U^=Z z9k5>F^(`fEi4Ho1l9ofpXjJt(l8|@LG?mWjt|@~b5_o^_O&al|@WWPeLa{vb4SVh7 z0L%cW#x#${pT_qIu=&g!c8CtRoB`s^mJWu?%6L(9&PQPF0>&OVXn*{Ua@HqW$h-7a zsaVKKp}y5vSLpLzt1)sIch(odE&M_#j&r%x!LjJTcjIxZ!F62MvA~cx*Ua}s|H%e- zqkOhyxpDctF_E`JHH02u7eddMRC8rU-pfv4fLPq11cP@mbNwI`l2VQ3Jkn#TXz(ZLCjmfUs5MI(XX z@v$w5qgf3y{Z~berC-8P%s`tfx1zLI>0P2_8@qeZLvLO;y}(;qG8t1`9V zuL0wm{%-l2E8FBS#}C^-eRwnmm;^?d`hw<=gQwds)L6$L*d=mHn0bx7zM3Z(+A+Zk zaK-&epLcpZX;KGG#`>9e?#d|tqS#ssuqRnKO+pULYI>$$EF5u zw?&cuBNzI8(H`E4@ZK%8%pSR1Ay*5F&p_k=y9H-2$gWz#x6>d8z zCWw%*4%(q;HG!adj7AnJrTW7S>1E#gn{WeuV!Y#1n!f_;&^NF`m zhuCNrGqM9z(t5!;#pv4m7>>=neAn!U>T$2Yj1ZDyCYLq|>syF~3<}6~9WgGySOSr} z3x*s@B}TGYDgW{PZui2tRRs(UkI!Ol!Yoh-nDy3VAn+<~8(2A-=<}Ui)p^At7y5Lk zx_ke(WUv-oLoSr!P1=o*l?{}}GaOb37T6x6!aN#k+8)6uiyXW~-^BVz^VA1Y7XrU% zqR-?MEs-X-%}(1@@RRV2&qE(n2OSR?F#Gk{Z$4IwsaeAILdodf@56?@Dmf#Id)*aK z;cMim8Tl{z=c($^Gx>&68vncBxnsu#2Dkvx9dJ13n#1$KqjpXJQw+42$vs);0>Y?% zy{m2^43KHE&4#zk3IrCAX7|Mk_v-7s*Zpbe;*7htM-n4%gEYk@W*ADPMf0lc+Br!h zLfGGhFfx4h$@45R+fzFL2eq#&F^S_s#O_ zD!g)+qb;0;FwB1b0LDGW7@*JK{CAT^Qmza ze*2Y%?htE_WC20K0a6UKcKw>pbJ_f?cxlrwEWJA3W4AHLP9Ws#&{{L5U!dV)`sFm# zdfo#hXy7zUBU@%45;w(l%6`7*D;58qXEn8;DCT8xo`!t4f(4ZRTY4{DVefTp8}Jz& z$zbiZO1E{LVCq_eZ^fSc=2HV=BAXGxQE%VNY_I*{@$9TssJgc2N{5rh$n6ba|X zU(Jc@g|M%Wk(p5JIFWqxdSl7@;PDU{#s`x+F6!7j-a+57$O6Np@J$}x{B``?U&KD` z$VsKakN6I!>=CwZVi6uV)#iMu8r`Me*hvaq_&y5bWDz>*-o{6s`8?pH@H`Fzx-KsRnvCbs-#eJxC?*L@B&I zu)D1?-xZ-x!s&j+jq1Fl80}Pt{&dx>l=ed2<$}RjR6P^rs~UWGJ8R>4$$Vr=>e%SM zd);4Bqu-s_pn>@x4JM(}z7hWKSkKBGP_H{}Q<2jVMp?3`E1=Psmjm-k(F&my^sOVo zqoqNiT$*K6EEqDoVP_30a!)K^SF(><2A62LIiG0UF1f56|0Yr2wmsI!1R&8Z*E!#O zN3UoD`P3Dzy(JCk9V&X&|MV!^SD-h~VJv}jF`(W1XXG_Wm}3PjBOkwyz`VwG^@pg< zq|``RG!f3z8fmGolB13A$v3ix9}LieMFNS_l+11MckUAFV~<5q58lcx73FQ#n@XZo z3UEShr~Hu?&6W>yR+T*Kl2(LNWmg{37dUxc9&!ursZVx^O@zV)vkMn0pcVuXYcyYu zU4rD&V?vAk+41Q}s<=7^*~D3W-1%<>gPa}&(@k;KTo87whM?jijH$Xe@d*aG%lkUw;bL-VY=)R4l%l7UdoMt4>!9yLrN0QFc%IFOu^W z>f1&Y>5aDAVfOVHtM}q84Ug2Ap99xBcn6>nOPb%OWITk8xTz`E1PY7Vatg04{Ccl--Vpr)n|@fMl5xbTqJ zs4m8y!lkM*x0;BQ^kmVfWqZ*N50S$B!Y;ZxI^X!2l`dkXe@bt^sr@ax04^=m3GFVNhKQC$ z!VJ{VR}y@!bOB^WXG(4yf@{Wle8x3rVs)-T-XZD1PIki8i8&>Z+eoJ%;$$8}8vXz1&Ryu~6QR=& zT|Cp~LB;1^5SJj*G_&9uLGtndkpQ`8pJEN!?;_-l%uP?+CV76!Dp@gx3N(Rje_1=F z)P`qFy)a@ftpf*q<}^9)6Q!#IIg+%Fm}x;yd_p@@)@H;kgAEajEcv4m{#7s& zFTEBuQ&@TvMwOR36uRYrz<|Ro040~SaK+V`BRw_Tuytv-wo@`~!qeAK7M%n03*SiA ziQp3aS8uUgN7;CJ5DQpeS^Wj~h!OZ@73YRQ$ z()5cJM%rSS<9tSBDJ3pI>1PUf>V|p{M<#47T-)DtbGxJLgkLSr61x+(Mu@#J30p)W zyhJ(Li3z@77YC3_T@@$i#4M%9V#)6kJnSPIJQJ@PJ3mnJU4nVGcpt+@N=d1Eqm(i; z8T1PPnXgp-Hfz>*7Y^S;G1-{Uu%**uhDcU(SKN^rEGG9|#C~vJ%MZJTYM9N<$NmCI zLRIc@8bnUNg}G#)O-=J6pYRWx93@)$k=>}kIP7F+pA}DrqP*EACbd<~BAv4+QQG>& zzZ^bcwn@?fBPxEwfJ3=T=Q-Da$5%N9^QS_Hk4E0*donH(hqA?8L=hd!G(!4awFdEd zt8(;*jks$(9E>vM@`UZZ_l?|E8w;SoqHfRfE=M#GCpMZ#P@9r%PQE&m zTTIE$pWzv6&l(7580%#;MIxJ(mpS&x|97)XHkewFD_H2aT+t(K>l zn)J8%rU;8t_m_~KMlx;@4io<2u$ilH`0d)pZh=dkD|>kT zO6;CAZ3sF9mT^eN?S;_9E@Bh<^*DWH>?qse$KiZBxiGFM6OTgJtHmIu#=sXtT7xsV z;w$Tq;_ir`YV?L!)FCMT3@$`wrfjI8Wse|uzNm}#1YyT;=Dj{BZ)TIsz<%Hzezjq3 zylky0b|Wt-xZ`e0*ogo1A2LA7n-L+Sv_cbYfREJ+a^76-7AqPUB-u%>eR10J%u^d$ zkN-fA?9U}-1+Wy&1aAy!uajq9uw8-p~#E~(P zuG(I>1L(o0Pv~o?g6wkEU|wN6$4hvxERohoUxP2i)YFGnpde;8q;6%CR>%Bk;Y^p{ z#S~a0#Gp3j05HJB#E9tt9=`>U!n9^&)WvciVh8XwTMXOi2<41gyxq&i-Js>VGujWgO>F3d+|s8>);(K?dH4VMM!flN;IvYjyubN&Qe&N_*d4^;}I^bjxiek*|1Z z^&93soo%0z(=!N23ZHm86;M|aEa^Q`{zLOUUwe2YG!k!j4Mk2enl4`RE2q8eFJFZI z#@c>RWl_2F%Gil`a#nUFtkdmUM<`PT;D9tv)NAolm{pp`TQA$^?Lx`q@ z$PrQtTXL6t*U^Ar(gKE4oYHL6Fer!>%QM zqy0HHac3g)h`QC6lZvO2*tH&(moo4q>?diMM!avBQ3pfNDI4gtddFDQdlPg{f$v*R z@ZW|VvCC8#shGK>b@^Y`OZ}($I$}9@F73c9hJxp9!QRI&S+iCLKM?Ts(u*YQ+>smi`hIJciqpcz zNlWaM<>qb!wxh|VeW4#nN+P%Ppg0jRiD&`bW%sJbEHQ4>)Es_Ed;yRTj|G!8CdJ{u zGi))?rE9-{#X@R1J64_PNex#o4XO&-Z{zvQ_^e|XO=PM~g^`OiE&nFvU&)ty*iYEW z!w4Ua1!pmE2>Pjm*f>G5IzLpm)N{qWomV=+le=VM+Onyt^D)B9mVno^p03+Lx`Mxp zLSXe6AZi2tWmVp-j&vrW0v+5?r!&GB?j@YEztFY^oS+Zup*&44+AuMOpcrnW$9o$b zgQHYs>-wFnXp}Atm|5o?3ra^LLOAFAldrHv?recu2_Xo5?<~pOdUIRPx89U79ThiD zSOKoFSyLb6e=rSMV=hZ-)@24-r{+&o{1{@pmc%fsT4?`_sw=ylHD3yp1E)d9C??R& z0Q-kh7bL9%2ev<7|8sxx} z)~IwvYD~isHU6?q?Arr!0!a2yhUq@Cp0gc8j(7R>$fJbW(m`6WO*(K8W#F%jG^hC&fYITu_UfWS+&kc2?`(v=N(wOM(iNpvlnkchGT>gKj{ z0+|bZCF?W~0KpMV4JyIbmL1o)9B_@l6AlZcc9(C8Q=xF+8ONlgW{oys2L-pAFrk|93Ghv3Z*9^ldwBICsMYD@Zby0U+s2Y*a>pWjsd`=o zo@3Pt6rY__I`fkcYQQqBF+Bbk)6Impiac|RRi*vxF%A0sKvjS7!4Hk-(z8shKkk*idH*k-*p=nyzAS!NbzU9bqR0pIUe$>712DUO_ zdh2Q}{j$(qX+z9#welBi!@gT+ZuU?~;5@D6!FkpG@2FYXpkRA4t6^R}V^17e$NE&q z0yw!X%Wdd}LlYN?P))bkeM6KuH^NV3Mer*L(mnzwX&vPos(k(tw?*O<;@C!@YLYW` z?kF2A9cE*O5PKKt#sD8wNe8^<4LjM~Ez8o_5eR>5X9`!HNmK8U$$~*AIM3eNC@uhd zxGY9tBikJqlSG5FYgEB}kBjVZn)_JA6;NO{_pifWkP??g7zGQ&`^AVWvuksOr$CYhu~(_xk&-yF_C?vg@qTC&8Kw%et$YDyScEMu09{GZMBpVfTOx zK?d*I8)TT}r{Wd(m0+ZfKx4$ggFM}~AxbdQEenDxwv@$hy$9g3p5PLw+$n!N=O!m% zygDpF5>E=pzN9x$no3{WY(f^<0ID2T3XWU8_8@4qrAE35lW4>VR(At|$Q|#eZL=Cs zI-U0hczR31fazNATi*CZ@&FbXfO}@ftO(iU=hgKucQzQ(n+D6O-$;ZSiBU=Gx{Qkz3sf;a;Z=c^}

p!*Z_;7&1;8)3J~i4?v1 zs@=pyBd33ZvBc;CErQjh$yL;wMC|2_xiMoQPumupqv>Sz#TKJ>h`8=o=w}lbW;^s* z?@1tglh-NKE`j74KQ2-|bd^@T5yvqk5cz!>tzQ?2m)N4Qk~1tENN?va5fsnAfjghx zzY{Uo*hCyHcjSOEap6Juk>V3RS~f;eg!m!*jlIxafO417EZP~q&XT=7A!QYy1t;Lu ztbwu0o_%JE9?an19BR3D{R@6^RmbNi(K!a0z4$WFXu*53uSE4fyA|tJTYjW!Bj86j zDe`+oU|q|{vGt-0?OTj${V%p+8`~EIX5Q**$72L%o{wH&wr8Jmjbn{!0;ja46(W)P z&|b|l#E)?o{^0}mOz%&*7T}TDFE-;sipy>9!bRAliysu2ML)b+V0>PQ>Ai(W%nN|n zl8vVOof*0KykGR^VChmg&U)wEoU^j z*4uuSz?1Zir6{+L7pD!O%wKlQIAn$(uZ=h*s8Tb-!Z}Mk#V=?3PDocCT5y@eK#62n z;OHiD%eoBs@T3(G)yUm)c?n;=YR<$>GG;S@malph8A`Ahi{D#vr(8Z@7cJ9k;qjrl zFROZyUSK+|9Tc^y`uP$EabHV)sCPs|nE4D`*49~s?DjZ2vyxU?Y~O@%J=^ZS!3@FP zxlaqojj^y7*3AH64kk${{;Z^kbk=OP`nm^Ls(5K`nxLsFIqOCBP)MI%-44as`5*$U zdz549Rkbddd(3Um?OW0NhpMjksZZb|B1!EozhkPAH{^z^$ioqkN_fxW?B&~CG&{^` z^{&SNtsG98Bkc&RtWfeOzQ6z}7)c&dz4kwIgiUo%sk}$9($dH!OfAM**f&MWMtBx= zs$pXa(ygqnKJx<>HrQ8|_Cu0BSMJaM<6lZ!wozEKS7Jqubu@bWD2(l+2hp}Ja^tnf z0vDI{G3H^&h4@D%U(Mq&XSWD`jGwx_0%_tABr`???y$T$bLN8Oak!)r_|G(4i4^+A z#*P|~2aKH{Nl;dJ!<$uYNAkoXOprv~D2bJ>-&}+Cu(QYJMBmVwwUzT+mArlOhrMwL zTKoL-8$0L^e?RBHOvkf*H&4=PqpN>!d%D@=PWxzZ`M?fpIRfXMYE_mJ3j>|Zp$nB= z!*6}Va;aOYMi<8OF1s8zV`bt!xw_FX7p=d5bC}`p|jy{67lLg1*u}VAL9~ zYP;bnp|X8^i*rAzdv`-rWyhs?7N+B9JY_aZDa;_MU}RdSI>&MnxW z+E{;`zJ{S6GzOP{cK!6-1@wl8|GBdfbgxjHDa#g@DwkUb_UTVNYJ+C-mb~`{Rht;8 z`>>S$c@O^7tgK=mST?x4rw#YUvXm|abix(hxbGFp*0m75E_*Y>3{%yK+KHOLIVUH| zzgqPJ=b!U;Qr6nqwW%^&`5#=N`#zs9hg4J5tyWq=ap?K?j&2RWub{EPW4}D|+As#I zl`GH64^yQpbTy0J-hMv${TDyW&S9)ygQkpccON662RhTyrCV{alid6iG3giwKX}-| zBqFU$$fdmtN-Z9@+VUew9kUK#^>HUN1Oq}jrRpPtu|)K1R>yfAhupzSKTB!j!k)XG z$EUha^%K1%VSD%?H|;3ShWaWcXjU|3x{SyS%gbbIXuPps!GNB1KH6cVMZmR=EA%9|8s9p^4;U|cs@Nb+?9dg$447ISYDB?B(oxsCvvBBS)C{t?VvWycfl$~9f1(RAaK!pKEM-v@X3u1p7xiQqr%PFZ$;=gJ8?;tAz)r8 zCSUzxAWpJ8|KC6&eFHy*3Dto&&26z#fEnuPurWz9=o-c_$QMNMpTU_nDjZ(I$|Cjv zg%>V>ABNgNh`heFta;wyV;iBrN}@EyA6ebe&*C9IC|wy?DsiP=mvb)EJNM*eTa*AK zG=zSa)N_re(3k5BuOlvV7^f}=2%0FIyuW$~R8ST)*T`v@FrYfy#E>?MWb`uu%ed4b@Sg~wuG}q z%Yf+&aN~}HM&Pr|?d(l6?sWgO6Ls1)!S74M7HpZEM4`s-nXQAn7)g&D(S*!<2wX}T z^4_soWr#86`b;(YybMYiMkRI~2~-ib33mgm*L|h5oAHgN+^R_8za{mHo?2c|MSSXE zYCks^oefY%Y-Mp-A)DoW^Z}=;NjOGSU*_tblGGNsp4p=}iobqhQdM!Ld}d?iAPiqs zKS=B*G^rXeR%?ToSB13JWO>f?U+&}brlbl^=S40j{nNDeq9=ouc;y4Rx0t+7jA}Ub z`9Q09rWj+u!>U6i3dzqz6xv86AN4v}-D!uBTJrjavhhbCEZ#d4=hB-FU16xzBjVp)&EQWuq?MZIxh1d1o-{WO*DQZg; zipw8aTiuOoz~M%1erusTLI0aHg`pyLpu|{Ypeh7SqppB3UY^Nld(^fSyiDYa7q+-X z^lBY9E_CnxuZ|>(i*4kZ@ha|M8j0~hF!{xNYX=s&Tc8SlR7MPSSp)j6n%g)Yy_H)e zCqi?VGb~DOX_?X7IFC>~7lY#&Sabwai9{a#9|GkBPU0**GsQ;RiVG{s7tg z9mHX9LeocAsXx2!UPJvYzsRG}|5s*VbdMd&<9Mq8lv(9F|mlxaeppWHpVDO*=2~TcEEPl3?et>(pF8wlEc4iEW^H5i9Umok{ zQyg6yLGVP*gEl>#IRV_*TJz2w-Pg{VJmQ6`>ZD*s8lOG({_T*YKuGV|oI86z?S@3wfRu%!S=$}; zn$tC4BX_+EqG%yBdU+b8cXwVqpWk6d599IuVQy9W3PGls61=GQIxhT}b!#K6zc(&p z^WpAPeM6aHl{}PH$1m$sT=p_&!RWo~4{fMJnlkb5c10?@&(9KTJBQzCVt?Z(BDS+7 zDtfsuUvd9Ut!`(ADwo9h3h($_dBS8Xuj=^15$rAq8+#cVTb|?whUs ztH{p#F;g_z9TpTC+XC2@ijQC>yWZJYrqEb>IqRW`An~exj`Zg7HB)oib!3gNmTF2- zTP#^Cev_Gkdku|fdnWMTGAO)Pd;1sv|LVhFYpjf4lLxB!eZC!!Nw&}Ih|vDW0IcR0 z+4T@uITF`sI$3ARM%0U%j#TF}>k8^miArD1wn0PR-Y_7K|qpD1C>UH z-Z@`~EUtIzeS;cd9F*Dr(6Zl*(Pa${`~#B{%U{Ism9uHwBk$3HzHqs%vl$`oL7(#e z^@ag;lo0Jh4*>v}WI^(^JO89~cUr&b2Bq&yhF{s=u<3XV^ZSGd3jjxczQ&`%ff4%P zHt2>ScjzeqAlF@lVP_vAxXE*C&?{kwuOF|3*f=2*(YX!?9S)gV;ThOXJ*Pd5*+Z3k zJV3qb6X5}9r>%rtk;3A&T^Ql>Pgta^6CzQL!U*%I$o|K&s%j8NsV{OL;#vu@?mY`9 za1`2#Q4ls^_cn5U`vE&&ZWW#MIJwg$bX=Y+>gw0~>awJFOAG(x*Ks@fdx-Ds3rkj^ z&K2nIhv5L$vy(mr9|8yvUkY0LM!t1L!;44|Ie9GE`4CspAX@`+ZaVqjw7KTEry4%Qms&XaOvR@iNwqcdrd1~oL*T|Jm5ZsdN1Jue}8mw0m;H zA%Z97K68j6zS_YT<<-SYnP514NtjDP$JLB559>*vc*rKKfB5u!7XVmHTd7jKwn@fa`#ia`>XTdwhfb|qiXpgm6!eF=k@1%hCpRX0F&cnuO8FIG{Yda>3arHB zHJSUkhn=S^lTF%8{rX2V`#-}s{_;;O-G`2&jV!xC4ha8y582%P`a5J7--4`G92Y{d7{}`Tw;K7qpjE^WZh1BQfc0OmH3MFYaWxRlf`7Z4`Ye?xwwI9gWy;4+bd!(Cu3=TsPIRZuf+I) z?@B5*!fTbOjN#DCU>%J*Qo|u4v4np_GjOd7T?Yhm!aB5~EC&Sg!cNTM6C{aXT~PD* zZpdO+iFP9!@L<8N#W}Qb)B)XTu=eZ(LF~SU^1lGx$vi!9pFH0B6m6C!hjoY#Yx+z4 zC)xNfnzzqKCgi`p`40ANUs|4a;41j>{{Pfsi;z`6p1;B^om)XsHl>eYHR=E /mosquitto/config/mosquitto.conf && + echo ''listener 8883'' >> /mosquitto/config/mosquitto.conf && + echo ''listener 9001'' >> /mosquitto/config/mosquitto.conf && + echo ''cafile /certs/ca.crt'' >> /mosquitto/config/mosquitto.conf && + echo ''certfile /certs/server.crt'' >> /mosquitto/config/mosquitto.conf && + echo ''keyfile /certs/server.key'' >> /mosquitto/config/mosquitto.conf && + echo ''require_certificate ''$REQUIRE_CERTIFICATE >> /mosquitto/config/mosquitto.conf && + echo ''allow_anonymous ''$ALLOW_ANONYMOUS >> /mosquitto/config/mosquitto.conf && + echo ''password_file /mosquitto/config/passwords'' >> /mosquitto/config/mosquitto.conf && + touch /mosquitto/config/passwords && + mosquitto_passwd -b -c /mosquitto/config/passwords $USERNAME $PASSWORD && + chmod 0700 /mosquitto/config/passwords && + chown mosquitto:mosquitto /mosquitto/config/passwords && + chmod 0700 /certs/* && + chown mosquitto:mosquitto /certs/* && + exec mosquitto -c /mosquitto/config/mosquitto.conf + "' + labels: + - traefik.enable=true + - traefik.tcp.routers.mqtt.entrypoints=mqtt + - traefik.tcp.routers.mqtts.entrypoints=mqtts From 080a886d3857aa76510a2437c48090d827b8f887 Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Fri, 11 Oct 2024 15:40:59 +0100 Subject: [PATCH 021/120] Change enviroment variables. --- templates/compose/mosquitto.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index 25ab30940..cc84ce99c 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -14,10 +14,10 @@ services: - "9001:9001" environment: - SERVICE_FQDN_MOSQUITTO - - "USERNAME=${USERNAME:-mosquitto}" - - "PASSWORD=${PASSWORD:-mosquitto}" - - "REQUIRE_CERTIFICATE=${REQUIRE_CERTIFICATE:-false}" - - "ALLOW_ANONYMOUS=${ALLOW_ANONYMOUS:-true}" + - MQTT_USERNAME=${MQTT_USERNAME:-mosquitto} + - MQTT_PASSWORD=${MQTT_PASSWORD:-mosquitto} + - REQUIRE_CERTIFICATE=${REQUIRE_CERTIFICATE:-false} + - ALLOW_ANONYMOUS=${ALLOW_ANONYMOUS:-true} volumes: - "./mosquitto/config:/mosquitto/config" - "./mosquitto/data:/mosquitto/data" From 845c2984fce6f6fedbf40ec7fefc9de5ab655698 Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Fri, 11 Oct 2024 15:41:45 +0100 Subject: [PATCH 022/120] Remove unnecessary bind mounts. --- templates/compose/mosquitto.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index cc84ce99c..610733a0a 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -20,8 +20,6 @@ services: - ALLOW_ANONYMOUS=${ALLOW_ANONYMOUS:-true} volumes: - "./mosquitto/config:/mosquitto/config" - - "./mosquitto/data:/mosquitto/data" - - "./mosquitto/log:/mosquitto/log" - "./certs:/certs" entrypoint: 'sh -c " echo ''listener 1883'' > /mosquitto/config/mosquitto.conf && From 15a33d129c8e74ba671294444cad925f6f1acd5f Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Fri, 11 Oct 2024 15:42:20 +0100 Subject: [PATCH 023/120] Improve config file build. --- templates/compose/mosquitto.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index 610733a0a..be9e505d9 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -25,18 +25,22 @@ services: echo ''listener 1883'' > /mosquitto/config/mosquitto.conf && echo ''listener 8883'' >> /mosquitto/config/mosquitto.conf && echo ''listener 9001'' >> /mosquitto/config/mosquitto.conf && + if [ ''$REQUIRE_CERTIFICATE'' = ''true'' ]; then echo ''cafile /certs/ca.crt'' >> /mosquitto/config/mosquitto.conf && echo ''certfile /certs/server.crt'' >> /mosquitto/config/mosquitto.conf && - echo ''keyfile /certs/server.key'' >> /mosquitto/config/mosquitto.conf && + echo ''keyfile /certs/server.key'' >> /mosquitto/config/mosquitto.conf; + fi && echo ''require_certificate ''$REQUIRE_CERTIFICATE >> /mosquitto/config/mosquitto.conf && echo ''allow_anonymous ''$ALLOW_ANONYMOUS >> /mosquitto/config/mosquitto.conf && echo ''password_file /mosquitto/config/passwords'' >> /mosquitto/config/mosquitto.conf && touch /mosquitto/config/passwords && - mosquitto_passwd -b -c /mosquitto/config/passwords $USERNAME $PASSWORD && + mosquitto_passwd -b -c /mosquitto/config/passwords $MQTT_USERNAME $MQTT_PASSWORD && chmod 0700 /mosquitto/config/passwords && + chown root:root /mosquitto/config/passwords && chown mosquitto:mosquitto /mosquitto/config/passwords && - chmod 0700 /certs/* && - chown mosquitto:mosquitto /certs/* && + chmod 0700 /certs/ && + chown root:root /certs/ && + chown mosquitto:mosquitto /certs/ && exec mosquitto -c /mosquitto/config/mosquitto.conf "' labels: From c54b865beea1fe21e967204a2d3e33e49cf5fb16 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:40:16 +0200 Subject: [PATCH 024/120] fix cal.com --- templates/compose/calcom.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/templates/compose/calcom.yaml b/templates/compose/calcom.yaml index c7ea7744c..2e7bca8ae 100644 --- a/templates/compose/calcom.yaml +++ b/templates/compose/calcom.yaml @@ -7,6 +7,7 @@ services: calcom: image: calcom.docker.scarf.sh/calcom/cal.com + platform: linux/amd64 environment: # Some variables still uses Calcom previous name, Calendso # @@ -21,9 +22,9 @@ services: - NEXTAUTH_URL=${SERVICE_FQDN_CALCOM}/api/auth # It is highly recommended that the NEXTAUTH_SECRET must be overridden and very unique # Use `openssl rand -base64 32` to generate a key - - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-$SERVICE_BASE64_CALCOM_SECRET} + - NEXTAUTH_SECRET=${SERVICE_BASE64_CALCOMSECRET} # Encryption key that will be used to encrypt CalDAV credentials, choose a random string, for example with `dd if=/dev/urandom bs=1K count=1 | md5sum` - - CALENDSO_ENCRYPTION_KEY=${CALENDSO_ENCRYPTION_KEY:-$SERVICE_BASE64_CALCOM_KEY} + - CALENDSO_ENCRYPTION_KEY=${SERVICE_BASE64_CALCOMKEY} - POSTGRES_USER=${SERVICE_USER_POSTGRES} - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} - POSTGRES_DB=${POSTGRES_DB:-calendso} @@ -54,13 +55,13 @@ services: environment: - POSTGRES_USER=${SERVICE_USER_POSTGRES} - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} - - POSTGRES_DB=${POSTGRES_DATABASE:-calcom} + - POSTGRES_DB=${POSTGRES_DB:-calendso} volumes: - calcom-postgresql-data:/var/lib/postgresql/data healthcheck: test: - CMD-SHELL - - pg_isready -U ${SERVICE_USER_POSTGRES} -d ${POSTGRES_DATABASE:-calcom} + - pg_isready -U ${SERVICE_USER_POSTGRES} -d ${POSTGRES_DB:-calendso} interval: 10s timeout: 5s retries: 5 From d34c4dd1e82582bcde73f7f4c6ba2a068a941e00 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:40:27 +0200 Subject: [PATCH 025/120] Update service-templates.json --- templates/service-templates.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/templates/service-templates.json b/templates/service-templates.json index 664eb1ade..074a2cebd 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -224,6 +224,21 @@ "minversion": "0.0.0", "port": "10000" }, + "calcom": { + "documentation": "https://cal.com/docs?utm_source=coolify.io", + "slogan": "Scheduling infrastructure for everyone.", + "compose": "c2VydmljZXM6CiAgY2FsY29tOgogICAgaW1hZ2U6IGNhbGNvbS5kb2NrZXIuc2NhcmYuc2gvY2FsY29tL2NhbC5jb20KICAgIHBsYXRmb3JtOiBsaW51eC9hbWQ2NAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0NBTENPTV8zMDAwCiAgICAgIC0gTkVYVF9QVUJMSUNfTElDRU5TRV9DT05TRU5UPWFncmVlCiAgICAgIC0gTk9ERV9FTlY9cHJvZHVjdGlvbgogICAgICAtICdORVhUX1BVQkxJQ19XRUJBUFBfVVJMPSR7U0VSVklDRV9GUUROX0NBTENPTX0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQSV9WMl9VUkw9JHtTRVJWSUNFX0ZRRE5fQ0FMQ09NfS9hcGkvdjInCiAgICAgIC0gJ05FWFRBVVRIX1VSTD0ke1NFUlZJQ0VfRlFETl9DQUxDT019L2FwaS9hdXRoJwogICAgICAtICdORVhUQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF9DQUxDT01TRUNSRVR9JwogICAgICAtICdDQUxFTkRTT19FTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfQkFTRTY0X0NBTENPTUtFWX0nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1jYWxlbmRzb30nCiAgICAgIC0gREFUQUJBU0VfSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AJHtEQVRBQkFTRV9IT1NUOi1wb3N0Z3Jlc3FsfS8ke1BPU1RHUkVTX0RCOi1jYWxlbmRzb30nCiAgICAgIC0gJ0RBVEFCQVNFX0RJUkVDVF9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QCR7REFUQUJBU0VfSE9TVDotcG9zdGdyZXNxbH0vJHtQT1NUR1JFU19EQjotY2FsZW5kc299JwogICAgICAtIENBTENPTV9URUxFTUVUUllfRElTQUJMRUQ9MQogICAgICAtICdFTUFJTF9GUk9NPSR7RU1BSUxfRlJPTX0nCiAgICAgIC0gJ0VNQUlMX0ZST01fTkFNRT0ke0VNQUlMX0ZST01fTkFNRX0nCiAgICAgIC0gJ0VNQUlMX1NFUlZFUl9IT1NUPSR7RU1BSUxfU0VSVkVSX0hPU1R9JwogICAgICAtICdFTUFJTF9TRVJWRVJfUE9SVD0ke0VNQUlMX1NFUlZFUl9QT1JUfScKICAgICAgLSAnRU1BSUxfU0VSVkVSX1VTRVI9JHtFTUFJTF9TRVJWRVJfVVNFUn0nCiAgICAgIC0gJ0VNQUlMX1NFUlZFUl9QQVNTV09SRD0ke0VNQUlMX1NFUlZFUl9QQVNTV09SRH0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQUF9OQU1FPSJDYWwuY29tIicKICAgICAgLSAnQUxMT1dFRF9IT1NUTkFNRVM9WyIke1NFUlZJQ0VfRlFETl9DQUxDT019Il0nCiAgICBkZXBlbmRzX29uOgogICAgICAtIHBvc3RncmVzcWwKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWNhbGVuZHNvfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2NhbGNvbS1wb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfSAtZCAke1BPU1RHUkVTX0RCOi1jYWxlbmRzb30nCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogICAgcmVzdGFydDogdW5sZXNzLXN0b3BwZWQK", + "tags": [ + "calcom", + "calendso", + "scheduling", + "open", + "source" + ], + "logo": "svgs/calcom.svg", + "minversion": "0.0.0", + "port": "3000" + }, "castopod": { "documentation": "https://docs.castopod.org/main/en/?utm_source=coolify.io", "slogan": "Castopod is a free & open-source hosting platform made for podcasters who want engage and interact with their audience.", From abaccdf03dc753f9a8ffb3d7c6286a6dfd5d7a66 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:05:05 +0200 Subject: [PATCH 026/120] fix calcom postgres healthcheck --- templates/compose/calcom.yaml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/templates/compose/calcom.yaml b/templates/compose/calcom.yaml index 2e7bca8ae..89f3376ee 100644 --- a/templates/compose/calcom.yaml +++ b/templates/compose/calcom.yaml @@ -59,10 +59,7 @@ services: volumes: - calcom-postgresql-data:/var/lib/postgresql/data healthcheck: - test: - - CMD-SHELL - - pg_isready -U ${SERVICE_USER_POSTGRES} -d ${POSTGRES_DB:-calendso} - interval: 10s - timeout: 5s - retries: 5 - restart: unless-stopped + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 5s + timeout: 20s + retries: 10 From b6cd54ccbc70af5502c4cbce674cc6223703fde9 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:21:41 +0200 Subject: [PATCH 027/120] fix edgedb --- templates/compose/edgedb.yaml | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/templates/compose/edgedb.yaml b/templates/compose/edgedb.yaml index a4e127fa5..c305895ee 100644 --- a/templates/compose/edgedb.yaml +++ b/templates/compose/edgedb.yaml @@ -1,3 +1,4 @@ +# ignore: true # documentation: https://www.edgedb.com # slogan: An open-source database designed as a spiritual successor to SQL and the relational paradigm. Powered by the Postgres query engine under the hood. # tags: db database sql @@ -8,38 +9,33 @@ services: edgedb: image: edgedb/edgedb environment: - - SERVICE_FQDN_EDGEDB + - SERVICE_FQDN_EDGEDB_5656 - EDGEDB_SERVER_ADMIN_UI=${EDGEDB_SERVER_ADMIN_UI:-enabled} - - EDGEDB_SERVER_BACKEND_DSN=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB - - EDGEDB_SERVER_SECURITY=strict - - EDGEDB_SERVER_PASSWORD=$SERVICE_EDGEDB_SERVER_PASSWORD - - EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed - # - EDGEDB_SERVER_TLS_CERT_FILE= # Ideally Coolify should generate its own certificates - # - EDGEDB_SERVER_TLS_KEY_FILE= # -- || -- + - EDGEDB_SERVER_BACKEND_DSN=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgresql:5432/${POSTGRES_DB:-edgedb} + - EDGEDB_SERVER_SECURITY=${EDGEDB_SERVER_SECURITY:-strict} + - EDGEDB_SERVER_PASSWORD=${SERVICE_PASSWORD_EDGEDB} - POSTGRES_DB=${POSTGRES_DB:-edgedb} - depends_on: postgresql: condition: service_healthy volumes: - - "./dbschema:/dbschema" + - edgedb-data:/dbschema healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5656/server/status/alive"] interval: 5s timeout: 20s retries: 10 - ports: - - "5656:5656" + postgresql: image: postgres:16-alpine volumes: - - postgresql-data:/var/lib/postgresql/data + - edgedb-postgresql-data:/var/lib/postgresql/data environment: - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} - POSTGRES_DB=${POSTGRES_DB:-edgedb} healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 20s - retries: 10 \ No newline at end of file + retries: 10 From bd18ca5817c455ef2dfc4ce684e7ec2eaa26608f Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:22:32 +0200 Subject: [PATCH 028/120] Update service-templates.json --- templates/service-templates.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/service-templates.json b/templates/service-templates.json index 074a2cebd..ebfca7623 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -227,7 +227,7 @@ "calcom": { "documentation": "https://cal.com/docs?utm_source=coolify.io", "slogan": "Scheduling infrastructure for everyone.", - "compose": "c2VydmljZXM6CiAgY2FsY29tOgogICAgaW1hZ2U6IGNhbGNvbS5kb2NrZXIuc2NhcmYuc2gvY2FsY29tL2NhbC5jb20KICAgIHBsYXRmb3JtOiBsaW51eC9hbWQ2NAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0NBTENPTV8zMDAwCiAgICAgIC0gTkVYVF9QVUJMSUNfTElDRU5TRV9DT05TRU5UPWFncmVlCiAgICAgIC0gTk9ERV9FTlY9cHJvZHVjdGlvbgogICAgICAtICdORVhUX1BVQkxJQ19XRUJBUFBfVVJMPSR7U0VSVklDRV9GUUROX0NBTENPTX0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQSV9WMl9VUkw9JHtTRVJWSUNFX0ZRRE5fQ0FMQ09NfS9hcGkvdjInCiAgICAgIC0gJ05FWFRBVVRIX1VSTD0ke1NFUlZJQ0VfRlFETl9DQUxDT019L2FwaS9hdXRoJwogICAgICAtICdORVhUQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF9DQUxDT01TRUNSRVR9JwogICAgICAtICdDQUxFTkRTT19FTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfQkFTRTY0X0NBTENPTUtFWX0nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1jYWxlbmRzb30nCiAgICAgIC0gREFUQUJBU0VfSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AJHtEQVRBQkFTRV9IT1NUOi1wb3N0Z3Jlc3FsfS8ke1BPU1RHUkVTX0RCOi1jYWxlbmRzb30nCiAgICAgIC0gJ0RBVEFCQVNFX0RJUkVDVF9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QCR7REFUQUJBU0VfSE9TVDotcG9zdGdyZXNxbH0vJHtQT1NUR1JFU19EQjotY2FsZW5kc299JwogICAgICAtIENBTENPTV9URUxFTUVUUllfRElTQUJMRUQ9MQogICAgICAtICdFTUFJTF9GUk9NPSR7RU1BSUxfRlJPTX0nCiAgICAgIC0gJ0VNQUlMX0ZST01fTkFNRT0ke0VNQUlMX0ZST01fTkFNRX0nCiAgICAgIC0gJ0VNQUlMX1NFUlZFUl9IT1NUPSR7RU1BSUxfU0VSVkVSX0hPU1R9JwogICAgICAtICdFTUFJTF9TRVJWRVJfUE9SVD0ke0VNQUlMX1NFUlZFUl9QT1JUfScKICAgICAgLSAnRU1BSUxfU0VSVkVSX1VTRVI9JHtFTUFJTF9TRVJWRVJfVVNFUn0nCiAgICAgIC0gJ0VNQUlMX1NFUlZFUl9QQVNTV09SRD0ke0VNQUlMX1NFUlZFUl9QQVNTV09SRH0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQUF9OQU1FPSJDYWwuY29tIicKICAgICAgLSAnQUxMT1dFRF9IT1NUTkFNRVM9WyIke1NFUlZJQ0VfRlFETl9DQUxDT019Il0nCiAgICBkZXBlbmRzX29uOgogICAgICAtIHBvc3RncmVzcWwKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWNhbGVuZHNvfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2NhbGNvbS1wb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfSAtZCAke1BPU1RHUkVTX0RCOi1jYWxlbmRzb30nCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogICAgcmVzdGFydDogdW5sZXNzLXN0b3BwZWQK", + "compose": "c2VydmljZXM6CiAgY2FsY29tOgogICAgaW1hZ2U6IGNhbGNvbS5kb2NrZXIuc2NhcmYuc2gvY2FsY29tL2NhbC5jb20KICAgIHBsYXRmb3JtOiBsaW51eC9hbWQ2NAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0NBTENPTV8zMDAwCiAgICAgIC0gTkVYVF9QVUJMSUNfTElDRU5TRV9DT05TRU5UPWFncmVlCiAgICAgIC0gTk9ERV9FTlY9cHJvZHVjdGlvbgogICAgICAtICdORVhUX1BVQkxJQ19XRUJBUFBfVVJMPSR7U0VSVklDRV9GUUROX0NBTENPTX0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQSV9WMl9VUkw9JHtTRVJWSUNFX0ZRRE5fQ0FMQ09NfS9hcGkvdjInCiAgICAgIC0gJ05FWFRBVVRIX1VSTD0ke1NFUlZJQ0VfRlFETl9DQUxDT019L2FwaS9hdXRoJwogICAgICAtICdORVhUQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF9DQUxDT01TRUNSRVR9JwogICAgICAtICdDQUxFTkRTT19FTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfQkFTRTY0X0NBTENPTUtFWX0nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1jYWxlbmRzb30nCiAgICAgIC0gREFUQUJBU0VfSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AJHtEQVRBQkFTRV9IT1NUOi1wb3N0Z3Jlc3FsfS8ke1BPU1RHUkVTX0RCOi1jYWxlbmRzb30nCiAgICAgIC0gJ0RBVEFCQVNFX0RJUkVDVF9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QCR7REFUQUJBU0VfSE9TVDotcG9zdGdyZXNxbH0vJHtQT1NUR1JFU19EQjotY2FsZW5kc299JwogICAgICAtIENBTENPTV9URUxFTUVUUllfRElTQUJMRUQ9MQogICAgICAtICdFTUFJTF9GUk9NPSR7RU1BSUxfRlJPTX0nCiAgICAgIC0gJ0VNQUlMX0ZST01fTkFNRT0ke0VNQUlMX0ZST01fTkFNRX0nCiAgICAgIC0gJ0VNQUlMX1NFUlZFUl9IT1NUPSR7RU1BSUxfU0VSVkVSX0hPU1R9JwogICAgICAtICdFTUFJTF9TRVJWRVJfUE9SVD0ke0VNQUlMX1NFUlZFUl9QT1JUfScKICAgICAgLSAnRU1BSUxfU0VSVkVSX1VTRVI9JHtFTUFJTF9TRVJWRVJfVVNFUn0nCiAgICAgIC0gJ0VNQUlMX1NFUlZFUl9QQVNTV09SRD0ke0VNQUlMX1NFUlZFUl9QQVNTV09SRH0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQUF9OQU1FPSJDYWwuY29tIicKICAgICAgLSAnQUxMT1dFRF9IT1NUTkFNRVM9WyIke1NFUlZJQ0VfRlFETl9DQUxDT019Il0nCiAgICBkZXBlbmRzX29uOgogICAgICAtIHBvc3RncmVzcWwKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWNhbGVuZHNvfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2NhbGNvbS1wb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=", "tags": [ "calcom", "calendso", From c0c77d711af4c1b38f5ab91650dacdc9032a148a Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:46:58 +0200 Subject: [PATCH 029/120] Update azimutt.yaml --- templates/compose/azimutt.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/compose/azimutt.yaml b/templates/compose/azimutt.yaml index 314d4479a..4b498e423 100644 --- a/templates/compose/azimutt.yaml +++ b/templates/compose/azimutt.yaml @@ -9,9 +9,9 @@ services: postgres: image: postgres:15 environment: - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_DB=azimutt + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_DB=${POSTGRES_DB:-azimutt} volumes: - azimutt-postgres-data:/var/lib/postgresql/data healthcheck: @@ -80,8 +80,8 @@ services: - PHX_SERVER=true - PHX_HOST=$SERVICE_URL_AZIMUTT - PORT=${PORT:-4000} - - DATABASE_URL=ecto://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgres/azimutt - - SECRET_KEY_BASE=$SERVICE_BASE64_64_AZIMUTT + - DATABASE_URL=ecto://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres/${POSTGRES_DB:-azimutt} + - SECRET_KEY_BASE=${SERVICE_BASE64_64_AZIMUTT} - FILE_STORAGE_ADAPTER=${FILE_STORAGE_ADAPTER:-s3} - AUTH_PASSWORD=${AUTH_PASSWORD:-true} - SKIP_ONBOARDING_FUNNEL=${SKIP_ONBOARDING_FUNNEL:-true} From 4caca0dfe59593e5d61327da0cd79ea2c6191268 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:57:09 +0200 Subject: [PATCH 030/120] fix plausible --- templates/compose/plausible.yaml | 53 ++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/templates/compose/plausible.yaml b/templates/compose/plausible.yaml index e02e92d38..25b5c6938 100644 --- a/templates/compose/plausible.yaml +++ b/templates/compose/plausible.yaml @@ -10,31 +10,53 @@ services: command: 'sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"' environment: - SERVICE_FQDN_PLAUSIBLE - - "DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@plausible_db/plausible" + - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@plausible-db:5432/${POSTGRES_DB:-plausible-db} + - CLICKHOUSE_DATABASE_URL=http://plausible-events-db:8123/plausible_events_db - BASE_URL=$SERVICE_FQDN_PLAUSIBLE - SECRET_KEY_BASE=$SERVICE_BASE64_64_PLAUSIBLE - TOTP_VAULT_KEY=$SERVICE_REALBASE64_32_TOTP depends_on: - - plausible_db - - plausible_events_db - - mail + plausible-db: + condition: service_healthy + plausible-events-db: + condition: service_healthy + mail: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8000/ping"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 45s + + mail: image: bytemark/smtp + platform: linux/amd64 + healthcheck: + test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/25' || exit 1"] + interval: 5s + timeout: 10s + retries: 20 - plausible_db: + plausible-db: image: "postgres:16-alpine" volumes: - - "db-data:/var/lib/postgresql/data" + - plausible-postgres-data:/var/lib/postgresql/data environment: - - POSTGRES_DB=plausible - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - POSTGRES_DB=${POSTGRES_DB:-plausible-db} + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 5s + timeout: 20s + retries: 10 - plausible_events_db: + plausible-events-db: image: "clickhouse/clickhouse-server:24.3.3.102-alpine" volumes: - - type: volume - source: event-data - target: /var/lib/clickhouse + - plausible-events-data:/var/lib/clickhouse - type: bind source: ./clickhouse/clickhouse-config.xml target: /etc/clickhouse-server/config.d/logging.xml @@ -49,3 +71,10 @@ services: nofile: soft: 262144 hard: 262144 + healthcheck: + test: + [ + "CMD-SHELL", + "wget --no-verbose --tries=1 -O - http://127.0.0.1:8123/ping || exit 1", + ] + start_period: 30s From a7dc8fa2ccc7cabd4f50ffc98e1c46d510574749 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:57:45 +0200 Subject: [PATCH 031/120] format --- templates/compose/plausible.yaml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/templates/compose/plausible.yaml b/templates/compose/plausible.yaml index 25b5c6938..d932316d8 100644 --- a/templates/compose/plausible.yaml +++ b/templates/compose/plausible.yaml @@ -23,13 +23,20 @@ services: mail: condition: service_healthy healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8000/ping"] + test: + [ + "CMD", + "wget", + "--no-verbose", + "--tries=1", + "--spider", + "http://127.0.0.1:8000/ping", + ] interval: 10s timeout: 5s retries: 5 start_period: 45s - mail: image: bytemark/smtp platform: linux/amd64 From c3311133c200e9577c698de0a978468dbe445928 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:43:47 +0200 Subject: [PATCH 032/120] fix windmill healthchecks --- templates/compose/windmill.yaml | 10 +++++----- templates/service-templates.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/compose/windmill.yaml b/templates/compose/windmill.yaml index a14854ba0..1326870c2 100644 --- a/templates/compose/windmill.yaml +++ b/templates/compose/windmill.yaml @@ -32,7 +32,7 @@ services: volumes: - worker-logs:/tmp/windmill/logs healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"] + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 @@ -51,7 +51,7 @@ services: - worker-dependency-cache:/tmp/windmill/cache - worker-logs:/tmp/windmill/logs healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"] + test: ["CMD-SHELL", "exit 0"] interval: 30s timeout: 10s retries: 3 @@ -70,7 +70,7 @@ services: - worker-dependency-cache:/tmp/windmill/cache - worker-logs:/tmp/windmill/logs healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"] + test: ["CMD-SHELL", "exit 0"] interval: 30s timeout: 10s retries: 3 @@ -89,7 +89,7 @@ services: - worker-dependency-cache:/tmp/windmill/cache - worker-logs:/tmp/windmill/logs healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"] + test: ["CMD-SHELL", "exit 0"] interval: 30s timeout: 10s retries: 3 @@ -108,7 +108,7 @@ services: volumes: - worker-logs:/tmp/windmill/logs healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"] + test: ["CMD-SHELL", "exit 0"] interval: 30s timeout: 10s retries: 3 diff --git a/templates/service-templates.json b/templates/service-templates.json index ebfca7623..7ebdfe604 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -2639,7 +2639,7 @@ "windmill": { "documentation": "https://www.windmill.dev/docs/?utm_source=coolify.io", "slogan": "Windmill is a developer platform to build production-grade multi-steps automations and internal apps.", - "compose": "c2VydmljZXM6CiAgZGI6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgc2htX3NpemU6IDFnCiAgICB2b2x1bWVzOgogICAgICAtICdkYi1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXdpbmRtaWxsfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSBwb3N0Z3JlcycKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgd2luZG1pbGwtc2VydmVyOgogICAgaW1hZ2U6ICdnaGNyLmlvL3dpbmRtaWxsLWxhYnMvd2luZG1pbGw6bWFpbicKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9XSU5ETUlMTF84MDAwCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovL3Bvc3RncmVzOiRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTQGRiL3dpbmRtaWxsJwogICAgICAtICdNT0RFPSR7TU9ERTotc2VydmVyfScKICAgICAgLSBCQVNFX1VSTD0kU0VSVklDRV9GUUROX1dJTkRNSUxMCiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwMDAvYXBpL3ZlcnNpb24gfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLTE6CiAgICBpbWFnZTogJ2doY3IuaW8vd2luZG1pbGwtbGFicy93aW5kbWlsbDptYWluJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovL3Bvc3RncmVzOiRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTQGRiL3dpbmRtaWxsJwogICAgICAtICdNT0RFPSR7TU9ERTotd29ya2VyfScKICAgICAgLSAnV09SS0VSX0dST1VQPSR7V09SS0VSX0dST1VQOi1kZWZhdWx0fScKICAgIGRlcGVuZHNfb246CiAgICAgIGRiOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICB2b2x1bWVzOgogICAgICAtICcvdmFyL3J1bi9kb2NrZXIuc29jazovdmFyL3J1bi9kb2NrZXIuc29jaycKICAgICAgLSAnd29ya2VyLWRlcGVuZGVuY3ktY2FjaGU6L3RtcC93aW5kbWlsbC9jYWNoZScKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwMDAvYXBpL3ZlcnNpb24gfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLTI6CiAgICBpbWFnZTogJ2doY3IuaW8vd2luZG1pbGwtbGFicy93aW5kbWlsbDptYWluJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovL3Bvc3RncmVzOiRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTQGRiL3dpbmRtaWxsJwogICAgICAtICdNT0RFPSR7TU9ERTotd29ya2VyfScKICAgICAgLSAnV09SS0VSX0dST1VQPSR7V09SS0VSX0dST1VQOi1kZWZhdWx0fScKICAgIGRlcGVuZHNfb246CiAgICAgIGRiOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICB2b2x1bWVzOgogICAgICAtICcvdmFyL3J1bi9kb2NrZXIuc29jazovdmFyL3J1bi9kb2NrZXIuc29jaycKICAgICAgLSAnd29ya2VyLWRlcGVuZGVuY3ktY2FjaGU6L3RtcC93aW5kbWlsbC9jYWNoZScKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwMDAvYXBpL3ZlcnNpb24gfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLTM6CiAgICBpbWFnZTogJ2doY3IuaW8vd2luZG1pbGwtbGFicy93aW5kbWlsbDptYWluJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovL3Bvc3RncmVzOiRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTQGRiL3dpbmRtaWxsJwogICAgICAtICdNT0RFPSR7TU9ERTotd29ya2VyfScKICAgICAgLSAnV09SS0VSX0dST1VQPSR7V09SS0VSX0dST1VQOi1kZWZhdWx0fScKICAgIGRlcGVuZHNfb246CiAgICAgIGRiOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICB2b2x1bWVzOgogICAgICAtICcvdmFyL3J1bi9kb2NrZXIuc29jazovdmFyL3J1bi9kb2NrZXIuc29jaycKICAgICAgLSAnd29ya2VyLWRlcGVuZGVuY3ktY2FjaGU6L3RtcC93aW5kbWlsbC9jYWNoZScKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwMDAvYXBpL3ZlcnNpb24gfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLW5hdGl2ZToKICAgIGltYWdlOiAnZ2hjci5pby93aW5kbWlsbC1sYWJzL3dpbmRtaWxsOm1haW4nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vcG9zdGdyZXM6JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNAZGIvd2luZG1pbGwnCiAgICAgIC0gJ01PREU9JHtNT0RFOi13b3JrZXJ9JwogICAgICAtICdXT1JLRVJfR1JPVVA9JHtXT1JLRVJfR1JPVVA6LW5hdGl2ZX0nCiAgICAgIC0gJ05VTV9XT1JLRVJTPSR7TlVNX1dPUktFUlM6LTh9JwogICAgICAtICdTTEVFUF9RVUVVRT0ke1NMRUVQX1FVRVVFOi0yMDB9JwogICAgZGVwZW5kc19vbjoKICAgICAgZGI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3dvcmtlci1sb2dzOi90bXAvd2luZG1pbGwvbG9ncycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo4MDAwL2FwaS92ZXJzaW9uIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwogIGxzcDoKICAgIGltYWdlOiAnZ2hjci5pby93aW5kbWlsbC1sYWJzL3dpbmRtaWxsLWxzcDpsYXRlc3QnCiAgICB2b2x1bWVzOgogICAgICAtICdsc3AtY2FjaGU6L3Jvb3QvLmNhY2hlJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdleGl0IDAnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMK", + "compose": "c2VydmljZXM6CiAgZGI6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgc2htX3NpemU6IDFnCiAgICB2b2x1bWVzOgogICAgICAtICdkYi1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXdpbmRtaWxsfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSBwb3N0Z3JlcycKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgd2luZG1pbGwtc2VydmVyOgogICAgaW1hZ2U6ICdnaGNyLmlvL3dpbmRtaWxsLWxhYnMvd2luZG1pbGw6bWFpbicKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9XSU5ETUlMTF84MDAwCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovL3Bvc3RncmVzOiRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTQGRiL3dpbmRtaWxsJwogICAgICAtICdNT0RFPSR7TU9ERTotc2VydmVyfScKICAgICAgLSBCQVNFX1VSTD0kU0VSVklDRV9GUUROX1dJTkRNSUxMCiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwMDAvaGVhbHRoJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLTE6CiAgICBpbWFnZTogJ2doY3IuaW8vd2luZG1pbGwtbGFicy93aW5kbWlsbDptYWluJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovL3Bvc3RncmVzOiRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTQGRiL3dpbmRtaWxsJwogICAgICAtICdNT0RFPSR7TU9ERTotd29ya2VyfScKICAgICAgLSAnV09SS0VSX0dST1VQPSR7V09SS0VSX0dST1VQOi1kZWZhdWx0fScKICAgIGRlcGVuZHNfb246CiAgICAgIGRiOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICB2b2x1bWVzOgogICAgICAtICcvdmFyL3J1bi9kb2NrZXIuc29jazovdmFyL3J1bi9kb2NrZXIuc29jaycKICAgICAgLSAnd29ya2VyLWRlcGVuZGVuY3ktY2FjaGU6L3RtcC93aW5kbWlsbC9jYWNoZScKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdleGl0IDAnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICB3aW5kbWlsbC13b3JrZXItMjoKICAgIGltYWdlOiAnZ2hjci5pby93aW5kbWlsbC1sYWJzL3dpbmRtaWxsOm1haW4nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vcG9zdGdyZXM6JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNAZGIvd2luZG1pbGwnCiAgICAgIC0gJ01PREU9JHtNT0RFOi13b3JrZXJ9JwogICAgICAtICdXT1JLRVJfR1JPVVA9JHtXT1JLRVJfR1JPVVA6LWRlZmF1bHR9JwogICAgZGVwZW5kc19vbjoKICAgICAgZGI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIHZvbHVtZXM6CiAgICAgIC0gJy92YXIvcnVuL2RvY2tlci5zb2NrOi92YXIvcnVuL2RvY2tlci5zb2NrJwogICAgICAtICd3b3JrZXItZGVwZW5kZW5jeS1jYWNoZTovdG1wL3dpbmRtaWxsL2NhY2hlJwogICAgICAtICd3b3JrZXItbG9nczovdG1wL3dpbmRtaWxsL2xvZ3MnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2V4aXQgMCcKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwogIHdpbmRtaWxsLXdvcmtlci0zOgogICAgaW1hZ2U6ICdnaGNyLmlvL3dpbmRtaWxsLWxhYnMvd2luZG1pbGw6bWFpbicKICAgIGVudmlyb25tZW50OgogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXM6Ly9wb3N0Z3JlczokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0BkYi93aW5kbWlsbCcKICAgICAgLSAnTU9ERT0ke01PREU6LXdvcmtlcn0nCiAgICAgIC0gJ1dPUktFUl9HUk9VUD0ke1dPUktFUl9HUk9VUDotZGVmYXVsdH0nCiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnL3Zhci9ydW4vZG9ja2VyLnNvY2s6L3Zhci9ydW4vZG9ja2VyLnNvY2snCiAgICAgIC0gJ3dvcmtlci1kZXBlbmRlbmN5LWNhY2hlOi90bXAvd2luZG1pbGwvY2FjaGUnCiAgICAgIC0gJ3dvcmtlci1sb2dzOi90bXAvd2luZG1pbGwvbG9ncycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLW5hdGl2ZToKICAgIGltYWdlOiAnZ2hjci5pby93aW5kbWlsbC1sYWJzL3dpbmRtaWxsOm1haW4nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vcG9zdGdyZXM6JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNAZGIvd2luZG1pbGwnCiAgICAgIC0gJ01PREU9JHtNT0RFOi13b3JrZXJ9JwogICAgICAtICdXT1JLRVJfR1JPVVA9JHtXT1JLRVJfR1JPVVA6LW5hdGl2ZX0nCiAgICAgIC0gJ05VTV9XT1JLRVJTPSR7TlVNX1dPUktFUlM6LTh9JwogICAgICAtICdTTEVFUF9RVUVVRT0ke1NMRUVQX1FVRVVFOi0yMDB9JwogICAgZGVwZW5kc19vbjoKICAgICAgZGI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3dvcmtlci1sb2dzOi90bXAvd2luZG1pbGwvbG9ncycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgbHNwOgogICAgaW1hZ2U6ICdnaGNyLmlvL3dpbmRtaWxsLWxhYnMvd2luZG1pbGwtbHNwOmxhdGVzdCcKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2xzcC1jYWNoZTovcm9vdC8uY2FjaGUnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2V4aXQgMCcKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwo=", "tags": [ "windmill", "workflow", From 8a2c9f3d443820541fbf14682efa0dd5b2fc319c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 17:54:29 +0200 Subject: [PATCH 033/120] updates sentinel --- app/Jobs/PushServerUpdateJob.php | 312 +++++++++++++++++++++++++------ 1 file changed, 259 insertions(+), 53 deletions(-) diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 226cf9392..a426e8532 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -2,17 +2,20 @@ namespace App\Jobs; +use App\Actions\Database\StartDatabaseProxy; use App\Actions\Proxy\StartProxy; +use App\Actions\Shared\ComplexStatusCheck; use App\Models\Application; use App\Models\ApplicationPreview; use App\Models\Server; +use App\Models\ServiceApplication; +use App\Models\ServiceDatabase; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Collection; -use Illuminate\Support\Facades\Log; class PushServerUpdateJob implements ShouldQueue { @@ -20,7 +23,33 @@ class PushServerUpdateJob implements ShouldQueue public $tries = 1; - public $timeout = 60; + public $timeout = 30; + + public Collection $containers; + + public Collection $allApplicationIds; + + public Collection $allDatabaseUuids; + + public Collection $allServiceApplicationIds; + + public Collection $allApplicationPreviewsIds; + + public Collection $allServiceDatabaseIds; + + public Collection $allApplicationsWithAdditionalServers; + + public Collection $foundApplicationIds; + + public Collection $foundDatabaseUuids; + + public Collection $foundServiceApplicationIds; + + public Collection $foundServiceDatabaseIds; + + public Collection $foundApplicationPreviewsIds; + + public bool $foundProxy = false; public function backoff(): int { @@ -29,12 +58,19 @@ public function backoff(): int public function __construct(public Server $server, public $data) { - // TODO: Handle multiple servers - // TODO: Handle Preview deployments - // TODO: Handle DB TCP proxies - // TODO: Handle DBs - // TODO: Handle services - // TODO: Handle proxies + // TODO: Handle multiple servers - done - NOT TESTED + // TODO: Handle Preview deployments - done - NOT TESTED + $this->containers = collect(); + $this->foundApplicationIds = collect(); + $this->foundDatabaseUuids = collect(); + $this->foundServiceApplicationIds = collect(); + $this->foundApplicationPreviewsIds = collect(); + $this->foundServiceDatabaseIds = collect(); + $this->allApplicationIds = collect(); + $this->allDatabaseUuids = collect(); + $this->allTcpProxyUuids = collect(); + $this->allServiceApplicationIds = collect(); + $this->allServiceDatabaseIds = collect(); } public function handle() @@ -43,14 +79,34 @@ public function handle() throw new \Exception('No data provided'); } $data = collect($this->data); - $containers = collect(data_get($data, 'containers')); - if ($containers->isEmpty()) { + $this->containers = collect(data_get($data, 'containers')); + if ($this->containers->isEmpty()) { return; } - $foundApplicationIds = collect(); - $foundServiceIds = collect(); - $foundProxy = false; - foreach ($containers as $container) { + $this->allApplicationIds = $this->server->applications() + ->filter(function ($application) { + return $application->additional_servers->count() === 0; + }) + ->pluck('id'); + $this->allApplicationsWithAdditionalServers = $this->server->applications() + ->filter(function ($application) { + return $application->additional_servers->count() > 0; + }); + $this->allApplicationPreviewsIds = $this->server->previews()->pluck('id'); + $this->allDatabaseUuids = $this->server->databases()->pluck('uuid'); + $this->allTcpProxyUuids = $this->server->databases()->where('is_public', true)->pluck('uuid'); + $this->server->services()->each(function ($service) { + $service->applications()->pluck('id')->each(function ($applicationId) { + $this->allServiceApplicationIds->push($applicationId); + }); + $service->databases()->pluck('id')->each(function ($databaseId) { + $this->allServiceDatabaseIds->push($databaseId); + }); + }); + + logger('allServiceApplicationIds', ['allServiceApplicationIds' => $this->allServiceApplicationIds]); + + foreach ($this->containers as $container) { $containerStatus = data_get($container, 'state', 'exited'); $containerHealth = data_get($container, 'health_status', 'unhealthy'); $containerStatus = "$containerStatus ($containerHealth)"; @@ -60,77 +116,227 @@ public function handle() if ($labels->has('coolify.applicationId')) { $applicationId = $labels->get('coolify.applicationId'); $pullRequestId = data_get($labels, 'coolify.pullRequestId', '0'); - $foundApplicationIds->push($applicationId); try { - $this->updateApplicationStatus($applicationId, $pullRequestId, $containerStatus); + if ($pullRequestId === '0') { + if ($this->allApplicationIds->contains($applicationId)) { + $this->foundApplicationIds->push($applicationId); + } + $this->updateApplicationStatus($applicationId, $containerStatus); + } else { + if ($this->allApplicationPreviewsIds->contains($applicationId)) { + $this->foundApplicationPreviewsIds->push($applicationId); + } + $this->updateApplicationPreviewStatus($applicationId, $containerStatus); + } } catch (\Exception $e) { - Log::error($e); + logger()->error($e); } } elseif ($labels->has('coolify.serviceId')) { $serviceId = $labels->get('coolify.serviceId'); - $foundServiceIds->push($serviceId); - Log::info("Service: $serviceId, $containerStatus"); + $subType = $labels->get('coolify.service.subType'); + $subId = $labels->get('coolify.service.subId'); + if ($subType === 'application') { + $this->foundServiceApplicationIds->push($subId); + $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus); + } elseif ($subType === 'database') { + $this->foundServiceDatabaseIds->push($subId); + $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus); + } + } else { $name = data_get($container, 'name'); $uuid = $labels->get('com.docker.compose.service'); $type = $labels->get('coolify.type'); if ($name === 'coolify-proxy') { - $foundProxy = true; - Log::info("Proxy: $uuid, $containerStatus"); + $this->foundProxy = true; } elseif ($type === 'service') { - Log::info("Service: $uuid, $containerStatus"); + logger("Service: $uuid, $containerStatus"); } else { - Log::info("Database: $uuid, $containerStatus"); + if ($this->allDatabaseUuids->contains($uuid)) { + $this->foundDatabaseUuids->push($uuid); + if ($this->allTcpProxyUuids->contains($uuid)) { + $this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: true); + } else { + $this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: false); + } + } } } } } + $this->updateProxyStatus(); + + $this->updateNotFoundApplicationStatus(); + $this->updateNotFoundApplicationPreviewStatus(); + $this->updateNotFoundDatabaseStatus(); + $this->updateNotFoundServiceStatus(); + + $this->updateAdditionalServersStatus(); + } + + private function updateApplicationStatus(string $applicationId, string $containerStatus) + { + $application = $this->server->applications()->where('id', $applicationId)->first(); + if (! $application) { + return; + } + $application->status = $containerStatus; + $application->save(); + logger('Application updated', ['application_id' => $applicationId, 'status' => $containerStatus]); + } + + private function updateApplicationPreviewStatus(string $applicationId, string $containerStatus) + { + $application = $this->server->previews()->where('id', $applicationId)->first(); + if (! $application) { + return; + } + $application->status = $containerStatus; + $application->save(); + logger('Application preview updated', ['application_id' => $applicationId, 'status' => $containerStatus]); + } + + private function updateNotFoundApplicationStatus() + { + $notFoundApplicationIds = $this->allApplicationIds->diff($this->foundApplicationIds); + if ($notFoundApplicationIds->isNotEmpty()) { + logger('Not found application ids', ['application_ids' => $notFoundApplicationIds]); + $notFoundApplicationIds->each(function ($applicationId) { + logger('Updating application status', ['application_id' => $applicationId, 'status' => 'exited']); + $application = Application::find($applicationId); + if ($application) { + $application->status = 'exited'; + $application->save(); + logger('Application status updated', ['application_id' => $applicationId, 'status' => 'exited']); + } + }); + } + } + + private function updateNotFoundApplicationPreviewStatus() + { + $notFoundApplicationPreviewsIds = $this->allApplicationPreviewsIds->diff($this->foundApplicationPreviewsIds); + if ($notFoundApplicationPreviewsIds->isNotEmpty()) { + logger('Not found application previews ids', ['application_previews_ids' => $notFoundApplicationPreviewsIds]); + $notFoundApplicationPreviewsIds->each(function ($applicationPreviewId) { + logger('Updating application preview status', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']); + $applicationPreview = ApplicationPreview::find($applicationPreviewId); + if ($applicationPreview) { + $applicationPreview->status = 'exited'; + $applicationPreview->save(); + logger('Application preview status updated', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']); + } + }); + } + } + + private function updateProxyStatus() + { // If proxy is not found, start it - if (! $foundProxy && $this->server->isProxyShouldRun()) { - Log::info('Proxy not found, starting it'); + if (! $this->foundProxy && $this->server->isProxyShouldRun()) { + logger('Proxy not found, starting it.'); StartProxy::dispatch($this->server); } - // Update not found applications - $allApplicationIds = $this->server->applications()->pluck('id'); - $notFoundApplicationIds = $allApplicationIds->diff($foundApplicationIds); - if ($notFoundApplicationIds->isNotEmpty()) { - Log::info('Not found application ids', ['application_ids' => $notFoundApplicationIds]); - $this->updateNotFoundApplications($notFoundApplicationIds); + } + + private function updateDatabaseStatus(string $databaseUuid, string $containerStatus, bool $tcpProxy = false) + { + $database = $this->server->databases()->where('uuid', $databaseUuid)->first(); + if (! $database) { + return; + } + $database->status = $containerStatus; + $database->save(); + + if (str($containerStatus)->contains('running') && $tcpProxy) { + $tcpProxyContainerFound = $this->containers->filter(function ($value, $key) use ($databaseUuid) { + return data_get($value, 'name') === "$databaseUuid-proxy"; + })->first(); + + if (! $tcpProxyContainerFound) { + logger('Starting TCP proxy for database', ['database_uuid' => $databaseUuid]); + StartDatabaseProxy::dispatch($database); + } else { + logger('TCP proxy for database found in containers', ['database_uuid' => $databaseUuid]); + } } } - private function updateApplicationStatus(string $applicationId, string $pullRequestId, string $containerStatus) + private function updateNotFoundDatabaseStatus() { - if ($pullRequestId === '0') { - $application = Application::find($applicationId); - if (! $application) { - return; - } + $notFoundDatabaseUuids = $this->allDatabaseUuids->diff($this->foundDatabaseUuids); + if ($notFoundDatabaseUuids->isNotEmpty()) { + logger('Not found database uuids', ['database_uuids' => $notFoundDatabaseUuids]); + $notFoundDatabaseUuids->each(function ($databaseUuid) { + logger('Updating database status', ['database_uuid' => $databaseUuid, 'status' => 'exited']); + $database = $this->server->databases()->where('uuid', $databaseUuid)->first(); + if ($database) { + $database->status = 'exited'; + $database->save(); + logger('Database status updated', ['database_uuid' => $databaseUuid, 'status' => 'exited']); + } + }); + } + } + + private function updateServiceSubStatus(string $serviceId, string $subType, string $subId, string $containerStatus) + { + $service = $this->server->services()->where('id', $serviceId)->first(); + if (! $service) { + return; + } + if ($subType === 'application') { + $application = $service->applications()->where('id', $subId)->first(); $application->status = $containerStatus; $application->save(); - Log::info('Application updated', ['application_id' => $applicationId, 'status' => $containerStatus]); + logger('Service application updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); + } elseif ($subType === 'database') { + $database = $service->databases()->where('id', $subId)->first(); + $database->status = $containerStatus; + $database->save(); + logger('Service database updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); } else { - $application = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first(); - if (! $application) { - return; - } - $application->status = $containerStatus; - $application->save(); + logger()->warning('Unknown sub type', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); } } - private function updateNotFoundApplications(Collection $applicationIds) + private function updateNotFoundServiceStatus() { - $applicationIds->each(function ($applicationId) { - Log::info('Updating application status', ['application_id' => $applicationId, 'status' => 'exited']); - $application = Application::find($applicationId); - if ($application) { - $application->status = 'exited'; - $application->save(); - Log::info('Application status updated', ['application_id' => $applicationId, 'status' => 'exited']); - } + $notFoundServiceApplicationIds = $this->allServiceApplicationIds->diff($this->foundServiceApplicationIds); + $notFoundServiceDatabaseIds = $this->allServiceDatabaseIds->diff($this->foundServiceDatabaseIds); + if ($notFoundServiceApplicationIds->isNotEmpty()) { + logger('Not found service application ids', ['service_application_ids' => $notFoundServiceApplicationIds]); + $notFoundServiceApplicationIds->each(function ($serviceApplicationId) { + logger('Updating service application status', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']); + $application = ServiceApplication::find($serviceApplicationId); + if ($application) { + $application->status = 'exited'; + $application->save(); + logger('Service application status updated', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']); + } + }); + } + if ($notFoundServiceDatabaseIds->isNotEmpty()) { + logger('Not found service database ids', ['service_database_ids' => $notFoundServiceDatabaseIds]); + $notFoundServiceDatabaseIds->each(function ($serviceDatabaseId) { + logger('Updating service database status', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']); + $database = ServiceDatabase::find($serviceDatabaseId); + if ($database) { + $database->status = 'exited'; + $database->save(); + logger('Service database status updated', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']); + } + }); + } + } + + private function updateAdditionalServersStatus() + { + $this->allApplicationsWithAdditionalServers->each(function ($application) { + logger('Updating additional servers status for application', ['application_id' => $application->id]); + ComplexStatusCheck::run($application); }); } } From 1f72321681e197603488700b98aff43e830f4792 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 18:04:36 +0200 Subject: [PATCH 034/120] fix: sentinel --- app/Jobs/PushServerUpdateJob.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index a426e8532..3b4bd0598 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -60,6 +60,7 @@ public function __construct(public Server $server, public $data) { // TODO: Handle multiple servers - done - NOT TESTED // TODO: Handle Preview deployments - done - NOT TESTED + // TODO: Emails $this->containers = collect(); $this->foundApplicationIds = collect(); $this->foundDatabaseUuids = collect(); @@ -148,7 +149,10 @@ public function handle() $uuid = $labels->get('com.docker.compose.service'); $type = $labels->get('coolify.type'); if ($name === 'coolify-proxy') { - $this->foundProxy = true; + logger("Proxy: $uuid, $containerStatus"); + if (str($containerStatus)->contains('running')) { + $this->foundProxy = true; + } } elseif ($type === 'service') { logger("Service: $uuid, $containerStatus"); } else { @@ -234,6 +238,7 @@ private function updateNotFoundApplicationPreviewStatus() private function updateProxyStatus() { // If proxy is not found, start it + logger('Proxy not found', ['foundProxy' => $this->foundProxy, 'isProxyShouldRun' => $this->server->isProxyShouldRun()]); if (! $this->foundProxy && $this->server->isProxyShouldRun()) { logger('Proxy not found, starting it.'); StartProxy::dispatch($this->server); @@ -249,12 +254,12 @@ private function updateDatabaseStatus(string $databaseUuid, string $containerSta } $database->status = $containerStatus; $database->save(); - + logger('Database status updated', ['database_uuid' => $databaseUuid, 'status' => $containerStatus]); if (str($containerStatus)->contains('running') && $tcpProxy) { $tcpProxyContainerFound = $this->containers->filter(function ($value, $key) use ($databaseUuid) { - return data_get($value, 'name') === "$databaseUuid-proxy"; + return data_get($value, 'name') === "$databaseUuid-proxy" && data_get($value, 'state') === 'running'; })->first(); - + logger('TCP proxy container found', ['tcpProxyContainerFound' => $tcpProxyContainerFound]); if (! $tcpProxyContainerFound) { logger('Starting TCP proxy for database', ['database_uuid' => $databaseUuid]); StartDatabaseProxy::dispatch($database); From bdd6597451e93a5aface19876e79e3b736045a9e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 19:42:44 +0200 Subject: [PATCH 035/120] chore: Update project resource index page --- app/Livewire/Project/Resource/Index.php | 4 +++- .../views/livewire/project/resource/index.blade.php | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/Livewire/Project/Resource/Index.php b/app/Livewire/Project/Resource/Index.php index 71ce2c356..283496887 100644 --- a/app/Livewire/Project/Resource/Index.php +++ b/app/Livewire/Project/Resource/Index.php @@ -32,8 +32,11 @@ class Index extends Component public $services = []; + public array $parameters; + public function mount() { + $this->parameters = get_route_parameters(); $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); if (! $project) { return redirect()->route('dashboard'); @@ -44,7 +47,6 @@ public function mount() } $this->project = $project; $this->environment = $environment; - $this->applications = $this->environment->applications->load(['tags']); $this->applications = $this->applications->map(function ($application) { if (data_get($application, 'environment.project.uuid')) { diff --git a/resources/views/livewire/project/resource/index.blade.php b/resources/views/livewire/project/resource/index.blade.php index f6502762a..0e16b7266 100644 --- a/resources/views/livewire/project/resource/index.blade.php +++ b/resources/views/livewire/project/resource/index.blade.php @@ -7,15 +7,15 @@

Resources

@if ($environment->isEmpty()) + href="{{ route('project.clone-me', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($parameters, 'environment_name')]) }}"> Clone @else - + New + href="{{ route('project.clone-me', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($parameters, 'environment_name')]) }}"> Clone @endif @@ -25,7 +25,7 @@ class="button">+
  1. + href="{{ route('project.show', ['project_uuid' => data_get($parameters, 'project_uuid')]) }}"> {{ $project->name }}
  2. @@ -44,7 +44,7 @@ class="button">+
@if ($environment->isEmpty()) - + Add New Resource @else
From fdeb9353bea2c751917ddd5357543594fac8a0f6 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 19:45:03 +0200 Subject: [PATCH 036/120] chore: Update project service configuration view --- app/Jobs/PushServerUpdateJob.php | 247 +++++++++--------- .../project/service/configuration.blade.php | 2 +- 2 files changed, 130 insertions(+), 119 deletions(-) diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 3b4bd0598..9bed82015 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -3,6 +3,7 @@ namespace App\Jobs; use App\Actions\Database\StartDatabaseProxy; +use App\Actions\Database\StopDatabaseProxy; use App\Actions\Proxy\StartProxy; use App\Actions\Shared\ComplexStatusCheck; use App\Models\Application; @@ -76,107 +77,109 @@ public function __construct(public Server $server, public $data) public function handle() { - if (! $this->data) { - throw new \Exception('No data provided'); - } - $data = collect($this->data); - $this->containers = collect(data_get($data, 'containers')); - if ($this->containers->isEmpty()) { - return; - } - $this->allApplicationIds = $this->server->applications() - ->filter(function ($application) { - return $application->additional_servers->count() === 0; - }) - ->pluck('id'); - $this->allApplicationsWithAdditionalServers = $this->server->applications() - ->filter(function ($application) { - return $application->additional_servers->count() > 0; + try { + if (! $this->data) { + throw new \Exception('No data provided'); + } + $data = collect($this->data); + $this->containers = collect(data_get($data, 'containers')); + if ($this->containers->isEmpty()) { + return; + } + $this->allApplicationIds = $this->server->applications() + ->filter(function ($application) { + return $application->additional_servers->count() === 0; + }) + ->pluck('id'); + $this->allApplicationsWithAdditionalServers = $this->server->applications() + ->filter(function ($application) { + return $application->additional_servers->count() > 0; + }); + $this->allApplicationPreviewsIds = $this->server->previews()->pluck('id'); + $this->allDatabaseUuids = $this->server->databases()->pluck('uuid'); + $this->allTcpProxyUuids = $this->server->databases()->where('is_public', true)->pluck('uuid'); + $this->server->services()->each(function ($service) { + $service->applications()->pluck('id')->each(function ($applicationId) { + $this->allServiceApplicationIds->push($applicationId); + }); + $service->databases()->pluck('id')->each(function ($databaseId) { + $this->allServiceDatabaseIds->push($databaseId); + }); }); - $this->allApplicationPreviewsIds = $this->server->previews()->pluck('id'); - $this->allDatabaseUuids = $this->server->databases()->pluck('uuid'); - $this->allTcpProxyUuids = $this->server->databases()->where('is_public', true)->pluck('uuid'); - $this->server->services()->each(function ($service) { - $service->applications()->pluck('id')->each(function ($applicationId) { - $this->allServiceApplicationIds->push($applicationId); - }); - $service->databases()->pluck('id')->each(function ($databaseId) { - $this->allServiceDatabaseIds->push($databaseId); - }); - }); - logger('allServiceApplicationIds', ['allServiceApplicationIds' => $this->allServiceApplicationIds]); + ray('allServiceApplicationIds', ['allServiceApplicationIds' => $this->allServiceApplicationIds]); - foreach ($this->containers as $container) { - $containerStatus = data_get($container, 'state', 'exited'); - $containerHealth = data_get($container, 'health_status', 'unhealthy'); - $containerStatus = "$containerStatus ($containerHealth)"; - $labels = collect(data_get($container, 'labels')); - $coolify_managed = $labels->has('coolify.managed'); - if ($coolify_managed) { - if ($labels->has('coolify.applicationId')) { - $applicationId = $labels->get('coolify.applicationId'); - $pullRequestId = data_get($labels, 'coolify.pullRequestId', '0'); - try { - if ($pullRequestId === '0') { - if ($this->allApplicationIds->contains($applicationId)) { - $this->foundApplicationIds->push($applicationId); - } - $this->updateApplicationStatus($applicationId, $containerStatus); - } else { - if ($this->allApplicationPreviewsIds->contains($applicationId)) { - $this->foundApplicationPreviewsIds->push($applicationId); - } - $this->updateApplicationPreviewStatus($applicationId, $containerStatus); - } - } catch (\Exception $e) { - logger()->error($e); - } - } elseif ($labels->has('coolify.serviceId')) { - $serviceId = $labels->get('coolify.serviceId'); - $subType = $labels->get('coolify.service.subType'); - $subId = $labels->get('coolify.service.subId'); - if ($subType === 'application') { - $this->foundServiceApplicationIds->push($subId); - $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus); - } elseif ($subType === 'database') { - $this->foundServiceDatabaseIds->push($subId); - $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus); - } - - } else { - $name = data_get($container, 'name'); - $uuid = $labels->get('com.docker.compose.service'); - $type = $labels->get('coolify.type'); - if ($name === 'coolify-proxy') { - logger("Proxy: $uuid, $containerStatus"); - if (str($containerStatus)->contains('running')) { - $this->foundProxy = true; - } - } elseif ($type === 'service') { - logger("Service: $uuid, $containerStatus"); - } else { - if ($this->allDatabaseUuids->contains($uuid)) { - $this->foundDatabaseUuids->push($uuid); - if ($this->allTcpProxyUuids->contains($uuid)) { - $this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: true); + foreach ($this->containers as $container) { + $containerStatus = data_get($container, 'state', 'exited'); + $containerHealth = data_get($container, 'health_status', 'unhealthy'); + $containerStatus = "$containerStatus ($containerHealth)"; + $labels = collect(data_get($container, 'labels')); + $coolify_managed = $labels->has('coolify.managed'); + if ($coolify_managed) { + if ($labels->has('coolify.applicationId')) { + $applicationId = $labels->get('coolify.applicationId'); + $pullRequestId = data_get($labels, 'coolify.pullRequestId', '0'); + try { + if ($pullRequestId === '0') { + if ($this->allApplicationIds->contains($applicationId) && $this->isRunning($containerStatus)) { + $this->foundApplicationIds->push($applicationId); + } + $this->updateApplicationStatus($applicationId, $containerStatus); } else { - $this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: false); + if ($this->allApplicationPreviewsIds->contains($applicationId) && $this->isRunning($containerStatus)) { + $this->foundApplicationPreviewsIds->push($applicationId); + } + $this->updateApplicationPreviewStatus($applicationId, $containerStatus); + } + } catch (\Exception $e) { + ray()->error($e); + } + } elseif ($labels->has('coolify.serviceId')) { + $serviceId = $labels->get('coolify.serviceId'); + $subType = $labels->get('coolify.service.subType'); + $subId = $labels->get('coolify.service.subId'); + if ($subType === 'application' && $this->isRunning($containerStatus)) { + $this->foundServiceApplicationIds->push($subId); + $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus); + } elseif ($subType === 'database' && $this->isRunning($containerStatus)) { + $this->foundServiceDatabaseIds->push($subId); + $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus); + } + + } else { + $name = data_get($container, 'name'); + $uuid = $labels->get('com.docker.compose.service'); + $type = $labels->get('coolify.type'); + if ($name === 'coolify-proxy' && $this->isRunning($containerStatus)) { + $this->foundProxy = true; + } elseif ($type === 'service' && $this->isRunning($containerStatus)) { + ray("Service: $uuid, $containerStatus"); + } else { + if ($this->allDatabaseUuids->contains($uuid) && $this->isRunning($containerStatus)) { + $this->foundDatabaseUuids->push($uuid); + if ($this->allTcpProxyUuids->contains($uuid) && $this->isRunning($containerStatus)) { + $this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: true); + } else { + $this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: false); + } } } } } } + + $this->updateProxyStatus(); + + $this->updateNotFoundApplicationStatus(); + $this->updateNotFoundApplicationPreviewStatus(); + $this->updateNotFoundDatabaseStatus(); + $this->updateNotFoundServiceStatus(); + + $this->updateAdditionalServersStatus(); + } catch (\Exception $e) { + throw $e; } - $this->updateProxyStatus(); - - $this->updateNotFoundApplicationStatus(); - $this->updateNotFoundApplicationPreviewStatus(); - $this->updateNotFoundDatabaseStatus(); - $this->updateNotFoundServiceStatus(); - - $this->updateAdditionalServersStatus(); } private function updateApplicationStatus(string $applicationId, string $containerStatus) @@ -187,7 +190,7 @@ private function updateApplicationStatus(string $applicationId, string $containe } $application->status = $containerStatus; $application->save(); - logger('Application updated', ['application_id' => $applicationId, 'status' => $containerStatus]); + ray('Application updated', ['application_id' => $applicationId, 'status' => $containerStatus]); } private function updateApplicationPreviewStatus(string $applicationId, string $containerStatus) @@ -198,21 +201,21 @@ private function updateApplicationPreviewStatus(string $applicationId, string $c } $application->status = $containerStatus; $application->save(); - logger('Application preview updated', ['application_id' => $applicationId, 'status' => $containerStatus]); + ray('Application preview updated', ['application_id' => $applicationId, 'status' => $containerStatus]); } private function updateNotFoundApplicationStatus() { $notFoundApplicationIds = $this->allApplicationIds->diff($this->foundApplicationIds); if ($notFoundApplicationIds->isNotEmpty()) { - logger('Not found application ids', ['application_ids' => $notFoundApplicationIds]); + ray('Not found application ids', ['application_ids' => $notFoundApplicationIds]); $notFoundApplicationIds->each(function ($applicationId) { - logger('Updating application status', ['application_id' => $applicationId, 'status' => 'exited']); + ray('Updating application status', ['application_id' => $applicationId, 'status' => 'exited']); $application = Application::find($applicationId); if ($application) { $application->status = 'exited'; $application->save(); - logger('Application status updated', ['application_id' => $applicationId, 'status' => 'exited']); + ray('Application status updated', ['application_id' => $applicationId, 'status' => 'exited']); } }); } @@ -222,14 +225,14 @@ private function updateNotFoundApplicationPreviewStatus() { $notFoundApplicationPreviewsIds = $this->allApplicationPreviewsIds->diff($this->foundApplicationPreviewsIds); if ($notFoundApplicationPreviewsIds->isNotEmpty()) { - logger('Not found application previews ids', ['application_previews_ids' => $notFoundApplicationPreviewsIds]); + ray('Not found application previews ids', ['application_previews_ids' => $notFoundApplicationPreviewsIds]); $notFoundApplicationPreviewsIds->each(function ($applicationPreviewId) { - logger('Updating application preview status', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']); + ray('Updating application preview status', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']); $applicationPreview = ApplicationPreview::find($applicationPreviewId); if ($applicationPreview) { $applicationPreview->status = 'exited'; $applicationPreview->save(); - logger('Application preview status updated', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']); + ray('Application preview status updated', ['application_preview_id' => $applicationPreviewId, 'status' => 'exited']); } }); } @@ -238,9 +241,8 @@ private function updateNotFoundApplicationPreviewStatus() private function updateProxyStatus() { // If proxy is not found, start it - logger('Proxy not found', ['foundProxy' => $this->foundProxy, 'isProxyShouldRun' => $this->server->isProxyShouldRun()]); if (! $this->foundProxy && $this->server->isProxyShouldRun()) { - logger('Proxy not found, starting it.'); + ray('Proxy not found, starting it.'); StartProxy::dispatch($this->server); } @@ -254,17 +256,16 @@ private function updateDatabaseStatus(string $databaseUuid, string $containerSta } $database->status = $containerStatus; $database->save(); - logger('Database status updated', ['database_uuid' => $databaseUuid, 'status' => $containerStatus]); - if (str($containerStatus)->contains('running') && $tcpProxy) { + ray('Database status updated', ['database_uuid' => $databaseUuid, 'status' => $containerStatus]); + if ($this->isRunning($containerStatus) && $tcpProxy) { $tcpProxyContainerFound = $this->containers->filter(function ($value, $key) use ($databaseUuid) { return data_get($value, 'name') === "$databaseUuid-proxy" && data_get($value, 'state') === 'running'; })->first(); - logger('TCP proxy container found', ['tcpProxyContainerFound' => $tcpProxyContainerFound]); if (! $tcpProxyContainerFound) { - logger('Starting TCP proxy for database', ['database_uuid' => $databaseUuid]); + ray('Starting TCP proxy for database', ['database_uuid' => $databaseUuid]); StartDatabaseProxy::dispatch($database); } else { - logger('TCP proxy for database found in containers', ['database_uuid' => $databaseUuid]); + ray('TCP proxy for database found in containers', ['database_uuid' => $databaseUuid]); } } } @@ -273,14 +274,19 @@ private function updateNotFoundDatabaseStatus() { $notFoundDatabaseUuids = $this->allDatabaseUuids->diff($this->foundDatabaseUuids); if ($notFoundDatabaseUuids->isNotEmpty()) { - logger('Not found database uuids', ['database_uuids' => $notFoundDatabaseUuids]); + ray('Not found database uuids', ['database_uuids' => $notFoundDatabaseUuids]); $notFoundDatabaseUuids->each(function ($databaseUuid) { - logger('Updating database status', ['database_uuid' => $databaseUuid, 'status' => 'exited']); + ray('Updating database status', ['database_uuid' => $databaseUuid, 'status' => 'exited']); $database = $this->server->databases()->where('uuid', $databaseUuid)->first(); if ($database) { $database->status = 'exited'; $database->save(); - logger('Database status updated', ['database_uuid' => $databaseUuid, 'status' => 'exited']); + ray('Database status updated', ['database_uuid' => $databaseUuid, 'status' => 'exited']); + ray('Database is public', ['database_uuid' => $databaseUuid, 'is_public' => $database->is_public]); + if ($database->is_public) { + ray('Stopping TCP proxy for database', ['database_uuid' => $databaseUuid]); + StopDatabaseProxy::dispatch($database); + } } }); } @@ -296,14 +302,14 @@ private function updateServiceSubStatus(string $serviceId, string $subType, stri $application = $service->applications()->where('id', $subId)->first(); $application->status = $containerStatus; $application->save(); - logger('Service application updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); + ray('Service application updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); } elseif ($subType === 'database') { $database = $service->databases()->where('id', $subId)->first(); $database->status = $containerStatus; $database->save(); - logger('Service database updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); + ray('Service database updated', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); } else { - logger()->warning('Unknown sub type', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); + ray()->warning('Unknown sub type', ['service_id' => $serviceId, 'sub_type' => $subType, 'sub_id' => $subId, 'status' => $containerStatus]); } } @@ -312,26 +318,26 @@ private function updateNotFoundServiceStatus() $notFoundServiceApplicationIds = $this->allServiceApplicationIds->diff($this->foundServiceApplicationIds); $notFoundServiceDatabaseIds = $this->allServiceDatabaseIds->diff($this->foundServiceDatabaseIds); if ($notFoundServiceApplicationIds->isNotEmpty()) { - logger('Not found service application ids', ['service_application_ids' => $notFoundServiceApplicationIds]); + ray('Not found service application ids', ['service_application_ids' => $notFoundServiceApplicationIds]); $notFoundServiceApplicationIds->each(function ($serviceApplicationId) { - logger('Updating service application status', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']); + ray('Updating service application status', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']); $application = ServiceApplication::find($serviceApplicationId); if ($application) { $application->status = 'exited'; $application->save(); - logger('Service application status updated', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']); + ray('Service application status updated', ['service_application_id' => $serviceApplicationId, 'status' => 'exited']); } }); } if ($notFoundServiceDatabaseIds->isNotEmpty()) { - logger('Not found service database ids', ['service_database_ids' => $notFoundServiceDatabaseIds]); + ray('Not found service database ids', ['service_database_ids' => $notFoundServiceDatabaseIds]); $notFoundServiceDatabaseIds->each(function ($serviceDatabaseId) { - logger('Updating service database status', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']); + ray('Updating service database status', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']); $database = ServiceDatabase::find($serviceDatabaseId); if ($database) { $database->status = 'exited'; $database->save(); - logger('Service database status updated', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']); + ray('Service database status updated', ['service_database_id' => $serviceDatabaseId, 'status' => 'exited']); } }); } @@ -340,8 +346,13 @@ private function updateNotFoundServiceStatus() private function updateAdditionalServersStatus() { $this->allApplicationsWithAdditionalServers->each(function ($application) { - logger('Updating additional servers status for application', ['application_id' => $application->id]); + ray('Updating additional servers status for application', ['application_id' => $application->id]); ComplexStatusCheck::run($application); }); } + + private function isRunning(string $containerStatus) + { + return str($containerStatus)->contains('running'); + } } diff --git a/resources/views/livewire/project/service/configuration.blade.php b/resources/views/livewire/project/service/configuration.blade.php index d7d9d21d3..ed2a6dec9 100644 --- a/resources/views/livewire/project/service/configuration.blade.php +++ b/resources/views/livewire/project/service/configuration.blade.php @@ -1,4 +1,4 @@ -
+
{{ data_get_str($service, 'name')->limit(10) }} > Configuration | Coolify From bea492165f184486c338db63918bd195ca0d1723 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 21:05:33 +0200 Subject: [PATCH 037/120] sentinel updates --- app/Actions/Server/StartSentinel.php | 48 ++++++++++++------- app/Livewire/Server/Form.php | 21 ++++++-- .../views/livewire/server/form.blade.php | 7 ++- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php index 4b45d0738..a52fb4125 100644 --- a/app/Actions/Server/StartSentinel.php +++ b/app/Actions/Server/StartSentinel.php @@ -10,32 +10,48 @@ class StartSentinel { use AsAction; - public function handle(Server $server, $version = 'latest', bool $restart = false) + public function handle(Server $server, $version = 'next', bool $restart = false) { if ($restart) { StopSentinel::run($server); } - $metrics_history = $server->settings->metrics_history_days; - $refresh_rate = $server->settings->metrics_refresh_rate_seconds; + $metrics_history = $server->settings->sentinel_metrics_history_days; + $refresh_rate = $server->settings->sentinel_metrics_refresh_rate_seconds; $token = $server->settings->sentinel_token; - $fqdn = InstanceSettings::get()->fqdn; - if (str($fqdn)->startsWith('http')) { - throw new \Exception('You should use https to run Sentinel.'); + $endpoint = InstanceSettings::get()->fqdn; + if (isDev()) { + $endpoint = 'http://host.docker.internal:8000'; + } else { + if (str($endpoint)->startsWith('http')) { + throw new \Exception('You should use https to run Sentinel.'); + } + } + if (! $endpoint) { + throw new \Exception('You should set FQDN in Instance Settings.'); } $environments = [ 'TOKEN' => $token, - 'ENDPOINT' => InstanceSettings::get()->fqdn, + 'ENDPOINT' => $endpoint, 'COLLECTOR_ENABLED' => 'true', 'COLLECTOR_REFRESH_RATE_SECONDS' => $refresh_rate, - 'COLLECTOR_RETENTION_PERIOD_DAYS' => $metrics_history + 'COLLECTOR_RETENTION_PERIOD_DAYS' => $metrics_history, ]; - $docker_environments = "-e \"" . implode("\" -e \"", array_map(fn($key, $value) => "$key=$value", array_keys($environments), $environments)) . "\""; - ray($docker_environments); - return true; - // instant_remote_process([ - // "docker run --rm --pull always -d $docker_environments --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify/sentinel:/app/sentinel --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 ghcr.io/coollabsio/sentinel:$version", - // 'chown -R 9999:root /data/coolify/sentinel', - // 'chmod -R 700 /data/coolify/sentinel', - // ], $server, true); + if (isDev()) { + data_set($environments, 'GIN_MODE', 'debug'); + } + $mount_dir = '/data/coolify/sentinel'; + if (isDev()) { + $mount_dir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/sentinel'; + } + $docker_environments = '-e "'.implode('" -e "', array_map(fn ($key, $value) => "$key=$value", array_keys($environments), $environments)).'"'; + $docker_command = "docker run --pull always --rm -d $docker_environments --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v $mount_dir:/app/db --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 --add-host=host.docker.internal:host-gateway ghcr.io/coollabsio/sentinel:$version"; + + return instant_remote_process([ + 'docker rm -f coolify-sentinel || true', + "mkdir -p $mount_dir", + $docker_command, + "chown -R 9999:root $mount_dir", + "chmod -R 700 $mount_dir", + ], $server, true); } } diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 6efff504b..0bb7e4742 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -101,7 +101,9 @@ public function mount(Server $server) $this->server->settings->delete_unused_volumes = $server->settings->delete_unused_volumes; $this->server->settings->delete_unused_networks = $server->settings->delete_unused_networks; } - public function regenerateSentinelToken() { + + public function regenerateSentinelToken() + { try { $this->server->generateSentinelToken(); $this->server->settings->refresh(); @@ -110,6 +112,7 @@ public function regenerateSentinelToken() { return handleError($e, $this); } } + public function updated($field) { if ($field === 'server.settings.docker_cleanup_frequency') { @@ -186,25 +189,26 @@ public function instantSave() public function getPushData() { try { - if (!isDev()) { + if (! isDev()) { throw new \Exception('This feature is only available in dev mode.'); } $response = Http::withHeaders([ - 'Authorization' => 'Bearer ' . $this->server->settings->sentinel_token, + 'Authorization' => 'Bearer '.$this->server->settings->sentinel_token, ])->post('http://host.docker.internal:8888/api/push', [ 'data' => 'test', ]); if ($response->successful()) { $this->dispatch('success', 'Push data sent.'); + return; } $error = data_get($response->json(), 'error'); throw new \Exception($error); - - } catch(\Throwable $e) { + } catch (\Throwable $e) { return handleError($e, $this); } } + public function restartSentinel() { try { @@ -285,6 +289,7 @@ public function submit() return handleError($e, $this); } } + public function manualCleanup() { try { @@ -302,4 +307,10 @@ public function manualCloudflareConfig() $this->server->refresh(); $this->dispatch('success', 'Cloudflare Tunnels enabled.'); } + + public function startSentinel() + { + StartSentinel::run($this->server); + $this->dispatch('success', 'Sentinel started.'); + } } diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index ace297712..47b686c1e 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -282,11 +282,10 @@ functional issues.

{{-- @endif --}}
@if (isDev()) - Push Test - {{--
+
- Start Sentinel -
--}} + Start Sentinel +
Date: Mon, 14 Oct 2024 21:35:20 +0200 Subject: [PATCH 038/120] fix: make sure caddy is not removed by cleanup --- bootstrap/helpers/proxy.php | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 309ccee4a..33d19d9cc 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -244,6 +244,7 @@ function generate_default_proxy_configuration(Server $server) ], 'labels' => [ 'coolify.managed=true', + 'coolify.proxy=true', ], 'volumes' => [ '/var/run/docker.sock:/var/run/docker.sock:ro', From 8635f92ed48652feb6ee539121ac09614b6be5ba Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:35:38 +0200 Subject: [PATCH 039/120] Remove duplicated proxy check --- app/Actions/Docker/GetContainersStatus.php | 26 ----------- app/Jobs/ServerCheckJob.php | 52 +++++++++++----------- 2 files changed, 26 insertions(+), 52 deletions(-) diff --git a/app/Actions/Docker/GetContainersStatus.php b/app/Actions/Docker/GetContainersStatus.php index ed563eaae..d1603d7b4 100644 --- a/app/Actions/Docker/GetContainersStatus.php +++ b/app/Actions/Docker/GetContainersStatus.php @@ -651,31 +651,5 @@ private function old_way() // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url)); } - if (! $this->server->proxySet() || $this->server->proxy->force_stop) { - return; - } - $foundProxyContainer = $this->containers->filter(function ($value, $key) { - if ($this->server->isSwarm()) { - return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik'; - } else { - return data_get($value, 'Name') === '/coolify-proxy'; - } - })->first(); - if (! $foundProxyContainer) { - try { - $shouldStart = CheckProxy::run($this->server); - if ($shouldStart) { - StartProxy::run($this->server, false); - $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server)); - } - } catch (\Throwable $e) { - ray($e); - } - } else { - $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); - $this->server->save(); - $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); - instant_remote_process($connectProxyToDockerNetworks, $this->server, false); - } } } diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php index 39d4aa0c0..3ff695cc1 100644 --- a/app/Jobs/ServerCheckJob.php +++ b/app/Jobs/ServerCheckJob.php @@ -72,6 +72,32 @@ public function handle() if ($this->server->isLogDrainEnabled()) { $this->checkLogDrainContainer(); } + if ($this->server->proxySet() && ! $this->server->proxy->force_stop) { + $this->server->proxyType(); + $foundProxyContainer = $this->containers->filter(function ($value, $key) { + if ($this->server->isSwarm()) { + return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik'; + } else { + return data_get($value, 'Name') === '/coolify-proxy'; + } + })->first(); + if (! $foundProxyContainer) { + try { + $shouldStart = CheckProxy::run($this->server); + if ($shouldStart) { + StartProxy::run($this->server, false); + $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server)); + } + } catch (\Throwable $e) { + ray($e); + } + } else { + $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); + $this->server->save(); + $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); + instant_remote_process($connectProxyToDockerNetworks, $this->server, false); + } + } } } catch (\Throwable $e) { @@ -387,31 +413,5 @@ private function containerStatus() } // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url)); } - - // Check if proxy is running - $this->server->proxyType(); - $foundProxyContainer = $this->containers->filter(function ($value, $key) { - if ($this->server->isSwarm()) { - return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik'; - } else { - return data_get($value, 'Name') === '/coolify-proxy'; - } - })->first(); - if (! $foundProxyContainer) { - try { - $shouldStart = CheckProxy::run($this->server); - if ($shouldStart) { - StartProxy::run($this->server, false); - $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server)); - } - } catch (\Throwable $e) { - ray($e); - } - } else { - $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); - $this->server->save(); - $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); - instant_remote_process($connectProxyToDockerNetworks, $this->server, false); - } } } From 740419806eb44bd3c92d688fe7088e8350797544 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 22:35:18 +0200 Subject: [PATCH 040/120] Refactor StartSentinel to ensure endpoint uses HTTPS --- app/Actions/Server/StartSentinel.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php index a52fb4125..e7c613eb0 100644 --- a/app/Actions/Server/StartSentinel.php +++ b/app/Actions/Server/StartSentinel.php @@ -21,14 +21,12 @@ public function handle(Server $server, $version = 'next', bool $restart = false) $endpoint = InstanceSettings::get()->fqdn; if (isDev()) { $endpoint = 'http://host.docker.internal:8000'; - } else { - if (str($endpoint)->startsWith('http')) { - throw new \Exception('You should use https to run Sentinel.'); - } } if (! $endpoint) { throw new \Exception('You should set FQDN in Instance Settings.'); } + // Ensure the endpoint is using HTTPS + $endpoint = str($endpoint)->replace('http://', 'https://')->value(); $environments = [ 'TOKEN' => $token, 'ENDPOINT' => $endpoint, From 81db57002b3dbe695aed2320478c13a76102874e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 22:53:16 +0200 Subject: [PATCH 041/120] Refactor PushServerUpdateJob to handle multiple servers, previews, and emails --- app/Jobs/PushServerUpdateJob.php | 48 ++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 9bed82015..e029a3bf5 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -28,6 +28,14 @@ class PushServerUpdateJob implements ShouldQueue public Collection $containers; + public Collection $applications; + + public Collection $previews; + + public Collection $databases; + + public Collection $services; + public Collection $allApplicationIds; public Collection $allDatabaseUuids; @@ -59,9 +67,6 @@ public function backoff(): int public function __construct(public Server $server, public $data) { - // TODO: Handle multiple servers - done - NOT TESTED - // TODO: Handle Preview deployments - done - NOT TESTED - // TODO: Emails $this->containers = collect(); $this->foundApplicationIds = collect(); $this->foundDatabaseUuids = collect(); @@ -86,19 +91,20 @@ public function handle() if ($this->containers->isEmpty()) { return; } - $this->allApplicationIds = $this->server->applications() - ->filter(function ($application) { - return $application->additional_servers->count() === 0; - }) - ->pluck('id'); - $this->allApplicationsWithAdditionalServers = $this->server->applications() - ->filter(function ($application) { - return $application->additional_servers->count() > 0; - }); - $this->allApplicationPreviewsIds = $this->server->previews()->pluck('id'); - $this->allDatabaseUuids = $this->server->databases()->pluck('uuid'); - $this->allTcpProxyUuids = $this->server->databases()->where('is_public', true)->pluck('uuid'); - $this->server->services()->each(function ($service) { + $this->applications = $this->server->applications(); + $this->databases = $this->server->databases(); + $this->previews = $this->server->previews(); + $this->services = $this->server->services()->get(); + $this->allApplicationIds = $this->applications->filter(function ($application) { + return $application->additional_servers->count() === 0; + })->pluck('id'); + $this->allApplicationsWithAdditionalServers = $this->applications->filter(function ($application) { + return $application->additional_servers->count() > 0; + }); + $this->allApplicationPreviewsIds = $this->previews->pluck('id'); + $this->allDatabaseUuids = $this->databases->pluck('uuid'); + $this->allTcpProxyUuids = $this->databases->where('is_public', true)->pluck('uuid'); + $this->services->each(function ($service) { $service->applications()->pluck('id')->each(function ($applicationId) { $this->allServiceApplicationIds->push($applicationId); }); @@ -184,7 +190,7 @@ public function handle() private function updateApplicationStatus(string $applicationId, string $containerStatus) { - $application = $this->server->applications()->where('id', $applicationId)->first(); + $application = $this->applications->where('id', $applicationId)->first(); if (! $application) { return; } @@ -195,7 +201,7 @@ private function updateApplicationStatus(string $applicationId, string $containe private function updateApplicationPreviewStatus(string $applicationId, string $containerStatus) { - $application = $this->server->previews()->where('id', $applicationId)->first(); + $application = $this->previews->where('id', $applicationId)->first(); if (! $application) { return; } @@ -250,7 +256,7 @@ private function updateProxyStatus() private function updateDatabaseStatus(string $databaseUuid, string $containerStatus, bool $tcpProxy = false) { - $database = $this->server->databases()->where('uuid', $databaseUuid)->first(); + $database = $this->databases->where('uuid', $databaseUuid)->first(); if (! $database) { return; } @@ -277,7 +283,7 @@ private function updateNotFoundDatabaseStatus() ray('Not found database uuids', ['database_uuids' => $notFoundDatabaseUuids]); $notFoundDatabaseUuids->each(function ($databaseUuid) { ray('Updating database status', ['database_uuid' => $databaseUuid, 'status' => 'exited']); - $database = $this->server->databases()->where('uuid', $databaseUuid)->first(); + $database = $this->databases->where('uuid', $databaseUuid)->first(); if ($database) { $database->status = 'exited'; $database->save(); @@ -294,7 +300,7 @@ private function updateNotFoundDatabaseStatus() private function updateServiceSubStatus(string $serviceId, string $subType, string $subId, string $containerStatus) { - $service = $this->server->services()->where('id', $serviceId)->first(); + $service = $this->services->where('id', $serviceId)->first(); if (! $service) { return; } From 268c7b46631c4a6e078253113856ed2023242527 Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Mon, 14 Oct 2024 22:30:37 +0100 Subject: [PATCH 042/120] Fix entrypoint script and removed unused port. --- templates/compose/mosquitto.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index be9e505d9..5789bd607 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -1,6 +1,6 @@ # Documentation: https://mosquitto.org/documentation/ # Slogan: Mosquitto is lightweight and suitable for use on all devices, from low-power single-board computers to full servers. -# Tags: mosquitto, mqtt, ws, open-source +# Tags: mosquitto, mqtt, open-source # Logo: svgs/mosquitto.png # Port: 1883 @@ -11,7 +11,6 @@ services: ports: - "1883:1883" - "8883:8883" - - "9001:9001" environment: - SERVICE_FQDN_MOSQUITTO - MQTT_USERNAME=${MQTT_USERNAME:-mosquitto} @@ -22,13 +21,13 @@ services: - "./mosquitto/config:/mosquitto/config" - "./certs:/certs" entrypoint: 'sh -c " - echo ''listener 1883'' > /mosquitto/config/mosquitto.conf && - echo ''listener 8883'' >> /mosquitto/config/mosquitto.conf && - echo ''listener 9001'' >> /mosquitto/config/mosquitto.conf && if [ ''$REQUIRE_CERTIFICATE'' = ''true'' ]; then + echo ''listener 8883'' > /mosquitto/config/mosquitto.conf && echo ''cafile /certs/ca.crt'' >> /mosquitto/config/mosquitto.conf && echo ''certfile /certs/server.crt'' >> /mosquitto/config/mosquitto.conf && echo ''keyfile /certs/server.key'' >> /mosquitto/config/mosquitto.conf; + else + echo ''listener 1883'' > /mosquitto/config/mosquitto.conf; fi && echo ''require_certificate ''$REQUIRE_CERTIFICATE >> /mosquitto/config/mosquitto.conf && echo ''allow_anonymous ''$ALLOW_ANONYMOUS >> /mosquitto/config/mosquitto.conf && From d446cd4f31ce8f808b1f9ba6814c73b02c7b966d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 13:39:19 +0200 Subject: [PATCH 043/120] sentinel updates --- app/Actions/Server/StartSentinel.php | 39 +++--- app/Actions/Server/StopSentinel.php | 2 + app/Console/Kernel.php | 9 +- app/Jobs/PushServerUpdateJob.php | 48 +++++++- app/Livewire/Server/Charts.php | 12 +- app/Livewire/Server/Form.php | 93 ++++++-------- app/Models/Server.php | 113 +++++++++++++----- app/Models/ServerSetting.php | 3 +- bootstrap/helpers/shared.php | 2 +- ..._07_18_123458_add_force_cleanup_server.php | 2 +- ...pdate_metrics_token_in_server_settings.php | 16 ++- database/seeders/DatabaseSeeder.php | 1 + .../seeders/GenerateSentinelTokenSeeder.php | 25 ++++ database/seeders/ProductionSeeder.php | 1 + openapi.yaml | 2 +- .../views/components/forms/checkbox.blade.php | 5 +- .../views/livewire/server/form.blade.php | 52 +++++--- routes/api.php | 8 +- versions.json | 5 +- 19 files changed, 293 insertions(+), 145 deletions(-) create mode 100644 database/seeders/GenerateSentinelTokenSeeder.php diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php index e7c613eb0..cfea6afd8 100644 --- a/app/Actions/Server/StartSentinel.php +++ b/app/Actions/Server/StartSentinel.php @@ -17,39 +17,46 @@ public function handle(Server $server, $version = 'next', bool $restart = false) } $metrics_history = $server->settings->sentinel_metrics_history_days; $refresh_rate = $server->settings->sentinel_metrics_refresh_rate_seconds; + $push_interval = $server->settings->sentinel_push_interval_seconds; $token = $server->settings->sentinel_token; $endpoint = InstanceSettings::get()->fqdn; - if (isDev()) { + $mount_dir = '/data/coolify/sentinel'; + $image = "ghcr.io/coollabsio/sentinel:$version"; + + if ($server->isLocalhost()) { $endpoint = 'http://host.docker.internal:8000'; + } else { + if (! $endpoint) { + throw new \Exception('You should set FQDN in Instance Settings.'); + } } - if (! $endpoint) { - throw new \Exception('You should set FQDN in Instance Settings.'); - } - // Ensure the endpoint is using HTTPS - $endpoint = str($endpoint)->replace('http://', 'https://')->value(); $environments = [ 'TOKEN' => $token, - 'ENDPOINT' => $endpoint, - 'COLLECTOR_ENABLED' => 'true', + 'PUSH_ENDPOINT' => $endpoint, + 'PUSH_INTERVAL_SECONDS' => $push_interval, + 'COLLECTOR_ENABLED' => $server->isMetricsEnabled() ? 'true' : 'false', 'COLLECTOR_REFRESH_RATE_SECONDS' => $refresh_rate, 'COLLECTOR_RETENTION_PERIOD_DAYS' => $metrics_history, ]; if (isDev()) { - data_set($environments, 'GIN_MODE', 'debug'); - } - $mount_dir = '/data/coolify/sentinel'; - if (isDev()) { + data_set($environments, 'DEBUG', 'true'); $mount_dir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/sentinel'; + $image = 'sentinel'; } - $docker_environments = '-e "'.implode('" -e "', array_map(fn ($key, $value) => "$key=$value", array_keys($environments), $environments)).'"'; - $docker_command = "docker run --pull always --rm -d $docker_environments --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v $mount_dir:/app/db --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 --add-host=host.docker.internal:host-gateway ghcr.io/coollabsio/sentinel:$version"; + $docker_environments = '-e "' . implode('" -e "', array_map(fn($key, $value) => "$key=$value", array_keys($environments), $environments)) . '"'; - return instant_remote_process([ + $docker_command = "docker run -d $docker_environments --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v $mount_dir:/app/db --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 --add-host=host.docker.internal:host-gateway $image"; + + instant_remote_process([ 'docker rm -f coolify-sentinel || true', "mkdir -p $mount_dir", $docker_command, "chown -R 9999:root $mount_dir", "chmod -R 700 $mount_dir", - ], $server, true); + ], $server); + + $server->settings->is_sentinel_enabled = true; + $server->settings->save(); + $server->sentinelUpdateAt(); } } diff --git a/app/Actions/Server/StopSentinel.php b/app/Actions/Server/StopSentinel.php index 21ffca3bd..68972f0f2 100644 --- a/app/Actions/Server/StopSentinel.php +++ b/app/Actions/Server/StopSentinel.php @@ -3,6 +3,7 @@ namespace App\Actions\Server; use App\Models\Server; +use Carbon\Carbon; use Lorisleiva\Actions\Concerns\AsAction; class StopSentinel @@ -12,5 +13,6 @@ class StopSentinel public function handle(Server $server) { instant_remote_process(['docker rm -f coolify-sentinel'], $server, false); + $server->sentinelUpdateAt(isReset: true); } } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 6da32b461..a689b35b8 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -12,7 +12,6 @@ use App\Jobs\PullTemplatesFromCDN; use App\Jobs\ScheduledTaskJob; use App\Jobs\ServerCheckJob; -use App\Jobs\ServerStorageCheckJob; use App\Jobs\UpdateCoolifyJob; use App\Models\ScheduledDatabaseBackup; use App\Models\ScheduledTask; @@ -20,6 +19,7 @@ use App\Models\Team; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; +use Illuminate\Support\Carbon; class Kernel extends ConsoleKernel { @@ -38,7 +38,7 @@ protected function schedule(Schedule $schedule): void $schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer(); // Server Jobs $this->check_scheduled_backups($schedule); - // $this->check_resources($schedule); + $this->check_resources($schedule); $this->check_scheduled_tasks($schedule); $schedule->command('uploads:clear')->everyTwoMinutes(); @@ -115,7 +115,10 @@ private function check_resources($schedule) $servers = $this->all_servers->where('ip', '!=', '1.2.3.4'); } foreach ($servers as $server) { - $schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer(); + $last_sentinel_update = $server->sentinel_updated_at; + if (Carbon::parse($last_sentinel_update)->isBefore(now()->subMinutes(4))) { + $schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer(); + } // $schedule->job(new ServerStorageCheckJob($server))->everyMinute()->onOneServer(); $serverTimezone = $server->settings->server_timezone; if ($server->settings->force_docker_cleanup) { diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index e029a3bf5..82e311d47 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -4,7 +4,9 @@ use App\Actions\Database\StartDatabaseProxy; use App\Actions\Database\StopDatabaseProxy; +use App\Actions\Proxy\CheckProxy; use App\Actions\Proxy\StartProxy; +use App\Actions\Server\InstallLogDrain; use App\Actions\Shared\ComplexStatusCheck; use App\Models\Application; use App\Models\ApplicationPreview; @@ -40,6 +42,8 @@ class PushServerUpdateJob implements ShouldQueue public Collection $allDatabaseUuids; + public Collection $allTcpProxyUuids; + public Collection $allServiceApplicationIds; public Collection $allApplicationPreviewsIds; @@ -59,6 +63,7 @@ class PushServerUpdateJob implements ShouldQueue public Collection $foundApplicationPreviewsIds; public bool $foundProxy = false; + public bool $foundLogDrainContainer = false; public function backoff(): int { @@ -87,6 +92,11 @@ public function handle() throw new \Exception('No data provided'); } $data = collect($this->data); + + $this->serverStatus(); + + $this->server->sentinelUpdateAt(); + $this->containers = collect(data_get($data, 'containers')); if ($this->containers->isEmpty()) { return; @@ -122,6 +132,10 @@ public function handle() $labels = collect(data_get($container, 'labels')); $coolify_managed = $labels->has('coolify.managed'); if ($coolify_managed) { + $name = data_get($container, 'name'); + if ($name === 'coolify-log-drain' && $this->isRunning($containerStatus)) { + $this->foundLogDrainContainer = true; + } if ($labels->has('coolify.applicationId')) { $applicationId = $labels->get('coolify.applicationId'); $pullRequestId = data_get($labels, 'coolify.pullRequestId', '0'); @@ -153,7 +167,6 @@ public function handle() } } else { - $name = data_get($container, 'name'); $uuid = $labels->get('com.docker.compose.service'); $type = $labels->get('coolify.type'); if ($name === 'coolify-proxy' && $this->isRunning($containerStatus)) { @@ -182,12 +195,23 @@ public function handle() $this->updateNotFoundServiceStatus(); $this->updateAdditionalServersStatus(); + + $this->checkLogDrainContainer(); + } catch (\Exception $e) { throw $e; } } + private function serverStatus(){ + if ($this->server->isFunctional() === false) { + throw new \Exception('Server is not ready.'); + } + if ($this->server->status() === false) { + throw new \Exception('Server is not reachable.'); + } + } private function updateApplicationStatus(string $applicationId, string $containerStatus) { $application = $this->applications->where('id', $applicationId)->first(); @@ -247,9 +271,19 @@ private function updateNotFoundApplicationPreviewStatus() private function updateProxyStatus() { // If proxy is not found, start it - if (! $this->foundProxy && $this->server->isProxyShouldRun()) { - ray('Proxy not found, starting it.'); - StartProxy::dispatch($this->server); + if ($this->server->isProxyShouldRun()) { + if ($this->foundProxy === false) { + try { + if (CheckProxy::run($this->server)) { + StartProxy::run($this->server, false); + } + } catch (\Throwable $e) { + logger()->error($e); + } + } else { + $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); + instant_remote_process($connectProxyToDockerNetworks, $this->server, false); + } } } @@ -361,4 +395,10 @@ private function isRunning(string $containerStatus) { return str($containerStatus)->contains('running'); } + + private function checkLogDrainContainer(){ + if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) { + InstallLogDrain::dispatch($this->server); + } + } } diff --git a/app/Livewire/Server/Charts.php b/app/Livewire/Server/Charts.php index 0921c7fa4..09b31c0b0 100644 --- a/app/Livewire/Server/Charts.php +++ b/app/Livewire/Server/Charts.php @@ -34,12 +34,12 @@ public function loadData() try { $cpuMetrics = $this->server->getCpuMetrics($this->interval); $memoryMetrics = $this->server->getMemoryMetrics($this->interval); - $cpuMetrics = collect($cpuMetrics)->map(function ($metric) { - return [$metric[0], $metric[1]]; - }); - $memoryMetrics = collect($memoryMetrics)->map(function ($metric) { - return [$metric[0], $metric[1]]; - }); + // $cpuMetrics = collect($cpuMetrics)->map(function ($metric) { + // return [$metric[0], $metric[1]]; + // }); + // $memoryMetrics = collect($memoryMetrics)->map(function ($metric) { + // return [$metric[0], $metric[1]]; + // }); $this->dispatch("refreshChartData-{$this->chartId}-cpu", [ 'seriesData' => $cpuMetrics, ]); diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 0bb7e4742..48c7c0ae7 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -58,8 +58,9 @@ public function getListeners() 'server.settings.sentinel_token' => 'required', 'server.settings.sentinel_metrics_refresh_rate_seconds' => 'required|integer|min:1', 'server.settings.sentinel_metrics_history_days' => 'required|integer|min:1', + 'server.settings.sentinel_push_interval_seconds' => 'required|integer|min:10', 'wildcard_domain' => 'nullable|url', - 'server.settings.is_server_api_enabled' => 'required|boolean', + 'server.settings.is_sentinel_enabled' => 'required|boolean', 'server.settings.server_timezone' => 'required|string|timezone', 'server.settings.force_docker_cleanup' => 'required|boolean', 'server.settings.docker_cleanup_frequency' => 'required_if:server.settings.force_docker_cleanup,true|string', @@ -85,7 +86,8 @@ public function getListeners() 'server.settings.sentinel_token' => 'Metrics Token', 'server.settings.sentinel_metrics_refresh_rate_seconds' => 'Metrics Interval', 'server.settings.sentinel_metrics_history_days' => 'Metrics History', - 'server.settings.is_server_api_enabled' => 'Server API', + 'server.settings.sentinel_push_interval_seconds' => 'Push Interval', + 'server.settings.is_sentinel_enabled' => 'Server API', 'server.settings.server_timezone' => 'Server Timezone', 'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', 'server.settings.delete_unused_networks' => 'Delete Unused Networks', @@ -102,12 +104,17 @@ public function mount(Server $server) $this->server->settings->delete_unused_networks = $server->settings->delete_unused_networks; } + public function checkSyncStatus(){ + $this->server->refresh(); + $this->server->settings->refresh(); + } + public function regenerateSentinelToken() { try { $this->server->generateSentinelToken(); $this->server->settings->refresh(); - $this->dispatch('success', 'Metrics token regenerated.'); + $this->dispatch('success', 'Sentinel token regenerated. Please restart your Sentinel.'); } catch (\Throwable $e) { return handleError($e, $this); } @@ -143,18 +150,22 @@ public function updatedServerSettingsIsBuildServer() $this->dispatch('proxyStatusUpdated'); } - public function checkPortForServerApi() - { - try { - if ($this->server->settings->is_server_api_enabled === true) { - $this->server->checkServerApi(); - $this->dispatch('success', 'Server API is reachable.'); - } - } catch (\Throwable $e) { - return handleError($e, $this); + public function updatedServerSettingsIsSentinelEnabled($value){ + if($value === false){ + StopSentinel::dispatch($this->server); + $this->server->settings->is_metrics_enabled = false; + $this->server->settings->save(); + $this->server->sentinelUpdateAt(isReset: true); + } else { + StartSentinel::run($this->server); } } + public function updatedServerSettingsIsMetricsEnabled(){ + $this->restartSentinel(); + } + + public function instantSave() { try { @@ -165,19 +176,20 @@ public function instantSave() $this->server->save(); $this->dispatch('success', 'Server updated.'); $this->dispatch('refreshServerShow'); - if ($this->server->isSentinelEnabled()) { - PullSentinelImageJob::dispatchSync($this->server); - ray('Sentinel is enabled'); - if ($this->server->settings->isDirty('is_metrics_enabled')) { - $this->dispatch('reloadWindow'); - } - if ($this->server->settings->isDirty('is_server_api_enabled') && $this->server->settings->is_server_api_enabled === true) { - ray('Starting sentinel'); - } - } else { - ray('Sentinel is not enabled'); - StopSentinel::dispatch($this->server); - } + + // if ($this->server->isSentinelEnabled()) { + // PullSentinelImageJob::dispatchSync($this->server); + // ray('Sentinel is enabled'); + // if ($this->server->settings->isDirty('is_metrics_enabled')) { + // $this->dispatch('reloadWindow'); + // } + // if ($this->server->settings->isDirty('is_sentinel_enabled') && $this->server->settings->is_sentinel_enabled === true) { + // ray('Starting sentinel'); + // } + // } else { + // ray('Sentinel is not enabled'); + // StopSentinel::dispatch($this->server); + // } $this->server->settings->save(); // $this->checkPortForServerApi(); @@ -186,35 +198,12 @@ public function instantSave() } } - public function getPushData() - { - try { - if (! isDev()) { - throw new \Exception('This feature is only available in dev mode.'); - } - $response = Http::withHeaders([ - 'Authorization' => 'Bearer '.$this->server->settings->sentinel_token, - ])->post('http://host.docker.internal:8888/api/push', [ - 'data' => 'test', - ]); - if ($response->successful()) { - $this->dispatch('success', 'Push data sent.'); - - return; - } - $error = data_get($response->json(), 'error'); - throw new \Exception($error); - } catch (\Throwable $e) { - return handleError($e, $this); - } - } - public function restartSentinel() { try { $version = get_latest_sentinel_version(); StartSentinel::run($this->server, $version, true); - $this->dispatch('success', 'Sentinel restarted.'); + $this->dispatch('success', 'Sentinel started.'); } catch (\Throwable $e) { return handleError($e, $this); } @@ -307,10 +296,4 @@ public function manualCloudflareConfig() $this->server->refresh(); $this->dispatch('success', 'Cloudflare Tunnels enabled.'); } - - public function startSentinel() - { - StartSentinel::run($this->server); - $this->dispatch('success', 'Sentinel started.'); - } } diff --git a/app/Models/Server.php b/app/Models/Server.php index 9e947c20b..aac3ddddf 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -7,6 +7,7 @@ use App\Jobs\PullSentinelImageJob; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; +use Illuminate\Support\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Process; @@ -16,6 +17,7 @@ use Spatie\SchemalessAttributes\Casts\SchemalessAttributes; use Spatie\SchemalessAttributes\SchemalessAttributesTrait; use Spatie\Url\Url; +use Illuminate\Support\Str; use Symfony\Component\Yaml\Yaml; #[OA\Schema( @@ -166,7 +168,7 @@ public function proxySet() public function setupDefault404Redirect() { - $dynamic_conf_path = $this->proxyPath().'/dynamic'; + $dynamic_conf_path = $this->proxyPath() . '/dynamic'; $proxy_type = $this->proxyType(); $redirect_url = $this->proxy->redirect_url; if ($proxy_type === ProxyTypes::TRAEFIK->value) { @@ -180,8 +182,8 @@ public function setupDefault404Redirect() respond 404 }'; $conf = - "# This file is automatically generated by Coolify.\n". - "# Do not edit it manually (only if you know what are you doing).\n\n". + "# This file is automatically generated by Coolify.\n" . + "# Do not edit it manually (only if you know what are you doing).\n\n" . $conf; $base64 = base64_encode($conf); instant_remote_process([ @@ -243,8 +245,8 @@ public function setupDefault404Redirect() ]; $conf = Yaml::dump($dynamic_conf, 12, 2); $conf = - "# This file is automatically generated by Coolify.\n". - "# Do not edit it manually (only if you know what are you doing).\n\n". + "# This file is automatically generated by Coolify.\n" . + "# Do not edit it manually (only if you know what are you doing).\n\n" . $conf; $base64 = base64_encode($conf); @@ -253,8 +255,8 @@ public function setupDefault404Redirect() redir $redirect_url }"; $conf = - "# This file is automatically generated by Coolify.\n". - "# Do not edit it manually (only if you know what are you doing).\n\n". + "# This file is automatically generated by Coolify.\n" . + "# Do not edit it manually (only if you know what are you doing).\n\n" . $conf; $base64 = base64_encode($conf); } @@ -272,7 +274,7 @@ public function setupDefault404Redirect() public function setupDynamicProxyConfiguration() { $settings = instanceSettings(); - $dynamic_config_path = $this->proxyPath().'/dynamic'; + $dynamic_config_path = $this->proxyPath() . '/dynamic'; if ($this->proxyType() === ProxyTypes::TRAEFIK->value) { $file = "$dynamic_config_path/coolify.yaml"; if (empty($settings->fqdn) || (isCloud() && $this->id !== 0) || ! $this->isLocalhost()) { @@ -391,8 +393,8 @@ public function setupDynamicProxyConfiguration() } $yaml = Yaml::dump($traefik_dynamic_conf, 12, 2); $yaml = - "# This file is automatically generated by Coolify.\n". - "# Do not edit it manually (only if you know what are you doing).\n\n". + "# This file is automatically generated by Coolify.\n" . + "# Do not edit it manually (only if you know what are you doing).\n\n" . $yaml; $base64 = base64_encode($yaml); @@ -456,13 +458,13 @@ public function proxyPath() if (isDev()) { $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/caddy'; } else { - $proxy_path = $proxy_path.'/caddy'; + $proxy_path = $proxy_path . '/caddy'; } } elseif ($proxyType === ProxyTypes::NGINX->value) { if (isDev()) { $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/nginx'; } else { - $proxy_path = $proxy_path.'/nginx'; + $proxy_path = $proxy_path . '/nginx'; } } @@ -538,6 +540,16 @@ public function generateSentinelToken() return $encrypted; } + public function sentinelUpdateAt(bool $isReset = false) + { + $this->sentinel_updated_at = $isReset ? now()->subMinutes(6000) : now(); + $this->save(); + } + public function isSentinelLive() + { + return Carbon::parse($this->sentinel_updated_at)->isAfter(now()->subMinutes(4)); + } + public function isSentinelEnabled() { return $this->isMetricsEnabled() || $this->isServerApiEnabled(); @@ -550,7 +562,7 @@ public function isMetricsEnabled() public function isServerApiEnabled() { - return $this->settings->is_server_api_enabled; + return $this->settings->is_sentinel_enabled; } public function checkServerApi() @@ -591,7 +603,15 @@ public function getCpuMetrics(int $mins = 5) { if ($this->isMetricsEnabled()) { $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $cpu = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://localhost:8888/api/cpu/history?from=$from'"], $this, false); + if (isDev() && $this->id === 0) { + $process = Process::run("curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://host.docker.internal:8888/api/cpu/history?from=$from"); + if ($process->failed()) { + throw new \Exception($process->errorOutput()); + } + $cpu = $process->output(); + } else { + $cpu = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://localhost:8888/api/cpu/history?from=$from'"], $this, false); + } if (str($cpu)->contains('error')) { $error = json_decode($cpu, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); @@ -600,17 +620,12 @@ public function getCpuMetrics(int $mins = 5) } throw new \Exception($error); } - $cpu = str($cpu)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($cpu)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $cpu_usage_percent] = explode(',', trim($line)); - $cpu_usage_percent = number_format($cpu_usage_percent, 0); - - return [(int) $time, (float) $cpu_usage_percent]; - }); + $cpu = json_decode($cpu, true); + $parsedCollection = collect($cpu)->map(function ($metric) { + return [(int)$metric['time'], (float)$metric['percent']]; }); + return $parsedCollection; - return $parsedCollection->toArray(); } } @@ -618,7 +633,15 @@ public function getMemoryMetrics(int $mins = 5) { if ($this->isMetricsEnabled()) { $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $memory = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://localhost:8888/api/memory/history?from=$from'"], $this, false); + if (isDev() && $this->id === 0) { + $process = Process::run("curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://host.docker.internal:8888/api/memory/history?from=$from"); + if ($process->failed()) { + throw new \Exception($process->errorOutput()); + } + $memory = $process->output(); + } else { + $memory = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://localhost:8888/api/memory/history?from=$from'"], $this, false); + } if (str($memory)->contains('error')) { $error = json_decode($memory, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); @@ -627,14 +650,9 @@ public function getMemoryMetrics(int $mins = 5) } throw new \Exception($error); } - $memory = str($memory)->explode("\n")->skip(1)->all(); - $parsedCollection = collect($memory)->flatMap(function ($item) { - return collect(explode("\n", trim($item)))->map(function ($line) { - [$time, $used, $free, $usedPercent] = explode(',', trim($line)); - $usedPercent = number_format($usedPercent, 0); - - return [(int) $time, (float) $usedPercent]; - }); + $memory = json_decode($memory, true); + $parsedCollection = collect($memory)->map(function ($metric) { + return [(int)$metric['time'], (float)$metric['usedPercent']]; }); return $parsedCollection->toArray(); @@ -1054,6 +1072,37 @@ public function isSwarmWorker() return data_get($this, 'settings.is_swarm_worker'); } + public function status(): bool + { + ['uptime' => $uptime] = $this->validateConnection(false); + if ($uptime) { + if ($this->unreachable_notification_sent === true) { + $this->update(['unreachable_notification_sent' => false]); + } + } else { + // $this->server->team?->notify(new Unreachable($this->server)); + foreach ($this->applications as $application) { + $application->update(['status' => 'exited']); + } + foreach ($this->databases as $database) { + $database->update(['status' => 'exited']); + } + foreach ($this->services as $service) { + $apps = $service->applications()->get(); + $dbs = $service->databases()->get(); + foreach ($apps as $app) { + $app->update(['status' => 'exited']); + } + foreach ($dbs as $db) { + $db->update(['status' => 'exited']); + } + } + + return false; + } + + return true; + } public function validateConnection($isManualCheck = true) { config()->set('constants.ssh.mux_enabled', ! $isManualCheck); diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index f5e0f7b0b..f2eba4854 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -24,7 +24,7 @@ 'is_logdrain_newrelic_enabled' => ['type' => 'boolean'], 'is_metrics_enabled' => ['type' => 'boolean'], 'is_reachable' => ['type' => 'boolean'], - 'is_server_api_enabled' => ['type' => 'boolean'], + 'is_sentinel_enabled' => ['type' => 'boolean'], 'is_swarm_manager' => ['type' => 'boolean'], 'is_swarm_worker' => ['type' => 'boolean'], 'is_usable' => ['type' => 'boolean'], @@ -55,7 +55,6 @@ class ServerSetting extends Model 'docker_cleanup_threshold' => 'integer', 'sentinel_token' => 'encrypted', ]; - public function server() { return $this->belongsTo(Server::class); diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 86c6def76..7ed806d43 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -164,7 +164,7 @@ function get_route_parameters(): array function get_latest_sentinel_version(): string { try { - $response = Http::get('https://cdn.coollabs.io/sentinel/versions.json'); + $response = Http::get('https://cdn.coollabs.io/coolify/versions.json'); $versions = $response->json(); return data_get($versions, 'sentinel.version'); diff --git a/database/migrations/2024_07_18_123458_add_force_cleanup_server.php b/database/migrations/2024_07_18_123458_add_force_cleanup_server.php index a33665bd0..ea3695b3f 100644 --- a/database/migrations/2024_07_18_123458_add_force_cleanup_server.php +++ b/database/migrations/2024_07_18_123458_add_force_cleanup_server.php @@ -12,7 +12,7 @@ public function up(): void { Schema::table('server_settings', function (Blueprint $table) { - $table->boolean('is_force_cleanup_enabled')->default(false)->after('is_sentinel_enabled'); + $table->boolean('is_force_cleanup_enabled')->default(false); }); } diff --git a/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php b/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php index 21c871cf4..051457600 100644 --- a/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php +++ b/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php @@ -15,12 +15,16 @@ public function up(): void $table->dropColumn('metrics_token'); $table->dropColumn('metrics_refresh_rate_seconds'); $table->dropColumn('metrics_history_days'); + $table->dropColumn('is_server_api_enabled'); + + $table->boolean('is_sentinel_enabled')->default(true); $table->text('sentinel_token')->nullable(); - $table->integer('sentinel_metrics_refresh_rate_seconds')->default(5); - $table->integer('sentinel_metrics_history_days')->default(30); + $table->integer('sentinel_metrics_refresh_rate_seconds')->default(10); + $table->integer('sentinel_metrics_history_days')->default(7); + $table->integer('sentinel_push_interval_seconds')->default(60); }); Schema::table('servers', function (Blueprint $table) { - $table->dateTime('sentinel_update_at')->default(now()); + $table->dateTime('sentinel_updated_at')->default(now()); }); } @@ -33,12 +37,16 @@ public function down(): void $table->string('metrics_token')->nullable(); $table->integer('metrics_refresh_rate_seconds')->default(5); $table->integer('metrics_history_days')->default(30); + $table->boolean('is_server_api_enabled')->default(false); + $table->dropColumn('sentinel_token'); $table->dropColumn('sentinel_metrics_refresh_rate_seconds'); $table->dropColumn('sentinel_metrics_history_days'); + $table->dropColumn('sentinel_push_interval_seconds'); + $table->dropColumn('is_sentinel_enabled'); }); Schema::table('servers', function (Blueprint $table) { - $table->dropColumn('sentinel_update_at'); + $table->dropColumn('sentinel_updated_at'); }); } }; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index be5083108..1888f0440 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -26,6 +26,7 @@ public function run(): void S3StorageSeeder::class, StandalonePostgresqlSeeder::class, OauthSettingSeeder::class, + GenerateSentinelTokenSeeder::class, ]); } } diff --git a/database/seeders/GenerateSentinelTokenSeeder.php b/database/seeders/GenerateSentinelTokenSeeder.php new file mode 100644 index 000000000..d915f7259 --- /dev/null +++ b/database/seeders/GenerateSentinelTokenSeeder.php @@ -0,0 +1,25 @@ +settings->sentinel_token)->isEmpty()) { + $server->generateSentinelToken(); + } + } + }); + } catch (\Throwable $e) { + echo "Error: {$e->getMessage()}\n"; + ray($e->getMessage()); + } + } +} diff --git a/database/seeders/ProductionSeeder.php b/database/seeders/ProductionSeeder.php index 206f04d6b..a1a025e8d 100644 --- a/database/seeders/ProductionSeeder.php +++ b/database/seeders/ProductionSeeder.php @@ -186,6 +186,7 @@ public function run(): void $this->call(OauthSettingSeeder::class); $this->call(PopulateSshKeysDirectorySeeder::class); + $this->call(GenerateSentinelTokenSeeder::class); } } diff --git a/openapi.yaml b/openapi.yaml index 3521b7de4..0963857c9 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4959,7 +4959,7 @@ components: type: boolean is_reachable: type: boolean - is_server_api_enabled: + is_sentinel_enabled: type: boolean is_swarm_manager: type: boolean diff --git a/resources/views/components/forms/checkbox.blade.php b/resources/views/components/forms/checkbox.blade.php index 439fc4ad2..fed6ad77f 100644 --- a/resources/views/components/forms/checkbox.blade.php +++ b/resources/views/components/forms/checkbox.blade.php @@ -14,7 +14,10 @@ 'w-full' => $fullWidth, ])> @if (!$hideLabel) -

Sentinel

- {{-- @if ($server->isSentinelEnabled()) --}} - {{-- Restart --}} - {{-- @endif --}} + @if ($server->isSentinelEnabled()) +
settings->sentinel_push_interval_seconds }}s="checkSyncStatus"> + @if ($server->isSentinelLive()) + + @else + + @endif + Restart +
+ @endif
@if (isDev()) -
- - Start Sentinel -
+
+ + @if ($server->isSentinelEnabled()) + + @else + + @endif +
- + Regenerate
-
- - +
+
+ + + +
@else diff --git a/routes/api.php b/routes/api.php index db07921a4..71552ae48 100644 --- a/routes/api.php +++ b/routes/api.php @@ -147,10 +147,14 @@ if (! $server) { return response()->json(['message' => 'Server not found'], 404); } + if ($server->settings->sentinel_token !== $naked_token) { + logger('Unauthorized'); + return response()->json(['message' => 'Unauthorized'], 401); + } $data = request()->all(); - $server->update(['sentinel_update_at' => now()]); - PushServerUpdateJob::dispatch($server, $data); + PushServerUpdateJob::dispatch($server, $data); + logger('hello'); return response()->json(['message' => 'ok'], 200); }); }); diff --git a/versions.json b/versions.json index 7d8a9b2d1..e24038001 100644 --- a/versions.json +++ b/versions.json @@ -1,7 +1,7 @@ { "coolify": { "v4": { - "version": "4.0.0-beta.361" + "version": "4.0.0-beta.360" }, "nightly": { "version": "4.0.0-beta.362" @@ -11,6 +11,9 @@ }, "realtime": { "version": "1.0.3" + }, + "sentinel": { + "version": "next" } } } From 567ce172dc96326b07d9049ab85176234f6291be Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 13:54:25 +0200 Subject: [PATCH 044/120] Refactor server form view to conditionally display Sentinel section based on server settings --- .../views/livewire/server/form.blade.php | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 526d087ae..f05ec0dc4 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -275,21 +275,21 @@ functional issues.

helper="You can define the maximum duration for a deployment to run before timing it out." />
-
-

Sentinel

- @if ($server->isSentinelEnabled()) -
settings->sentinel_push_interval_seconds }}s="checkSyncStatus"> - @if ($server->isSentinelLive()) - - @else - - @endif - Restart -
- @endif -
@if (isDev()) +
+

Sentinel

+ @if ($server->isSentinelEnabled()) +
settings->sentinel_push_interval_seconds }}s="checkSyncStatus"> + @if ($server->isSentinelLive()) + + @else + + @endif + Restart +
+ @endif +
- @else -
Metrics are disabled until a few bugs are fixed.
@endif @endif From bf0a2f805b31dd239055a1226f592d7374027793 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 14:03:10 +0200 Subject: [PATCH 045/120] Refactor get_latest_sentinel_version() to use 'coolify.sentinel.version' key from versions.json --- bootstrap/helpers/shared.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 7ed806d43..f70c705c7 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -167,7 +167,7 @@ function get_latest_sentinel_version(): string $response = Http::get('https://cdn.coollabs.io/coolify/versions.json'); $versions = $response->json(); - return data_get($versions, 'sentinel.version'); + return data_get($versions, 'coolify.sentinel.version'); } catch (\Throwable $e) { //throw $e; ray($e->getMessage()); From 73923a0207231f98a2075445f3fbfe455ae8feed Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 15:33:05 +0200 Subject: [PATCH 046/120] fix: metrics --- app/Livewire/Project/Shared/Metrics.php | 9 +-- app/Models/Application.php | 100 ++++++++++++++++-------- routes/api.php | 1 - 3 files changed, 69 insertions(+), 41 deletions(-) diff --git a/app/Livewire/Project/Shared/Metrics.php b/app/Livewire/Project/Shared/Metrics.php index d9d7dd3ef..fdc35fc0f 100644 --- a/app/Livewire/Project/Shared/Metrics.php +++ b/app/Livewire/Project/Shared/Metrics.php @@ -31,13 +31,8 @@ public function pollData() public function loadData() { try { - $metrics = $this->resource->getMetrics($this->interval); - $cpuMetrics = collect($metrics)->map(function ($metric) { - return [$metric[0], $metric[1]]; - }); - $memoryMetrics = collect($metrics)->map(function ($metric) { - return [$metric[0], $metric[2]]; - }); + $cpuMetrics = $this->resource->getCpuMetrics($this->interval); + $memoryMetrics = $this->resource->getMemoryMetrics($this->interval); $this->dispatch("refreshChartData-{$this->chartId}-cpu", [ 'seriesData' => $cpuMetrics, ]); diff --git a/app/Models/Application.php b/app/Models/Application.php index 10ef8079c..3002f1f45 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -213,7 +213,7 @@ public function delete_configurations() $server = data_get($this, 'destination.server'); $workdir = $this->workdir(); if (str($workdir)->endsWith($this->uuid)) { - instant_remote_process(['rm -rf '.$this->workdir()], $server, false); + instant_remote_process(['rm -rf ' . $this->workdir()], $server, false); } } @@ -348,7 +348,7 @@ public function type() public function publishDirectory(): Attribute { return Attribute::make( - set: fn ($value) => $value ? '/'.ltrim($value, '/') : null, + set: fn($value) => $value ? '/' . ltrim($value, '/') : null, ); } @@ -430,7 +430,7 @@ public function gitCommitLink($link): string $git_repository = str_replace('.git', '', $this->git_repository); $url = Url::fromString($git_repository); $url = $url->withUserInfo(''); - $url = $url->withPath($url->getPath().'/commits/'.$link); + $url = $url->withPath($url->getPath() . '/commits/' . $link); return $url->__toString(); } @@ -483,21 +483,21 @@ public function dockerComposeLocation(): Attribute public function baseDirectory(): Attribute { return Attribute::make( - set: fn ($value) => '/'.ltrim($value, '/'), + set: fn($value) => '/' . ltrim($value, '/'), ); } public function portsMappings(): Attribute { return Attribute::make( - set: fn ($value) => $value === '' ? null : $value, + set: fn($value) => $value === '' ? null : $value, ); } public function portsMappingsArray(): Attribute { return Attribute::make( - get: fn () => is_null($this->ports_mappings) + get: fn() => is_null($this->ports_mappings) ? [] : explode(',', $this->ports_mappings), @@ -614,7 +614,7 @@ public function status(): Attribute public function portsExposesArray(): Attribute { return Attribute::make( - get: fn () => is_null($this->ports_exposes) + get: fn() => is_null($this->ports_exposes) ? [] : explode(',', $this->ports_exposes) ); @@ -831,7 +831,7 @@ public function isHealthcheckDisabled(): bool public function workdir() { - return application_configuration_dir()."/{$this->uuid}"; + return application_configuration_dir() . "/{$this->uuid}"; } public function isLogDrainEnabled() @@ -841,7 +841,7 @@ public function isLogDrainEnabled() public function isConfigurationChanged(bool $save = false) { - $newConfigHash = $this->fqdn.$this->git_repository.$this->git_branch.$this->git_commit_sha.$this->build_pack.$this->static_image.$this->install_command.$this->build_command.$this->start_command.$this->ports_exposes.$this->ports_mappings.$this->base_directory.$this->publish_directory.$this->dockerfile.$this->dockerfile_location.$this->custom_labels.$this->custom_docker_run_options.$this->dockerfile_target_build.$this->redirect; + $newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command . $this->build_command . $this->start_command . $this->ports_exposes . $this->ports_mappings . $this->base_directory . $this->publish_directory . $this->dockerfile . $this->dockerfile_location . $this->custom_labels . $this->custom_docker_run_options . $this->dockerfile_target_build . $this->redirect; if ($this->pull_request_id === 0 || $this->pull_request_id === null) { $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort()); } else { @@ -895,7 +895,7 @@ public function generateBaseDir(string $uuid) public function dirOnServer() { - return application_configuration_dir()."/{$this->uuid}"; + return application_configuration_dir() . "/{$this->uuid}"; } public function setGitImportSettings(string $deployment_uuid, string $git_clone_command, bool $public = false) @@ -1019,7 +1019,7 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && " . $this->buildGitCheckoutCommand($pr_branch_name); } elseif ($git_type === 'github' || $git_type === 'gitea') { $branch = "pull/{$pull_request_id}/head:$pr_branch_name"; if ($exec_in_docker) { @@ -1027,14 +1027,14 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && " . $this->buildGitCheckoutCommand($pr_branch_name); } elseif ($git_type === 'bitbucket') { if ($exec_in_docker) { $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'")); } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" ".$this->buildGitCheckoutCommand($commit); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" " . $this->buildGitCheckoutCommand($commit); } } @@ -1063,7 +1063,7 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && " . $this->buildGitCheckoutCommand($pr_branch_name); } elseif ($git_type === 'github' || $git_type === 'gitea') { $branch = "pull/{$pull_request_id}/head:$pr_branch_name"; if ($exec_in_docker) { @@ -1071,14 +1071,14 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && " . $this->buildGitCheckoutCommand($pr_branch_name); } elseif ($git_type === 'bitbucket') { if ($exec_in_docker) { $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'")); } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" ".$this->buildGitCheckoutCommand($commit); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" " . $this->buildGitCheckoutCommand($commit); } } @@ -1131,7 +1131,7 @@ public function oldRawParser() } if ($source->startsWith('.')) { $source = $source->after('.'); - $source = $workdir.$source; + $source = $workdir . $source; } $commands->push("mkdir -p $source > /dev/null 2>&1 || true"); } @@ -1142,7 +1142,7 @@ public function oldRawParser() $labels->push('coolify.managed=true'); } if (! $labels->contains('coolify.applicationId')) { - $labels->push('coolify.applicationId='.$this->id); + $labels->push('coolify.applicationId=' . $this->id); } if (! $labels->contains('coolify.type')) { $labels->push('coolify.type=application'); @@ -1264,7 +1264,7 @@ public function parseContainerLabels(?ApplicationPreview $preview = null) public function fqdns(): Attribute { return Attribute::make( - get: fn () => is_null($this->fqdn) + get: fn() => is_null($this->fqdn) ? [] : explode(',', $this->fqdn), ); @@ -1325,10 +1325,10 @@ public function parseHealthcheckFromDockerfile($dockerfile, bool $isInit = false continue; } if (isset($healthcheckCommand) && str_contains($trimmedLine, '\\')) { - $healthcheckCommand .= ' '.trim($trimmedLine, '\\ '); + $healthcheckCommand .= ' ' . trim($trimmedLine, '\\ '); } if (isset($healthcheckCommand) && ! str_contains($trimmedLine, '\\') && ! empty($healthcheckCommand)) { - $healthcheckCommand .= ' '.$trimmedLine; + $healthcheckCommand .= ' ' . $trimmedLine; break; } } @@ -1400,13 +1400,21 @@ public static function getDomainsByUuid(string $uuid): array return []; } - 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 (isDev() && $server->id === 0) { + $process = Process::run("curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://host.docker.internal:8888/api/container/{$container_name}/cpu/history?from=$from"); + if ($process->failed()) { + throw new \Exception($process->errorOutput()); + } + $metrics = $process->output(); + } else { + $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?'); @@ -1415,16 +1423,41 @@ public function getMetrics(int $mins = 5) } 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]; - }); + $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; + if ($server->isMetricsEnabled()) { + $from = now()->subMinutes($mins)->toIso8601ZuluString(); + if (isDev() && $server->id === 0) { + $process = Process::run("curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://host.docker.internal:8888/api/container/{$container_name}/memory/history?from=$from"); + if ($process->failed()) { + throw new \Exception($process->errorOutput()); + } + $metrics = $process->output(); + } else { + $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) { + logger($metric); + return [(int)$metric['time'], (float)$metric['used']]; }); - return $parsedCollection->toArray(); } } @@ -1459,7 +1492,8 @@ public function generateConfig($is_json = false) return $config; } - public function setConfig($config) { + public function setConfig($config) + { $config = $config; $validator = Validator::make(['config' => $config], [ diff --git a/routes/api.php b/routes/api.php index 71552ae48..d91de155b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -154,7 +154,6 @@ $data = request()->all(); PushServerUpdateJob::dispatch($server, $data); - logger('hello'); return response()->json(['message' => 'ok'], 200); }); }); From 46ec8eed64586b674e7e793ba8aed19566967da5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 15:43:53 +0200 Subject: [PATCH 047/120] fix: generate sentinel url --- app/Livewire/Server/Form.php | 2 ++ app/Models/Server.php | 16 ++++++++++++++++ ...6_update_metrics_token_in_server_settings.php | 4 +++- database/seeders/DatabaseSeeder.php | 2 +- database/seeders/ProductionSeeder.php | 2 +- ...entinelTokenSeeder.php => SentinelSeeder.php} | 8 +++++++- resources/views/livewire/server/form.blade.php | 3 +++ 7 files changed, 33 insertions(+), 4 deletions(-) rename database/seeders/{GenerateSentinelTokenSeeder.php => SentinelSeeder.php} (56%) diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 48c7c0ae7..dadf9033d 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -60,6 +60,7 @@ public function getListeners() 'server.settings.sentinel_metrics_history_days' => 'required|integer|min:1', 'server.settings.sentinel_push_interval_seconds' => 'required|integer|min:10', 'wildcard_domain' => 'nullable|url', + 'server.settings.sentinel_custom_url' => 'nullable|url', 'server.settings.is_sentinel_enabled' => 'required|boolean', 'server.settings.server_timezone' => 'required|string|timezone', 'server.settings.force_docker_cleanup' => 'required|boolean', @@ -88,6 +89,7 @@ public function getListeners() 'server.settings.sentinel_metrics_history_days' => 'Metrics History', 'server.settings.sentinel_push_interval_seconds' => 'Push Interval', 'server.settings.is_sentinel_enabled' => 'Server API', + 'server.settings.sentinel_custom_url' => 'Sentinel URL', 'server.settings.server_timezone' => 'Server Timezone', 'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', 'server.settings.delete_unused_networks' => 'Delete Unused Networks', diff --git a/app/Models/Server.php b/app/Models/Server.php index aac3ddddf..5bcd5b9de 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -527,6 +527,22 @@ public function forceDisableServer() Storage::disk('ssh-mux')->delete($this->muxFilename()); } + public function generateSentinelUrl() { + if ($this->isLocalhost()) { + return 'http://host.docker.internal:8888'; + } + $settings = InstanceSettings::get(); + if ($settings->fqdn) { + return $settings->fqdn; + } + if ($settings->ipv4) { + return $settings->ipv4 . ':8888'; + } + if ($settings->ipv6) { + return $settings->ipv6 . ':8888'; + } + return null; + } public function generateSentinelToken() { $data = [ diff --git a/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php b/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php index 051457600..737dfd5ee 100644 --- a/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php +++ b/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php @@ -22,6 +22,7 @@ public function up(): void $table->integer('sentinel_metrics_refresh_rate_seconds')->default(10); $table->integer('sentinel_metrics_history_days')->default(7); $table->integer('sentinel_push_interval_seconds')->default(60); + $table->string('sentinel_custom_url')->nullable(); }); Schema::table('servers', function (Blueprint $table) { $table->dateTime('sentinel_updated_at')->default(now()); @@ -39,11 +40,12 @@ public function down(): void $table->integer('metrics_history_days')->default(30); $table->boolean('is_server_api_enabled')->default(false); + $table->dropColumn('is_sentinel_enabled'); $table->dropColumn('sentinel_token'); $table->dropColumn('sentinel_metrics_refresh_rate_seconds'); $table->dropColumn('sentinel_metrics_history_days'); $table->dropColumn('sentinel_push_interval_seconds'); - $table->dropColumn('is_sentinel_enabled'); + $table->dropColumn('sentinel_custom_url'); }); Schema::table('servers', function (Blueprint $table) { $table->dropColumn('sentinel_updated_at'); diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 1888f0440..cec05c8fe 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -26,7 +26,7 @@ public function run(): void S3StorageSeeder::class, StandalonePostgresqlSeeder::class, OauthSettingSeeder::class, - GenerateSentinelTokenSeeder::class, + SentinelSeeder::class, ]); } } diff --git a/database/seeders/ProductionSeeder.php b/database/seeders/ProductionSeeder.php index a1a025e8d..90b9d46ff 100644 --- a/database/seeders/ProductionSeeder.php +++ b/database/seeders/ProductionSeeder.php @@ -186,7 +186,7 @@ public function run(): void $this->call(OauthSettingSeeder::class); $this->call(PopulateSshKeysDirectorySeeder::class); - $this->call(GenerateSentinelTokenSeeder::class); + $this->call(SentinelSeeder::class); } } diff --git a/database/seeders/GenerateSentinelTokenSeeder.php b/database/seeders/SentinelSeeder.php similarity index 56% rename from database/seeders/GenerateSentinelTokenSeeder.php rename to database/seeders/SentinelSeeder.php index d915f7259..3f719cf6e 100644 --- a/database/seeders/GenerateSentinelTokenSeeder.php +++ b/database/seeders/SentinelSeeder.php @@ -5,7 +5,7 @@ use App\Models\Server; use Illuminate\Database\Seeder; -class GenerateSentinelTokenSeeder extends Seeder +class SentinelSeeder extends Seeder { public function run() { @@ -15,6 +15,12 @@ public function run() if (str($server->settings->sentinel_token)->isEmpty()) { $server->generateSentinelToken(); } + if (str($server->settings->sentinel_custom_url)->isEmpty()) { + $url = $server->generateSentinelUrl(); + logger()->info("Setting sentinel custom url for server {$server->id} to {$url}"); + $server->settings->sentinel_custom_url = $url; + $server->settings->save(); + } } }); } catch (\Throwable $e) { diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index f05ec0dc4..43d982b6c 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -305,6 +305,9 @@ functional issues.

+ + Regenerate
From 8c53af088ef257b9b4209f825df4b3a2addd6f78 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 15:45:02 +0200 Subject: [PATCH 048/120] Refactor StartSentinel.php to use data_get() for retrieving server settings --- app/Actions/Server/StartSentinel.php | 19 +++++++------------ app/Models/Server.php | 6 +++--- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php index cfea6afd8..a1d36a041 100644 --- a/app/Actions/Server/StartSentinel.php +++ b/app/Actions/Server/StartSentinel.php @@ -15,20 +15,15 @@ public function handle(Server $server, $version = 'next', bool $restart = false) if ($restart) { StopSentinel::run($server); } - $metrics_history = $server->settings->sentinel_metrics_history_days; - $refresh_rate = $server->settings->sentinel_metrics_refresh_rate_seconds; - $push_interval = $server->settings->sentinel_push_interval_seconds; - $token = $server->settings->sentinel_token; - $endpoint = InstanceSettings::get()->fqdn; + $metrics_history = data_get($server, 'settings.sentinel_metrics_history_days'); + $refresh_rate = data_get($server, 'settings.sentinel_metrics_refresh_rate_seconds'); + $push_interval = data_get($server, 'settings.sentinel_push_interval_seconds'); + $token = data_get($server, 'settings.sentinel_token'); + $endpoint = data_get($server, 'settings.sentinel_custom_url'); $mount_dir = '/data/coolify/sentinel'; $image = "ghcr.io/coollabsio/sentinel:$version"; - - if ($server->isLocalhost()) { - $endpoint = 'http://host.docker.internal:8000'; - } else { - if (! $endpoint) { - throw new \Exception('You should set FQDN in Instance Settings.'); - } + if (! $endpoint) { + throw new \Exception('You should set FQDN in Instance Settings.'); } $environments = [ 'TOKEN' => $token, diff --git a/app/Models/Server.php b/app/Models/Server.php index 5bcd5b9de..3639d9263 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -529,17 +529,17 @@ public function forceDisableServer() public function generateSentinelUrl() { if ($this->isLocalhost()) { - return 'http://host.docker.internal:8888'; + return 'http://host.docker.internal:8000'; } $settings = InstanceSettings::get(); if ($settings->fqdn) { return $settings->fqdn; } if ($settings->ipv4) { - return $settings->ipv4 . ':8888'; + return $settings->ipv4 . ':8000'; } if ($settings->ipv6) { - return $settings->ipv6 . ':8888'; + return $settings->ipv6 . ':8000'; } return null; } From 902cde59057ead5d7dda36f0096d041a8cc2019f Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:19:04 +0200 Subject: [PATCH 049/120] improve custom redis.conf --- app/Actions/Database/StartRedis.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index eeddab924..186ad0432 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -37,6 +37,8 @@ public function handle(StandaloneRedis $database) $environment_variables = $this->generate_environment_variables(); $this->add_custom_redis(); + $startCommand = $this->buildStartCommand(); + $docker_compose = [ 'services' => [ $container_name => [ @@ -105,7 +107,6 @@ public function handle(StandaloneRedis $database) 'target' => '/usr/local/etc/redis/redis.conf', 'read_only' => true, ]; - $docker_compose['services'][$container_name]['command'] = "redis-server /usr/local/etc/redis/redis.conf --requirepass {$this->database->redis_password} --appendonly yes"; } // Add custom docker run options @@ -173,6 +174,27 @@ private function generate_environment_variables() return $environment_variables->all(); } + private function buildStartCommand(): string + { + $hasRedisConf = ! is_null($this->database->redis_conf) && ! empty($this->database->redis_conf); + $redisConfPath = '/usr/local/etc/redis/redis.conf'; + + if ($hasRedisConf) { + $confContent = $this->database->redis_conf; + $hasRequirePass = str_contains($confContent, 'requirepass'); + + if ($hasRequirePass) { + $command = "redis-server $redisConfPath"; + } else { + $command = "redis-server $redisConfPath --requirepass {$this->database->redis_password}"; + } + } else { + $command = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; + } + + return $command; + } + private function add_custom_redis() { if (is_null($this->database->redis_conf) || empty($this->database->redis_conf)) { From c6e2c7e5e3f9531699d48f19986c476d2b198998 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:35:20 +0200 Subject: [PATCH 050/120] fix start command --- app/Actions/Database/StartRedis.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 186ad0432..3e3c5b3b9 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -21,8 +21,6 @@ public function handle(StandaloneRedis $database) { $this->database = $database; - $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; - $container_name = $this->database->uuid; $this->configuration_dir = database_configuration_dir().'/'.$container_name; From 79caa3c26bcf0224cdfb3de30170d3fde884c66f Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:02:37 +0200 Subject: [PATCH 051/120] fix: allow setting standalone redis variables via ENVs (team variables...) --- app/Actions/Database/StartRedis.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 3e3c5b3b9..45a031e70 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -159,12 +159,29 @@ private function generate_local_persistent_volumes_only_volume_names() private function generate_environment_variables() { $environment_variables = collect(); + $redis_password = null; + $redis_username = null; + foreach ($this->database->runtime_environment_variables as $env) { $environment_variables->push("$env->key=$env->real_value"); + + if ($env->key === 'REDIS_PASSWORD') { + $redis_password = $env->real_value; + } elseif ($env->key === 'REDIS_USERNAME') { + $redis_username = $env->real_value; + } } - if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) { + if (is_null($redis_password)) { $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); + } else { + $this->database->update(['redis_password' => $redis_password]); + } + + if (is_null($redis_username)) { + $environment_variables->push("REDIS_USERNAME={$this->database->redis_username}"); + } else { + $this->database->update(['redis_username' => $redis_username]); } add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables); From 2702fbc284f8aaa265603cd5a17ce35903be3257 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 17:03:50 +0200 Subject: [PATCH 052/120] Refactor logging in PushServerUpdateJob, Application, and SentinelSeeder --- app/Jobs/PushServerUpdateJob.php | 9 +++-- app/Models/Application.php | 51 +++++++++++++++-------------- database/seeders/SentinelSeeder.php | 1 - routes/api.php | 2 +- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 82e311d47..3ef4b944a 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -63,6 +63,7 @@ class PushServerUpdateJob implements ShouldQueue public Collection $foundApplicationPreviewsIds; public bool $foundProxy = false; + public bool $foundLogDrainContainer = false; public function backoff(): int @@ -204,7 +205,8 @@ public function handle() } - private function serverStatus(){ + private function serverStatus() + { if ($this->server->isFunctional() === false) { throw new \Exception('Server is not ready.'); } @@ -212,6 +214,7 @@ private function serverStatus(){ throw new \Exception('Server is not reachable.'); } } + private function updateApplicationStatus(string $applicationId, string $containerStatus) { $application = $this->applications->where('id', $applicationId)->first(); @@ -278,7 +281,6 @@ private function updateProxyStatus() StartProxy::run($this->server, false); } } catch (\Throwable $e) { - logger()->error($e); } } else { $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); @@ -396,7 +398,8 @@ private function isRunning(string $containerStatus) return str($containerStatus)->contains('running'); } - private function checkLogDrainContainer(){ + private function checkLogDrainContainer() + { if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) { InstallLogDrain::dispatch($this->server); } diff --git a/app/Models/Application.php b/app/Models/Application.php index 3002f1f45..846d7df4c 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -213,7 +213,7 @@ public function delete_configurations() $server = data_get($this, 'destination.server'); $workdir = $this->workdir(); if (str($workdir)->endsWith($this->uuid)) { - instant_remote_process(['rm -rf ' . $this->workdir()], $server, false); + instant_remote_process(['rm -rf '.$this->workdir()], $server, false); } } @@ -348,7 +348,7 @@ public function type() public function publishDirectory(): Attribute { return Attribute::make( - set: fn($value) => $value ? '/' . ltrim($value, '/') : null, + set: fn ($value) => $value ? '/'.ltrim($value, '/') : null, ); } @@ -430,7 +430,7 @@ public function gitCommitLink($link): string $git_repository = str_replace('.git', '', $this->git_repository); $url = Url::fromString($git_repository); $url = $url->withUserInfo(''); - $url = $url->withPath($url->getPath() . '/commits/' . $link); + $url = $url->withPath($url->getPath().'/commits/'.$link); return $url->__toString(); } @@ -483,21 +483,21 @@ public function dockerComposeLocation(): Attribute public function baseDirectory(): Attribute { return Attribute::make( - set: fn($value) => '/' . ltrim($value, '/'), + set: fn ($value) => '/'.ltrim($value, '/'), ); } public function portsMappings(): Attribute { return Attribute::make( - set: fn($value) => $value === '' ? null : $value, + set: fn ($value) => $value === '' ? null : $value, ); } public function portsMappingsArray(): Attribute { return Attribute::make( - get: fn() => is_null($this->ports_mappings) + get: fn () => is_null($this->ports_mappings) ? [] : explode(',', $this->ports_mappings), @@ -614,7 +614,7 @@ public function status(): Attribute public function portsExposesArray(): Attribute { return Attribute::make( - get: fn() => is_null($this->ports_exposes) + get: fn () => is_null($this->ports_exposes) ? [] : explode(',', $this->ports_exposes) ); @@ -831,7 +831,7 @@ public function isHealthcheckDisabled(): bool public function workdir() { - return application_configuration_dir() . "/{$this->uuid}"; + return application_configuration_dir()."/{$this->uuid}"; } public function isLogDrainEnabled() @@ -841,7 +841,7 @@ public function isLogDrainEnabled() public function isConfigurationChanged(bool $save = false) { - $newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command . $this->build_command . $this->start_command . $this->ports_exposes . $this->ports_mappings . $this->base_directory . $this->publish_directory . $this->dockerfile . $this->dockerfile_location . $this->custom_labels . $this->custom_docker_run_options . $this->dockerfile_target_build . $this->redirect; + $newConfigHash = $this->fqdn.$this->git_repository.$this->git_branch.$this->git_commit_sha.$this->build_pack.$this->static_image.$this->install_command.$this->build_command.$this->start_command.$this->ports_exposes.$this->ports_mappings.$this->base_directory.$this->publish_directory.$this->dockerfile.$this->dockerfile_location.$this->custom_labels.$this->custom_docker_run_options.$this->dockerfile_target_build.$this->redirect; if ($this->pull_request_id === 0 || $this->pull_request_id === null) { $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort()); } else { @@ -895,7 +895,7 @@ public function generateBaseDir(string $uuid) public function dirOnServer() { - return application_configuration_dir() . "/{$this->uuid}"; + return application_configuration_dir()."/{$this->uuid}"; } public function setGitImportSettings(string $deployment_uuid, string $git_clone_command, bool $public = false) @@ -1019,7 +1019,7 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && " . $this->buildGitCheckoutCommand($pr_branch_name); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name); } elseif ($git_type === 'github' || $git_type === 'gitea') { $branch = "pull/{$pull_request_id}/head:$pr_branch_name"; if ($exec_in_docker) { @@ -1027,14 +1027,14 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && " . $this->buildGitCheckoutCommand($pr_branch_name); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name); } elseif ($git_type === 'bitbucket') { if ($exec_in_docker) { $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'")); } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" " . $this->buildGitCheckoutCommand($commit); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" ".$this->buildGitCheckoutCommand($commit); } } @@ -1063,7 +1063,7 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && " . $this->buildGitCheckoutCommand($pr_branch_name); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name); } elseif ($git_type === 'github' || $git_type === 'gitea') { $branch = "pull/{$pull_request_id}/head:$pr_branch_name"; if ($exec_in_docker) { @@ -1071,14 +1071,14 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && " . $this->buildGitCheckoutCommand($pr_branch_name); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name); } elseif ($git_type === 'bitbucket') { if ($exec_in_docker) { $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'")); } else { $commands->push("echo 'Checking out $branch'"); } - $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" " . $this->buildGitCheckoutCommand($commit); + $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" ".$this->buildGitCheckoutCommand($commit); } } @@ -1131,7 +1131,7 @@ public function oldRawParser() } if ($source->startsWith('.')) { $source = $source->after('.'); - $source = $workdir . $source; + $source = $workdir.$source; } $commands->push("mkdir -p $source > /dev/null 2>&1 || true"); } @@ -1142,7 +1142,7 @@ public function oldRawParser() $labels->push('coolify.managed=true'); } if (! $labels->contains('coolify.applicationId')) { - $labels->push('coolify.applicationId=' . $this->id); + $labels->push('coolify.applicationId='.$this->id); } if (! $labels->contains('coolify.type')) { $labels->push('coolify.type=application'); @@ -1264,7 +1264,7 @@ public function parseContainerLabels(?ApplicationPreview $preview = null) public function fqdns(): Attribute { return Attribute::make( - get: fn() => is_null($this->fqdn) + get: fn () => is_null($this->fqdn) ? [] : explode(',', $this->fqdn), ); @@ -1325,10 +1325,10 @@ public function parseHealthcheckFromDockerfile($dockerfile, bool $isInit = false continue; } if (isset($healthcheckCommand) && str_contains($trimmedLine, '\\')) { - $healthcheckCommand .= ' ' . trim($trimmedLine, '\\ '); + $healthcheckCommand .= ' '.trim($trimmedLine, '\\ '); } if (isset($healthcheckCommand) && ! str_contains($trimmedLine, '\\') && ! empty($healthcheckCommand)) { - $healthcheckCommand .= ' ' . $trimmedLine; + $healthcheckCommand .= ' '.$trimmedLine; break; } } @@ -1425,11 +1425,13 @@ public function getCpuMetrics(int $mins = 5) } $metrics = json_decode($metrics, true); $parsedCollection = collect($metrics)->map(function ($metric) { - return [(int)$metric['time'], (float)$metric['percent']]; + return [(int) $metric['time'], (float) $metric['percent']]; }); + return $parsedCollection->toArray(); } } + public function getMemoryMetrics(int $mins = 5) { $server = $this->destination->server; @@ -1455,9 +1457,9 @@ public function getMemoryMetrics(int $mins = 5) } $metrics = json_decode($metrics, true); $parsedCollection = collect($metrics)->map(function ($metric) { - logger($metric); - return [(int)$metric['time'], (float)$metric['used']]; + return [(int) $metric['time'], (float) $metric['used']]; }); + return $parsedCollection->toArray(); } } @@ -1492,6 +1494,7 @@ public function generateConfig($is_json = false) return $config; } + public function setConfig($config) { diff --git a/database/seeders/SentinelSeeder.php b/database/seeders/SentinelSeeder.php index 3f719cf6e..2d29c1a8d 100644 --- a/database/seeders/SentinelSeeder.php +++ b/database/seeders/SentinelSeeder.php @@ -17,7 +17,6 @@ public function run() } if (str($server->settings->sentinel_custom_url)->isEmpty()) { $url = $server->generateSentinelUrl(); - logger()->info("Setting sentinel custom url for server {$server->id} to {$url}"); $server->settings->sentinel_custom_url = $url; $server->settings->save(); } diff --git a/routes/api.php b/routes/api.php index d91de155b..b63fde871 100644 --- a/routes/api.php +++ b/routes/api.php @@ -148,12 +148,12 @@ return response()->json(['message' => 'Server not found'], 404); } if ($server->settings->sentinel_token !== $naked_token) { - logger('Unauthorized'); return response()->json(['message' => 'Unauthorized'], 401); } $data = request()->all(); PushServerUpdateJob::dispatch($server, $data); + return response()->json(['message' => 'ok'], 200); }); }); From 5274ae1f0b578ab4b27bc4646c1ac2cb86805c93 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:23:33 +0200 Subject: [PATCH 053/120] fix: check for username separately form password --- app/Actions/Database/StartRedis.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 45a031e70..56be36202 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -167,7 +167,9 @@ private function generate_environment_variables() if ($env->key === 'REDIS_PASSWORD') { $redis_password = $env->real_value; - } elseif ($env->key === 'REDIS_USERNAME') { + } + + if ($env->key === 'REDIS_USERNAME') { $redis_username = $env->real_value; } } From edad4fcd5c0b8bdc89e4e590b8336956967df635 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:38:11 +0200 Subject: [PATCH 054/120] update helper text --- .../livewire/project/database/redis/general.blade.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index c76229d28..c5ab13d94 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -16,9 +16,11 @@ $redis_version = explode(':', $database->image)[1] ?? '0.0'; @endphp @if (version_compare($redis_version, '6.0', '>=')) - + @endif - +
-
\ No newline at end of file + From b9c9c1041a911824f5630b8cad87476205587558 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:20:26 +0200 Subject: [PATCH 055/120] feat: add is shared to env variables --- app/Models/EnvironmentVariable.php | 10 +++++++++ ...add_is_shared_to_environment_variables.php | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php diff --git a/app/Models/EnvironmentVariable.php b/app/Models/EnvironmentVariable.php index 531c8fa40..f77d73db8 100644 --- a/app/Models/EnvironmentVariable.php +++ b/app/Models/EnvironmentVariable.php @@ -74,6 +74,9 @@ protected static function booted() 'version' => config('version'), ]); }); + static::saving(function (EnvironmentVariable $environmentVariable) { + $environmentVariable->updateIsShared(); + }); } public function service() @@ -217,4 +220,11 @@ protected function key(): Attribute set: fn (string $value) => str($value)->trim()->replace(' ', '_')->value, ); } + + protected function updateIsShared(): void + { + $type = str($this->value)->after('{{')->before('.')->value; + $isShared = str($this->value)->startsWith('{{'.$type) && str($this->value)->endsWith('}}'); + $this->is_shared = $isShared; + } } diff --git a/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php b/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php new file mode 100644 index 000000000..eb878e2f6 --- /dev/null +++ b/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php @@ -0,0 +1,22 @@ +boolean('is_shared')->default(false); + }); + } + + public function down() + { + Schema::table('environment_variables', function (Blueprint $table) { + $table->dropColumn('is_shared'); + }); + } +} From 6f97d589aee48b673ca6d362526cbe923c62e8e7 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:29:13 +0200 Subject: [PATCH 056/120] feat: variabel sync and support shared vars --- app/Actions/Database/StartRedis.php | 37 ++++++++----------- .../Project/Database/Redis/General.php | 30 ++++++++++++--- bootstrap/helpers/databases.php | 16 ++++++++ 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 56be36202..3705ce938 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -159,31 +159,26 @@ private function generate_local_persistent_volumes_only_volume_names() private function generate_environment_variables() { $environment_variables = collect(); - $redis_password = null; - $redis_username = null; foreach ($this->database->runtime_environment_variables as $env) { - $environment_variables->push("$env->key=$env->real_value"); + if ($env->is_shared) { + $environment_variables->push("$env->key=$env->real_value"); - if ($env->key === 'REDIS_PASSWORD') { - $redis_password = $env->real_value; + if ($env->key === 'REDIS_PASSWORD') { + $this->database->update(['redis_password' => $env->real_value]); + } + + if ($env->key === 'REDIS_USERNAME') { + $this->database->update(['redis_username' => $env->real_value]); + } + } else { + if ($env->key === 'REDIS_PASSWORD') { + $env->update(['value' => $this->database->redis_password]); + } elseif ($env->key === 'REDIS_USERNAME') { + $env->update(['value' => $this->database->redis_username]); + } + $environment_variables->push("$env->key=$env->real_value"); } - - if ($env->key === 'REDIS_USERNAME') { - $redis_username = $env->real_value; - } - } - - if (is_null($redis_password)) { - $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); - } else { - $this->database->update(['redis_password' => $redis_password]); - } - - if (is_null($redis_username)) { - $environment_variables->push("REDIS_USERNAME={$this->database->redis_username}"); - } else { - $this->database->update(['redis_username' => $redis_username]); } add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables); diff --git a/app/Livewire/Project/Database/Redis/General.php b/app/Livewire/Project/Database/Redis/General.php index b5b459acb..ab9b0756d 100644 --- a/app/Livewire/Project/Database/Redis/General.php +++ b/app/Livewire/Project/Database/Redis/General.php @@ -80,14 +80,12 @@ public function submit() $redis_version = $this->get_redis_version(); - if (version_compare($redis_version, '6.0', '>=')) { - if ($this->database->isDirty('redis_username')) { - $this->database->redis_username = $this->database->redis_username; - } + if (version_compare($redis_version, '6.0', '>=') && $this->database->isDirty('redis_username')) { + $this->updateEnvironmentVariable('REDIS_USERNAME', $this->database->redis_username); } if ($this->database->isDirty('redis_password')) { - $this->database->redis_password = $this->database->redis_password; + $this->updateEnvironmentVariable('REDIS_PASSWORD', $this->database->redis_password); } $this->database->save(); @@ -101,6 +99,7 @@ public function submit() private function get_redis_version() { $image_parts = explode(':', $this->database->image); + return $image_parts[1] ?? '0.0'; } @@ -144,4 +143,23 @@ public function render() { return view('livewire.project.database.redis.general'); } -} \ No newline at end of file + + private function updateEnvironmentVariable($key, $value) + { + $envVar = $this->database->runtime_environment_variables() + ->where('key', $key) + ->first(); + + if ($envVar) { + if (! $envVar->is_shared) { + $envVar->update(['value' => $value]); + } + } else { + $this->database->runtime_environment_variables()->create([ + 'key' => $key, + 'value' => $value, + 'is_shared' => false, + ]); + } + } +} diff --git a/bootstrap/helpers/databases.php b/bootstrap/helpers/databases.php index 950eb67b6..d77327c8f 100644 --- a/bootstrap/helpers/databases.php +++ b/bootstrap/helpers/databases.php @@ -1,5 +1,6 @@ name = generate_database_name('redis'); $database->redis_password = \Illuminate\Support\Str::password(length: 64, symbols: false); + $database->redis_username = 'default'; $database->environment_id = $environment_id; $database->destination_id = $destination->id; $database->destination_type = $destination->getMorphClass(); @@ -57,6 +59,20 @@ function create_standalone_redis($environment_id, $destination_uuid, ?array $oth } $database->save(); + EnvironmentVariable::create([ + 'key' => 'REDIS_PASSWORD', + 'value' => $database->redis_password, + 'standalone_redis_id' => $database->id, + 'is_shared' => false, + ]); + + EnvironmentVariable::create([ + 'key' => 'REDIS_USERNAME', + 'value' => $database->redis_username, + 'standalone_redis_id' => $database->id, + 'is_shared' => false, + ]); + return $database; } From 85c3270dcc4270a6c9616bb68401105493370b45 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:44:17 +0200 Subject: [PATCH 057/120] update helper and disable input if variable is shared --- .../Project/Database/Redis/General.php | 9 +++++++++ app/Models/StandaloneRedis.php | 12 ++++++++---- .../project/database/redis/general.blade.php | 19 +++++++++++++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/app/Livewire/Project/Database/Redis/General.php b/app/Livewire/Project/Database/Redis/General.php index ab9b0756d..20a881523 100644 --- a/app/Livewire/Project/Database/Redis/General.php +++ b/app/Livewire/Project/Database/Redis/General.php @@ -4,6 +4,7 @@ use App\Actions\Database\StartDatabaseProxy; use App\Actions\Database\StopDatabaseProxy; +use App\Models\EnvironmentVariable; use App\Models\Server; use App\Models\StandaloneRedis; use Exception; @@ -144,6 +145,14 @@ public function render() return view('livewire.project.database.redis.general'); } + public function isSharedVariable($name) + { + return EnvironmentVariable::where('key', $name) + ->where('standalone_redis_id', $this->database->id) + ->where('is_shared', true) + ->exists(); + } + private function updateEnvironmentVariable($key, $value) { $envVar = $this->database->runtime_environment_variables() diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index e71eacc45..188982f47 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -21,7 +21,7 @@ class StandaloneRedis extends BaseModel ]; protected $attributes = [ - 'redis_username' => 'redis', + 'redis_username' => 'default', ]; protected static function booted() @@ -220,7 +220,8 @@ protected function internalDbUrl(): Attribute return new Attribute( get: function () { $redis_version = $this->get_redis_version(); - $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ""; + $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ''; + return "redis://{$username_part}{$this->redis_password}@{$this->uuid}:6379/0"; } ); @@ -232,9 +233,11 @@ protected function externalDbUrl(): Attribute get: function () { if ($this->is_public && $this->public_port) { $redis_version = $this->get_redis_version(); - $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ""; + $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ''; + return "redis://{$username_part}{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0"; } + return null; } ); @@ -243,6 +246,7 @@ protected function externalDbUrl(): Attribute private function get_redis_version() { $image_parts = explode(':', $this->image); + return $image_parts[1] ?? '0.0'; } @@ -309,9 +313,9 @@ public function getMetrics(int $mins = 5) return $parsedCollection->toArray(); } } + public function isBackupSolutionAvailable() { return false; } } - diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index c5ab13d94..e61c210b0 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -16,11 +16,22 @@ $redis_version = explode(':', $database->image)[1] ?? '0.0'; @endphp @if (version_compare($redis_version, '6.0', '>=')) - + @endif - + Date: Wed, 16 Oct 2024 14:04:21 +0200 Subject: [PATCH 058/120] fix: encrypt all existing redis passwords --- ...20026_encrypt_existing_redis_passwords.php | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 database/migrations/2024_10_16_120026_encrypt_existing_redis_passwords.php diff --git a/database/migrations/2024_10_16_120026_encrypt_existing_redis_passwords.php b/database/migrations/2024_10_16_120026_encrypt_existing_redis_passwords.php new file mode 100644 index 000000000..3b4f11986 --- /dev/null +++ b/database/migrations/2024_10_16_120026_encrypt_existing_redis_passwords.php @@ -0,0 +1,27 @@ +chunkById(100, function ($redisInstances) { + foreach ($redisInstances as $redis) { + DB::table('standalone_redis') + ->where('id', $redis->id) + ->update(['redis_password' => Crypt::encryptString($redis->redis_password)]); + } + }); + } catch (\Exception $e) { + echo 'Encrypting Redis passwords failed.'; + echo $e->getMessage(); + } + } +} From d52c91b5f8a3da1573dad92d1627114fc9d369c2 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 20:33:59 +0200 Subject: [PATCH 059/120] fix plausible use api health endpoint --- templates/compose/plausible.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/plausible.yaml b/templates/compose/plausible.yaml index d932316d8..c8fcf8d32 100644 --- a/templates/compose/plausible.yaml +++ b/templates/compose/plausible.yaml @@ -30,7 +30,7 @@ services: "--no-verbose", "--tries=1", "--spider", - "http://127.0.0.1:8000/ping", + "http://127.0.0.1:8000/api/health", ] interval: 10s timeout: 5s From a13faadf02dc9cd80ff5850afb21b98f83183747 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 20:41:34 +0200 Subject: [PATCH 060/120] Update plausible.yaml --- templates/compose/plausible.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/compose/plausible.yaml b/templates/compose/plausible.yaml index c8fcf8d32..a37dcaf6e 100644 --- a/templates/compose/plausible.yaml +++ b/templates/compose/plausible.yaml @@ -12,9 +12,9 @@ services: - SERVICE_FQDN_PLAUSIBLE - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@plausible-db:5432/${POSTGRES_DB:-plausible-db} - CLICKHOUSE_DATABASE_URL=http://plausible-events-db:8123/plausible_events_db - - BASE_URL=$SERVICE_FQDN_PLAUSIBLE - - SECRET_KEY_BASE=$SERVICE_BASE64_64_PLAUSIBLE - - TOTP_VAULT_KEY=$SERVICE_REALBASE64_32_TOTP + - BASE_URL=${SERVICE_FQDN_PLAUSIBLE} + - SECRET_KEY_BASE=${SERVICE_BASE64_64_PLAUSIBLE} + - TOTP_VAULT_KEY=${SERVICE_REALBASE64_32_TOTP} depends_on: plausible-db: condition: service_healthy From daf355bbe499b4bb37cde150de1957d10c38a757 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Wed, 16 Oct 2024 16:20:12 -0400 Subject: [PATCH 061/120] Update mindsdb.yaml --- templates/compose/mindsdb.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/templates/compose/mindsdb.yaml b/templates/compose/mindsdb.yaml index 44bae7719..d985bd8c9 100644 --- a/templates/compose/mindsdb.yaml +++ b/templates/compose/mindsdb.yaml @@ -10,6 +10,7 @@ services: restart: always environment: - SERVICE_FQDN_MINDSDB_47334 + - SERVICE_FQDN_API_47335 - MINDSDB_DOCKER_ENV=true - MINDSDB_STORAGE_DIR=/mindsdb/var - FLASK_DEBUG=1 # This will make sure http requests are logged regardless of log level @@ -21,13 +22,11 @@ services: # - LANGFUSE_DEBUG="True" - LANGFUSE_TIMEOUT="10" - LANGFUSE_SAMPLE_RATE="1.0" - ports: - - 47335:47335 - - 47336:47336 + # ports: + # - 47335:47335 + # - 47336:47336 volumes: - - type: bind - source: . - target: /mindsdb + - mindsdb-data:/mindsdb healthcheck: test: ["CMD", "curl", "-f", "http://localhost:47334/api/util/ping"] interval: 30s From 38af81c40bee55102b54e9c957b8f2ff05022aa3 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Wed, 16 Oct 2024 18:28:49 -0400 Subject: [PATCH 062/120] Update mindsdb.yaml --- templates/compose/mindsdb.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/mindsdb.yaml b/templates/compose/mindsdb.yaml index d985bd8c9..230bbbf47 100644 --- a/templates/compose/mindsdb.yaml +++ b/templates/compose/mindsdb.yaml @@ -26,7 +26,7 @@ services: # - 47335:47335 # - 47336:47336 volumes: - - mindsdb-data:/mindsdb + - mindsdb-data:/mindsdb/var healthcheck: test: ["CMD", "curl", "-f", "http://localhost:47334/api/util/ping"] interval: 30s From ce2bc46c28c49cd71051a7acad514b4d73f63b21 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Wed, 16 Oct 2024 18:31:06 -0400 Subject: [PATCH 063/120] Update mindsdb.yaml --- templates/compose/mindsdb.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/mindsdb.yaml b/templates/compose/mindsdb.yaml index 230bbbf47..06e120863 100644 --- a/templates/compose/mindsdb.yaml +++ b/templates/compose/mindsdb.yaml @@ -10,7 +10,7 @@ services: restart: always environment: - SERVICE_FQDN_MINDSDB_47334 - - SERVICE_FQDN_API_47335 + - SERVICE_FQDN_API_47335=/api - MINDSDB_DOCKER_ENV=true - MINDSDB_STORAGE_DIR=/mindsdb/var - FLASK_DEBUG=1 # This will make sure http requests are logged regardless of log level From 55a8f17cb99863b1e723eb980a695e24dff79a11 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Wed, 16 Oct 2024 22:00:42 -0400 Subject: [PATCH 064/120] WORKING! --- .../compose/grafana-with-postgresql.yaml | 62 +++++++++++-------- templates/compose/mindsdb.yaml | 15 +++++ 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/templates/compose/grafana-with-postgresql.yaml b/templates/compose/grafana-with-postgresql.yaml index 25276468e..5656069fb 100644 --- a/templates/compose/grafana-with-postgresql.yaml +++ b/templates/compose/grafana-with-postgresql.yaml @@ -1,39 +1,49 @@ -# documentation: https://grafana.com -# slogan: Grafana is the open source analytics & monitoring solution for every database. -# tags: grafana,analytics,monitoring,dashboard -# logo: svgs/grafana.svg -# port: 3000 + + +# documentation: https://docs.mindsdb.com/what-is-mindsdb +# slogan: MindsDB is the platform for building AI from enterprise data, enabling smarter organizations. +# tags: mysql, postgresdb, machine-learning, ai +# logo: svgs/mindsdb.png +# port: 47334 services: - grafana: - image: grafana/grafana-oss + mindsdb: + image: mindsdb/mindsdb + restart: always + container_name: mindsdb environment: - - SERVICE_FQDN_GRAFANA_3000 - - GF_SERVER_ROOT_URL=${SERVICE_FQDN_GRAFANA} - - GF_SERVER_DOMAIN=${SERVICE_FQDN_GRAFANA} - - GF_SECURITY_ADMIN_PASSWORD=${SERVICE_PASSWORD_GRAFANA} - - GF_DATABASE_TYPE=postgres - - GF_DATABASE_HOST=postgresql - - GF_DATABASE_USER=$SERVICE_USER_POSTGRES - - GF_DATABASE_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - GF_DATABASE_NAME=${POSTGRES_DB:-grafana} + - SERVICE_FQDN_MINDSDB_47334 + - SERVICE_FQDN_API_47335=/api + - MINDSDB_DOCKER_ENV=true + - MINDSDB_STORAGE_DIR=/mindsdb/var + - FLASK_DEBUG=1 # This will make sure http requests are logged regardless of log level + - OPENAI_API_KEY=$OPENAI_API_KEY + - LANGFUSE_HOST=$LANGFUSE_HOST + - LANGFUSE_PUBLIC_KEY=$LANGFUSE_PUBLIC_KEY + - LANGFUSE_SECRET_KEY=$LANGFUSE_SECRET_KEY + - LANGFUSE_RELEASE="local" + # - LANGFUSE_DEBUG="True" + - LANGFUSE_TIMEOUT="10" + - LANGFUSE_SAMPLE_RATE="1.0" + - MINDSDB_DB_CON=postgresql://postgres:postgres@postgresql + # ports: + # - 47335:47335 + # - 47336:47336 volumes: - - grafana-data:/var/lib/grafana + - mindsdb-data:/mindsdb/var healthcheck: - test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/api/health"] - interval: 5s - timeout: 20s - retries: 10 - depends_on: - - postgresql + test: ["CMD", "curl", "-f", "http://localhost:47334/api/util/ping"] + interval: 30s + timeout: 4s + retries: 100 postgresql: image: postgres:16-alpine volumes: - postgresql-data:/var/lib/postgresql/data environment: - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_DB=${POSTGRES_DB:-grafana} + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - POSTGRES_DB=mindsdb healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s diff --git a/templates/compose/mindsdb.yaml b/templates/compose/mindsdb.yaml index 06e120863..3628a14d8 100644 --- a/templates/compose/mindsdb.yaml +++ b/templates/compose/mindsdb.yaml @@ -8,6 +8,7 @@ services: mindsdb: image: mindsdb/mindsdb restart: always + container_name: mindsdb environment: - SERVICE_FQDN_MINDSDB_47334 - SERVICE_FQDN_API_47335=/api @@ -22,6 +23,7 @@ services: # - LANGFUSE_DEBUG="True" - LANGFUSE_TIMEOUT="10" - LANGFUSE_SAMPLE_RATE="1.0" + - MINDSDB_DB_CON='postgresql://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql' # ports: # - 47335:47335 # - 47336:47336 @@ -32,3 +34,16 @@ services: interval: 30s timeout: 4s retries: 100 + postgresql: + image: postgres:16-alpine + volumes: + - postgresql-data:/var/lib/postgresql/data + environment: + - POSTGRES_USER=$SERVICE_USER_POSTGRES + - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - POSTGRES_DB=${POSTGRES_DB:-mindsdb} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 5s + timeout: 20s + retries: 10 From f600c1b37dc93c4e7517716074ce645de37b4d37 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 10:04:38 +0200 Subject: [PATCH 065/120] fix: only enable Sentinel for new servers --- app/Models/ServerSetting.php | 8 ++++++++ ..._14_090416_update_metrics_token_in_server_settings.php | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index f2eba4854..2b9ce0cd0 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -55,6 +55,14 @@ class ServerSetting extends Model 'docker_cleanup_threshold' => 'integer', 'sentinel_token' => 'encrypted', ]; + + protected static function booted() + { + static::creating(function ($setting) { + $setting->is_sentinel_enabled = true; + }); + } + public function server() { return $this->belongsTo(Server::class); diff --git a/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php b/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php index 737dfd5ee..d5c38501f 100644 --- a/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php +++ b/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php @@ -17,7 +17,7 @@ public function up(): void $table->dropColumn('metrics_history_days'); $table->dropColumn('is_server_api_enabled'); - $table->boolean('is_sentinel_enabled')->default(true); + $table->boolean('is_sentinel_enabled')->default(false); $table->text('sentinel_token')->nullable(); $table->integer('sentinel_metrics_refresh_rate_seconds')->default(10); $table->integer('sentinel_metrics_history_days')->default(7); From 55cae39e557ae2fd5e5a57b8bffcd4872d12a61c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 10:04:49 +0200 Subject: [PATCH 066/120] dev: loggy --- bootstrap/helpers/shared.php | 15 +++++++ composer.json | 1 + composer.lock | 79 +++++++++++++++++++++++++++++++++++- storage/pail/.gitignore | 2 + 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 storage/pail/.gitignore diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index f70c705c7..b619d1dd1 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -4010,3 +4010,18 @@ function loadConfigFromGit(string $repository, string $branch, string $base_dire // continue } } + +function loggy($message = null, array $context = []) +{ + if (!isDev()) { + return; + } + if (function_exists('ray') && config('app.debug')) { + ray($message, $context); + } + if (is_null($message)) { + return app('log'); + } + + return app('log')->debug($message, $context); +} diff --git a/composer.json b/composer.json index fbd77d0cf..b17c3bf4e 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "laravel/fortify": "^v1.16.0", "laravel/framework": "^v11", "laravel/horizon": "^5.29.1", + "laravel/pail": "^1.1", "laravel/prompts": "^0.1.6", "laravel/sanctum": "^v4.0", "laravel/socialite": "^v5.14.0", diff --git a/composer.lock b/composer.lock index 0b8da82d0..981e723d4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c47adf3684eb727e22503937435c0914", + "content-hash": "943975ec232403b96a40d215253492d8", "packages": [ { "name": "amphp/amp", @@ -3144,6 +3144,83 @@ }, "time": "2024-10-08T18:23:02+00:00" }, + { + "name": "laravel/pail", + "version": "v1.1.5", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "b33ad8321416fe86efed7bf398f3306c47b4871b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/b33ad8321416fe86efed7bf398f3306c47b4871b", + "reference": "b33ad8321416fe86efed7bf398f3306c47b4871b", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/console": "^10.24|^11.0", + "illuminate/contracts": "^10.24|^11.0", + "illuminate/log": "^10.24|^11.0", + "illuminate/process": "^10.24|^11.0", + "illuminate/support": "^10.24|^11.0", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "laravel/pint": "^1.13", + "orchestra/testbench": "^8.12|^9.0", + "pestphp/pest": "^2.20", + "pestphp/pest-plugin-type-coverage": "^2.3", + "phpstan/phpstan": "^1.10", + "symfony/var-dumper": "^6.3|^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Pail\\PailServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Pail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Easily delve into your Laravel application's log files directly from the command line.", + "homepage": "https://github.com/laravel/pail", + "keywords": [ + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2024-10-15T20:06:24+00:00" + }, { "name": "laravel/prompts", "version": "v0.1.25", diff --git a/storage/pail/.gitignore b/storage/pail/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/storage/pail/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From 4c95647b9694f30cb898459c5ea1589620ff3cda Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 11:21:43 +0200 Subject: [PATCH 067/120] feat: cleanup sentinel on server deletion fix: Sentinel should not be enabled on build servers --- app/Actions/Server/RemoveServer.php | 17 +++++++++++++++++ app/Actions/Server/StartSentinel.php | 2 +- app/Actions/Server/StopSentinel.php | 2 +- app/Http/Controllers/Api/ServersController.php | 3 ++- app/Jobs/PushServerUpdateJob.php | 2 +- app/Livewire/Server/Delete.php | 3 ++- app/Livewire/Server/Form.php | 2 +- app/Models/Server.php | 4 ++-- 8 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 app/Actions/Server/RemoveServer.php diff --git a/app/Actions/Server/RemoveServer.php b/app/Actions/Server/RemoveServer.php new file mode 100644 index 000000000..8e92a51ae --- /dev/null +++ b/app/Actions/Server/RemoveServer.php @@ -0,0 +1,17 @@ +delete(); + } +} diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php index a1d36a041..3fbe4b3a3 100644 --- a/app/Actions/Server/StartSentinel.php +++ b/app/Actions/Server/StartSentinel.php @@ -52,6 +52,6 @@ public function handle(Server $server, $version = 'next', bool $restart = false) $server->settings->is_sentinel_enabled = true; $server->settings->save(); - $server->sentinelUpdateAt(); + $server->sentinelHeartbeat(); } } diff --git a/app/Actions/Server/StopSentinel.php b/app/Actions/Server/StopSentinel.php index 68972f0f2..edb6843af 100644 --- a/app/Actions/Server/StopSentinel.php +++ b/app/Actions/Server/StopSentinel.php @@ -13,6 +13,6 @@ class StopSentinel public function handle(Server $server) { instant_remote_process(['docker rm -f coolify-sentinel'], $server, false); - $server->sentinelUpdateAt(isReset: true); + $server->sentinelHeartbeat(isReset: true); } } diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index 6d512e578..6d47769a9 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api; +use App\Actions\Server\RemoveServer; use App\Actions\Server\ValidateServer; use App\Enums\ProxyStatus; use App\Enums\ProxyTypes; @@ -725,7 +726,7 @@ public function delete_server(Request $request) if ($server->definedResources()->count() > 0) { return response()->json(['message' => 'Server has resources, so you need to delete them before.'], 400); } - $server->delete(); + RemoveServer::dispatch($server); return response()->json(['message' => 'Server deleted.']); } diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 3ef4b944a..cdc3788e5 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -96,7 +96,7 @@ public function handle() $this->serverStatus(); - $this->server->sentinelUpdateAt(); + $this->server->sentinelHeartbeat(); $this->containers = collect(data_get($data, 'containers')); if ($this->containers->isEmpty()) { diff --git a/app/Livewire/Server/Delete.php b/app/Livewire/Server/Delete.php index ed2345b2a..2af56cb1c 100644 --- a/app/Livewire/Server/Delete.php +++ b/app/Livewire/Server/Delete.php @@ -2,6 +2,7 @@ namespace App\Livewire\Server; +use App\Actions\Server\RemoveServer; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; @@ -27,7 +28,7 @@ public function delete($password) return; } - $this->server->delete(); + RemoveServer::run($this->server); return redirect()->route('server.index'); } catch (\Throwable $e) { diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index dadf9033d..40bff3873 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -157,7 +157,7 @@ public function updatedServerSettingsIsSentinelEnabled($value){ StopSentinel::dispatch($this->server); $this->server->settings->is_metrics_enabled = false; $this->server->settings->save(); - $this->server->sentinelUpdateAt(isReset: true); + $this->server->sentinelHeartbeat(isReset: true); } else { StartSentinel::run($this->server); } diff --git a/app/Models/Server.php b/app/Models/Server.php index 3639d9263..cb5aa4524 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -556,7 +556,7 @@ public function generateSentinelToken() return $encrypted; } - public function sentinelUpdateAt(bool $isReset = false) + public function sentinelHeartbeat(bool $isReset = false) { $this->sentinel_updated_at = $isReset ? now()->subMinutes(6000) : now(); $this->save(); @@ -568,7 +568,7 @@ public function isSentinelLive() public function isSentinelEnabled() { - return $this->isMetricsEnabled() || $this->isServerApiEnabled(); + return $this->isMetricsEnabled() || $this->isServerApiEnabled() || !$this->isBuildServer(); } public function isMetricsEnabled() From 2cb424ed7b29f11d9ebefcd78dd491c86e639f40 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:07:35 +0200 Subject: [PATCH 068/120] setting to disable tow step confirmation --- app/Livewire/Settings/Index.php | 9 +- ...on_settings_to_instance_settings_table.php | 22 +++ .../views/livewire/settings/index.blade.php | 175 +++++++++--------- 3 files changed, 114 insertions(+), 92 deletions(-) create mode 100644 database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php index 754f0929b..7d3fe62a7 100644 --- a/app/Livewire/Settings/Index.php +++ b/app/Livewire/Settings/Index.php @@ -25,6 +25,10 @@ class Index extends Component public string $update_check_frequency; + public $timezones; + + public bool $disable_two_step_confirmation; + protected string $dynamic_config_path = '/data/coolify/proxy/dynamic'; protected Server $server; @@ -55,8 +59,6 @@ class Index extends Component 'update_check_frequency' => 'Update Check Frequency', ]; - public $timezones; - public function mount() { if (isInstanceAdmin()) { @@ -69,6 +71,7 @@ public function mount() $this->auto_update_frequency = $this->settings->auto_update_frequency; $this->update_check_frequency = $this->settings->update_check_frequency; $this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray(); + $this->disable_two_step_confirmation = $this->settings->disable_two_step_confirmation; } else { return redirect()->route('dashboard'); } @@ -83,6 +86,7 @@ public function instantSave() $this->settings->is_api_enabled = $this->is_api_enabled; $this->settings->auto_update_frequency = $this->auto_update_frequency; $this->settings->update_check_frequency = $this->update_check_frequency; + $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation; $this->settings->save(); $this->dispatch('success', 'Settings updated!'); } @@ -148,6 +152,7 @@ public function submit() $this->settings->is_api_enabled = $this->is_api_enabled; $this->settings->auto_update_frequency = $this->auto_update_frequency; $this->settings->update_check_frequency = $this->update_check_frequency; + $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation; $this->settings->save(); $this->server->setupDynamicProxyConfiguration(); if (! $error_show) { diff --git a/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php b/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php new file mode 100644 index 000000000..7040daf44 --- /dev/null +++ b/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php @@ -0,0 +1,22 @@ +boolean('disable_two_step_confirmation')->default(false); + }); + } + + public function down() + { + Schema::table('instance_settings', function (Blueprint $table) { + $table->dropColumn('disable_two_step_confirmation'); + }); + } +}; diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php index f9293e7d7..db2a06995 100644 --- a/resources/views/livewire/settings/index.blade.php +++ b/resources/views/livewire/settings/index.blade.php @@ -1,26 +1,24 @@
Settings | Coolify - - -
-
-

Configuration

- - Save - -
-
General configuration for your Coolify instance.
+ + + +
+

Configuration

+ + Save + +
+
General configuration for your Coolify instance.
-
-

Instance Settings

-
-
- - -
+

Instance Settings

+
+
+ + +
-
- - -
-
-
- - - - +
+ +
-
- +
+
+ + + + +
+
+ +
+ +

DNS Validation

+
+ +
+
-

DNS Validation

-
- -
- -
- - {{--
+ {{--
--}} -
-

API

-
- -
- +
+

API

+
+ +
+ -

Advanced

-
- - -
-
Update
-
- @if (!is_null(env('AUTOUPDATE', null))) +
Update
+
+ @if (!is_null(env('AUTOUPDATE', null)))
- +
- @else + @else - @endif -
-
-
- - Check Manually + @endif +
+
+
+ + Check Manually +
+ + @if (is_null(env('AUTOUPDATE', null)) && $is_auto_update_enabled) + + @endif
- @if (is_null(env('AUTOUPDATE', null)) && $is_auto_update_enabled) - - @endif -
- +

Advanced

+
+ + +
+ +
Confirmation Settings
+
+ +
+
+

Warning!

+

Disabling two-step confirmation reduces security (as anyone can easily delete anything) and increases the risk of accidental actions. This is not recommended for production servers.

+
+ +
+
+
From b67f4d197579eafe8950ac9891056880fcf06f4b Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:07:48 +0200 Subject: [PATCH 069/120] disable tow step confirmation --- .../components/modal-confirmation.blade.php | 190 ++++++++++-------- 1 file changed, 103 insertions(+), 87 deletions(-) diff --git a/resources/views/components/modal-confirmation.blade.php b/resources/views/components/modal-confirmation.blade.php index ef6c477f2..a0175c1a1 100644 --- a/resources/views/components/modal-confirmation.blade.php +++ b/resources/views/components/modal-confirmation.blade.php @@ -22,18 +22,23 @@ 'dispatchEventMessage' => '', ]) +@php + $settings = instanceSettings(); + $disableTwoStepConfirmation = $settings->disable_two_step_confirmation ?? false; +@endphp +
@endforeach - @if ($confirmWithText) -
-

Confirm Actions

-

{{ $confirmationLabel }}

-
- - -
+ @if (!$disableTwoStepConfirmation) + @if ($confirmWithText) +
+

Confirm Actions

+

{{ $confirmationLabel }}

+
+ + +
- - -
+ + +
+ @endif @endif
-
- + @endif
@@ -304,41 +314,47 @@ class="w-24 dark:bg-coolgray-200 dark:hover:bg-coolgray-300"> - + submitForm().then((result) => { + if (result === true) { + modalOpen = false; + resetModal(); + } else { + passwordError = result; + } + }); + "> + + + + @endif
From 8284cdfb02e7fa35c1597345cd98fa6bc3024c18 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:23:13 +0200 Subject: [PATCH 070/120] add password confirmation to disable two step confirmation --- app/Livewire/Settings/Index.php | 9 ++++++++- .../views/livewire/settings/index.blade.php | 16 +++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php index 7d3fe62a7..0636e592e 100644 --- a/app/Livewire/Settings/Index.php +++ b/app/Livewire/Settings/Index.php @@ -152,7 +152,6 @@ public function submit() $this->settings->is_api_enabled = $this->is_api_enabled; $this->settings->auto_update_frequency = $this->auto_update_frequency; $this->settings->update_check_frequency = $this->update_check_frequency; - $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation; $this->settings->save(); $this->server->setupDynamicProxyConfiguration(); if (! $error_show) { @@ -186,4 +185,12 @@ public function render() { return view('livewire.settings.index'); } + + public function toggleTwoStepConfirmation() + { + $this->settings->disable_two_step_confirmation = true; + $this->settings->save(); + $this->disable_two_step_confirmation = true; + $this->dispatch('success', 'Two step confirmation has been disabled.'); + } } diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php index db2a06995..b8874cbac 100644 --- a/resources/views/livewire/settings/index.blade.php +++ b/resources/views/livewire/settings/index.blade.php @@ -111,7 +111,21 @@

Warning!

Disabling two-step confirmation reduces security (as anyone can easily delete anything) and increases the risk of accidental actions. This is not recommended for production servers.

- + @if($disable_two_step_confirmation) + + @else + + @endif
From e1e00af35a66c6d972bcd950fc94fb35e297f61d Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:28:07 +0200 Subject: [PATCH 071/120] disable tow step confirmation by default on dev --- database/seeders/DatabaseSeeder.php | 1 + .../DisableTwoStepConfirmationSeeder.php | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 database/seeders/DisableTwoStepConfirmationSeeder.php diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index be5083108..1339e7889 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -26,6 +26,7 @@ public function run(): void S3StorageSeeder::class, StandalonePostgresqlSeeder::class, OauthSettingSeeder::class, + DisableTwoStepConfirmationSeeder::class, ]); } } diff --git a/database/seeders/DisableTwoStepConfirmationSeeder.php b/database/seeders/DisableTwoStepConfirmationSeeder.php new file mode 100644 index 000000000..c43bf1b01 --- /dev/null +++ b/database/seeders/DisableTwoStepConfirmationSeeder.php @@ -0,0 +1,20 @@ +updateOrInsert( + [], + ['disable_two_step_confirmation' => true] + ); + } +} From 83c7e1b78b50eacd890bd2282758862b4f3e5cde Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:36:18 +0200 Subject: [PATCH 072/120] fix typos --- resources/views/livewire/settings/index.blade.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php index b8874cbac..0fb111d91 100644 --- a/resources/views/livewire/settings/index.blade.php +++ b/resources/views/livewire/settings/index.blade.php @@ -109,7 +109,7 @@

Warning!

-

Disabling two-step confirmation reduces security (as anyone can easily delete anything) and increases the risk of accidental actions. This is not recommended for production servers.

+

Disabling two step confirmation reduces security (as anyone can easily delete anything) and increases the risk of accidental actions. This is not recommended for production servers.

@if($disable_two_step_confirmation) @@ -119,10 +119,10 @@ buttonTitle="Disable Two Step Confirmation" isErrorButton submitAction="toggleTwoStepConfirmation" - :actions="['Tow Step confimation will be disabled globally.', 'Disabling two-step confirmation reduces security (as anyone can easily delete anything).', 'The risk of accidental actions will increase.']" + :actions="['Tow Step confimation will be disabled globally.', 'Disabling two step confirmation reduces security (as anyone can easily delete anything).', 'The risk of accidental actions will increase.']" confirmationText="DISABLE TWO STEP CONFIRMATION" confirmationLabel="Please type the confirmation text to disable two step confirmation." - shortConfirmationLabel="Type Confirmation Text" + shortConfirmationLabel="Confirmation text" step3ButtonText="Disable Two Step Confirmation" /> @endif From 8b114f555874130ecd0e7b1850e7bce7574ed7d3 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:05:58 +0200 Subject: [PATCH 073/120] fix button text kind of --- resources/views/components/modal-confirmation.blade.php | 2 +- resources/views/livewire/server/delete.blade.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/components/modal-confirmation.blade.php b/resources/views/components/modal-confirmation.blade.php index a0175c1a1..4dc4e83e7 100644 --- a/resources/views/components/modal-confirmation.blade.php +++ b/resources/views/components/modal-confirmation.blade.php @@ -331,7 +331,7 @@ class="w-auto" } " > - + diff --git a/resources/views/livewire/server/delete.blade.php b/resources/views/livewire/server/delete.blade.php index 360e1e0c6..86053c0d4 100644 --- a/resources/views/livewire/server/delete.blade.php +++ b/resources/views/livewire/server/delete.blade.php @@ -16,7 +16,7 @@ + shortConfirmationLabel="Server Name" step3ButtonText="Permanently Delete" /> @endif @endif
From c087f22056ba5fa21c3d1b9e179f8024db4462aa Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:49:45 +0200 Subject: [PATCH 074/120] fix mindsdb --- templates/compose/mindsdb.yaml | 51 ++++++++++++++++---------------- templates/service-templates.json | 32 ++++++++++++++------ 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/templates/compose/mindsdb.yaml b/templates/compose/mindsdb.yaml index 3628a14d8..72dc5a2d0 100644 --- a/templates/compose/mindsdb.yaml +++ b/templates/compose/mindsdb.yaml @@ -1,49 +1,48 @@ # documentation: https://docs.mindsdb.com/what-is-mindsdb # slogan: MindsDB is the platform for building AI from enterprise data, enabling smarter organizations. # tags: mysql, postgresdb, machine-learning, ai -# logo: svgs/mindsdb.png +# logo: svgs/mindsdb.svg # port: 47334 services: mindsdb: - image: mindsdb/mindsdb - restart: always - container_name: mindsdb + image: mindsdb/mindsdb:latest environment: - SERVICE_FQDN_MINDSDB_47334 - SERVICE_FQDN_API_47335=/api - MINDSDB_DOCKER_ENV=true - MINDSDB_STORAGE_DIR=/mindsdb/var - - FLASK_DEBUG=1 # This will make sure http requests are logged regardless of log level - - OPENAI_API_KEY=$OPENAI_API_KEY - - LANGFUSE_HOST=$LANGFUSE_HOST - - LANGFUSE_PUBLIC_KEY=$LANGFUSE_PUBLIC_KEY - - LANGFUSE_SECRET_KEY=$LANGFUSE_SECRET_KEY - - LANGFUSE_RELEASE="local" - # - LANGFUSE_DEBUG="True" - - LANGFUSE_TIMEOUT="10" - - LANGFUSE_SAMPLE_RATE="1.0" - - MINDSDB_DB_CON='postgresql://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql' - # ports: - # - 47335:47335 - # - 47336:47336 + - FLASK_DEBUG=${FLASK_DEBUG:-1} # This will make sure http requests are logged regardless of log level + - OPENAI_API_KEY=${OPENAI_API_KEY} + - LANGFUSE_HOST=${LANGFUSE_HOST} + - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY} + - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY} + - LANGFUSE_RELEASE=${LANGFUSE_RELEASE:-local} + - LANGFUSE_DEBUG=${LANGFUSE_DEBUG:-False} + - LANGFUSE_TIMEOUT=${LANGFUSE_TIMEOUT:-10} + - LANGFUSE_SAMPLE_RATE=${LANGFUSE_SAMPLE_RATE:-1.0} + - MINDSDB_DB_CON=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgresql/${POSTGRES_DB:-mindsdb-db} volumes: - mindsdb-data:/mindsdb/var + depends_on: + postgresql: + condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:47334/api/util/ping"] interval: 30s - timeout: 4s - retries: 100 + timeout: 5s + retries: 15 + postgresql: image: postgres:16-alpine volumes: - - postgresql-data:/var/lib/postgresql/data + - mindsdb-postgresql-data:/var/lib/postgresql/data environment: - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_DB=${POSTGRES_DB:-mindsdb} + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_DB=${POSTGRES_DB:-mindsdb-db} healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] - interval: 5s - timeout: 20s - retries: 10 + interval: 10s + timeout: 5s + retries: 15 diff --git a/templates/service-templates.json b/templates/service-templates.json index 7ebdfe604..db789b421 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -999,18 +999,18 @@ "port": "8080" }, "grafana-with-postgresql": { - "documentation": "https://grafana.com?utm_source=coolify.io", - "slogan": "Grafana is the open source analytics & monitoring solution for every database.", - "compose": "c2VydmljZXM6CiAgZ3JhZmFuYToKICAgIGltYWdlOiBncmFmYW5hL2dyYWZhbmEtb3NzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fR1JBRkFOQV8zMDAwCiAgICAgIC0gJ0dGX1NFUlZFUl9ST09UX1VSTD0ke1NFUlZJQ0VfRlFETl9HUkFGQU5BfScKICAgICAgLSAnR0ZfU0VSVkVSX0RPTUFJTj0ke1NFUlZJQ0VfRlFETl9HUkFGQU5BfScKICAgICAgLSAnR0ZfU0VDVVJJVFlfQURNSU5fUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX0dSQUZBTkF9JwogICAgICAtIEdGX0RBVEFCQVNFX1RZUEU9cG9zdGdyZXMKICAgICAgLSBHRl9EQVRBQkFTRV9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBHRl9EQVRBQkFTRV9VU0VSPSRTRVJWSUNFX1VTRVJfUE9TVEdSRVMKICAgICAgLSBHRl9EQVRBQkFTRV9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFUwogICAgICAtICdHRl9EQVRBQkFTRV9OQU1FPSR7UE9TVEdSRVNfREI6LWdyYWZhbmF9JwogICAgdm9sdW1lczoKICAgICAgLSAnZ3JhZmFuYS1kYXRhOi92YXIvbGliL2dyYWZhbmEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMC9hcGkvaGVhbHRoJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICBkZXBlbmRzX29uOgogICAgICAtIHBvc3RncmVzcWwKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotZ3JhZmFuYX0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==", + "documentation": "https://docs.mindsdb.com/what-is-mindsdb?utm_source=coolify.io", + "slogan": "MindsDB is the platform for building AI from enterprise data, enabling smarter organizations.", + "compose": "c2VydmljZXM6CiAgbWluZHNkYjoKICAgIGltYWdlOiBtaW5kc2RiL21pbmRzZGIKICAgIHJlc3RhcnQ6IGFsd2F5cwogICAgY29udGFpbmVyX25hbWU6IG1pbmRzZGIKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NSU5EU0RCXzQ3MzM0CiAgICAgIC0gU0VSVklDRV9GUUROX0FQSV80NzMzNT0vYXBpCiAgICAgIC0gTUlORFNEQl9ET0NLRVJfRU5WPXRydWUKICAgICAgLSBNSU5EU0RCX1NUT1JBR0VfRElSPS9taW5kc2RiL3ZhcgogICAgICAtIEZMQVNLX0RFQlVHPTEKICAgICAgLSBPUEVOQUlfQVBJX0tFWT0kT1BFTkFJX0FQSV9LRVkKICAgICAgLSBMQU5HRlVTRV9IT1NUPSRMQU5HRlVTRV9IT1NUCiAgICAgIC0gTEFOR0ZVU0VfUFVCTElDX0tFWT0kTEFOR0ZVU0VfUFVCTElDX0tFWQogICAgICAtIExBTkdGVVNFX1NFQ1JFVF9LRVk9JExBTkdGVVNFX1NFQ1JFVF9LRVkKICAgICAgLSAnTEFOR0ZVU0VfUkVMRUFTRT0ibG9jYWwiJwogICAgICAtICdMQU5HRlVTRV9USU1FT1VUPSIxMCInCiAgICAgIC0gJ0xBTkdGVVNFX1NBTVBMRV9SQVRFPSIxLjAiJwogICAgICAtICdNSU5EU0RCX0RCX0NPTj1wb3N0Z3Jlc3FsOi8vcG9zdGdyZXM6cG9zdGdyZXNAcG9zdGdyZXNxbCcKICAgIHZvbHVtZXM6CiAgICAgIC0gJ21pbmRzZGItZGF0YTovbWluZHNkYi92YXInCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6NDczMzQvYXBpL3V0aWwvcGluZycKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiA0cwogICAgICByZXRyaWVzOiAxMDAKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPXBvc3RncmVzCiAgICAgIC0gUE9TVEdSRVNfREI9bWluZHNkYgogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=", "tags": [ - "grafana", - "analytics", - "monitoring", - "dashboard" + "mysql", + "postgresdb", + "machine-learning", + "ai" ], - "logo": "svgs/grafana.svg", + "logo": "svgs/mindsdb.png", "minversion": "0.0.0", - "port": "3000" + "port": "47334" }, "grafana": { "documentation": "https://grafana.com?utm_source=coolify.io", @@ -1538,6 +1538,20 @@ "minversion": "0.0.0", "port": "8081" }, + "mindsdb": { + "documentation": "https://docs.mindsdb.com/what-is-mindsdb?utm_source=coolify.io", + "slogan": "MindsDB is the platform for building AI from enterprise data, enabling smarter organizations.", + "compose": "c2VydmljZXM6CiAgbWluZHNkYjoKICAgIGltYWdlOiAnbWluZHNkYi9taW5kc2RiOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NSU5EU0RCXzQ3MzM0CiAgICAgIC0gU0VSVklDRV9GUUROX0FQSV80NzMzNT0vYXBpCiAgICAgIC0gTUlORFNEQl9ET0NLRVJfRU5WPXRydWUKICAgICAgLSBNSU5EU0RCX1NUT1JBR0VfRElSPS9taW5kc2RiL3ZhcgogICAgICAtICdGTEFTS19ERUJVRz0ke0ZMQVNLX0RFQlVHOi0xfScKICAgICAgLSAnT1BFTkFJX0FQSV9LRVk9JHtPUEVOQUlfQVBJX0tFWX0nCiAgICAgIC0gJ0xBTkdGVVNFX0hPU1Q9JHtMQU5HRlVTRV9IT1NUfScKICAgICAgLSAnTEFOR0ZVU0VfUFVCTElDX0tFWT0ke0xBTkdGVVNFX1BVQkxJQ19LRVl9JwogICAgICAtICdMQU5HRlVTRV9TRUNSRVRfS0VZPSR7TEFOR0ZVU0VfU0VDUkVUX0tFWX0nCiAgICAgIC0gJ0xBTkdGVVNFX1JFTEVBU0U9JHtMQU5HRlVTRV9SRUxFQVNFOi1sb2NhbH0nCiAgICAgIC0gJ0xBTkdGVVNFX0RFQlVHPSR7TEFOR0ZVU0VfREVCVUc6LUZhbHNlfScKICAgICAgLSAnTEFOR0ZVU0VfVElNRU9VVD0ke0xBTkdGVVNFX1RJTUVPVVQ6LTEwfScKICAgICAgLSAnTEFOR0ZVU0VfU0FNUExFX1JBVEU9JHtMQU5HRlVTRV9TQU1QTEVfUkFURTotMS4wfScKICAgICAgLSAnTUlORFNEQl9EQl9DT049cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzcWwvJHtQT1NUR1JFU19EQjotbWluZHNkYi1kYn0nCiAgICB2b2x1bWVzOgogICAgICAtICdtaW5kc2RiLWRhdGE6L21pbmRzZGIvdmFyJwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjQ3MzM0L2FwaS91dGlsL3BpbmcnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMTUKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdtaW5kc2RiLXBvc3RncmVzcWwtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LW1pbmRzZGItZGJ9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxNQo=", + "tags": [ + "mysql", + "postgresdb", + "machine-learning", + "ai" + ], + "logo": "svgs/mindsdb.svg", + "minversion": "0.0.0", + "port": "47334" + }, "minecraft": { "documentation": "https://github.com/itzg/docker-minecraft-server?utm_source=coolify.io", "slogan": "Minecraft Server that will automatically download selected version at startup.", From 1684cf103ad94fb1aa35b784077367c02d62f9eb Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 14:16:18 +0200 Subject: [PATCH 075/120] fix windmill --- templates/compose/windmill.yaml | 42 +++++++++++++++++--------------- templates/service-templates.json | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/templates/compose/windmill.yaml b/templates/compose/windmill.yaml index 1326870c2..1ce3a4652 100644 --- a/templates/compose/windmill.yaml +++ b/templates/compose/windmill.yaml @@ -11,10 +11,11 @@ services: volumes: - db-data:/var/lib/postgresql/data environment: - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_DB=${POSTGRES_DB:-windmill} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_DB=${POSTGRES_DB:-windmill-db} healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres"] + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 5 @@ -23,9 +24,9 @@ services: image: ghcr.io/windmill-labs/windmill:main environment: - SERVICE_FQDN_WINDMILL_8000 - - DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill - - MODE=${MODE:-server} - - BASE_URL=$SERVICE_FQDN_WINDMILL + - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@db/${POSTGRES_DB:-windmill-db} + - MODE=server + - BASE_URL=${SERVICE_FQDN_WINDMILL} depends_on: db: condition: service_healthy @@ -40,9 +41,9 @@ services: windmill-worker-1: image: ghcr.io/windmill-labs/windmill:main environment: - - DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill - - MODE=${MODE:-worker} - - WORKER_GROUP=${WORKER_GROUP:-default} + - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@db/${POSTGRES_DB:-windmill-db} + - MODE=worker + - WORKER_GROUP=default depends_on: db: condition: service_healthy @@ -59,9 +60,9 @@ services: windmill-worker-2: image: ghcr.io/windmill-labs/windmill:main environment: - - DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill - - MODE=${MODE:-worker} - - WORKER_GROUP=${WORKER_GROUP:-default} + - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@db/${POSTGRES_DB:-windmill-db} + - MODE=worker + - WORKER_GROUP=default depends_on: db: condition: service_healthy @@ -78,9 +79,9 @@ services: windmill-worker-3: image: ghcr.io/windmill-labs/windmill:main environment: - - DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill - - MODE=${MODE:-worker} - - WORKER_GROUP=${WORKER_GROUP:-default} + - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@db/${POSTGRES_DB:-windmill-db} + - MODE=worker + - WORKER_GROUP=default depends_on: db: condition: service_healthy @@ -97,11 +98,11 @@ services: windmill-worker-native: image: ghcr.io/windmill-labs/windmill:main environment: - - DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill - - MODE=${MODE:-worker} - - WORKER_GROUP=${WORKER_GROUP:-native} - - NUM_WORKERS=${NUM_WORKERS:-8} - - SLEEP_QUEUE=${SLEEP_QUEUE:-200} + - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@db/${POSTGRES_DB:-windmill-db} + - MODE=worker + - WORKER_GROUP=native + - NUM_WORKERS=8 + - SLEEP_QUEUE=200 depends_on: db: condition: service_healthy @@ -122,3 +123,4 @@ services: interval: 30s timeout: 10s retries: 3 + start_period: 20s \ No newline at end of file diff --git a/templates/service-templates.json b/templates/service-templates.json index db789b421..56466eb58 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -2653,7 +2653,7 @@ "windmill": { "documentation": "https://www.windmill.dev/docs/?utm_source=coolify.io", "slogan": "Windmill is a developer platform to build production-grade multi-steps automations and internal apps.", - "compose": "c2VydmljZXM6CiAgZGI6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgc2htX3NpemU6IDFnCiAgICB2b2x1bWVzOgogICAgICAtICdkYi1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXdpbmRtaWxsfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSBwb3N0Z3JlcycKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgd2luZG1pbGwtc2VydmVyOgogICAgaW1hZ2U6ICdnaGNyLmlvL3dpbmRtaWxsLWxhYnMvd2luZG1pbGw6bWFpbicKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9XSU5ETUlMTF84MDAwCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovL3Bvc3RncmVzOiRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTQGRiL3dpbmRtaWxsJwogICAgICAtICdNT0RFPSR7TU9ERTotc2VydmVyfScKICAgICAgLSBCQVNFX1VSTD0kU0VSVklDRV9GUUROX1dJTkRNSUxMCiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwMDAvaGVhbHRoJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLTE6CiAgICBpbWFnZTogJ2doY3IuaW8vd2luZG1pbGwtbGFicy93aW5kbWlsbDptYWluJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovL3Bvc3RncmVzOiRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTQGRiL3dpbmRtaWxsJwogICAgICAtICdNT0RFPSR7TU9ERTotd29ya2VyfScKICAgICAgLSAnV09SS0VSX0dST1VQPSR7V09SS0VSX0dST1VQOi1kZWZhdWx0fScKICAgIGRlcGVuZHNfb246CiAgICAgIGRiOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICB2b2x1bWVzOgogICAgICAtICcvdmFyL3J1bi9kb2NrZXIuc29jazovdmFyL3J1bi9kb2NrZXIuc29jaycKICAgICAgLSAnd29ya2VyLWRlcGVuZGVuY3ktY2FjaGU6L3RtcC93aW5kbWlsbC9jYWNoZScKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdleGl0IDAnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICB3aW5kbWlsbC13b3JrZXItMjoKICAgIGltYWdlOiAnZ2hjci5pby93aW5kbWlsbC1sYWJzL3dpbmRtaWxsOm1haW4nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vcG9zdGdyZXM6JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNAZGIvd2luZG1pbGwnCiAgICAgIC0gJ01PREU9JHtNT0RFOi13b3JrZXJ9JwogICAgICAtICdXT1JLRVJfR1JPVVA9JHtXT1JLRVJfR1JPVVA6LWRlZmF1bHR9JwogICAgZGVwZW5kc19vbjoKICAgICAgZGI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIHZvbHVtZXM6CiAgICAgIC0gJy92YXIvcnVuL2RvY2tlci5zb2NrOi92YXIvcnVuL2RvY2tlci5zb2NrJwogICAgICAtICd3b3JrZXItZGVwZW5kZW5jeS1jYWNoZTovdG1wL3dpbmRtaWxsL2NhY2hlJwogICAgICAtICd3b3JrZXItbG9nczovdG1wL3dpbmRtaWxsL2xvZ3MnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2V4aXQgMCcKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwogIHdpbmRtaWxsLXdvcmtlci0zOgogICAgaW1hZ2U6ICdnaGNyLmlvL3dpbmRtaWxsLWxhYnMvd2luZG1pbGw6bWFpbicKICAgIGVudmlyb25tZW50OgogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXM6Ly9wb3N0Z3JlczokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0BkYi93aW5kbWlsbCcKICAgICAgLSAnTU9ERT0ke01PREU6LXdvcmtlcn0nCiAgICAgIC0gJ1dPUktFUl9HUk9VUD0ke1dPUktFUl9HUk9VUDotZGVmYXVsdH0nCiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnL3Zhci9ydW4vZG9ja2VyLnNvY2s6L3Zhci9ydW4vZG9ja2VyLnNvY2snCiAgICAgIC0gJ3dvcmtlci1kZXBlbmRlbmN5LWNhY2hlOi90bXAvd2luZG1pbGwvY2FjaGUnCiAgICAgIC0gJ3dvcmtlci1sb2dzOi90bXAvd2luZG1pbGwvbG9ncycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLW5hdGl2ZToKICAgIGltYWdlOiAnZ2hjci5pby93aW5kbWlsbC1sYWJzL3dpbmRtaWxsOm1haW4nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vcG9zdGdyZXM6JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNAZGIvd2luZG1pbGwnCiAgICAgIC0gJ01PREU9JHtNT0RFOi13b3JrZXJ9JwogICAgICAtICdXT1JLRVJfR1JPVVA9JHtXT1JLRVJfR1JPVVA6LW5hdGl2ZX0nCiAgICAgIC0gJ05VTV9XT1JLRVJTPSR7TlVNX1dPUktFUlM6LTh9JwogICAgICAtICdTTEVFUF9RVUVVRT0ke1NMRUVQX1FVRVVFOi0yMDB9JwogICAgZGVwZW5kc19vbjoKICAgICAgZGI6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3dvcmtlci1sb2dzOi90bXAvd2luZG1pbGwvbG9ncycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgbHNwOgogICAgaW1hZ2U6ICdnaGNyLmlvL3dpbmRtaWxsLWxhYnMvd2luZG1pbGwtbHNwOmxhdGVzdCcKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2xzcC1jYWNoZTovcm9vdC8uY2FjaGUnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2V4aXQgMCcKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwo=", + "compose": "c2VydmljZXM6CiAgZGI6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgc2htX3NpemU6IDFnCiAgICB2b2x1bWVzOgogICAgICAtICdkYi1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotd2luZG1pbGwtZGJ9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgd2luZG1pbGwtc2VydmVyOgogICAgaW1hZ2U6ICdnaGNyLmlvL3dpbmRtaWxsLWxhYnMvd2luZG1pbGw6bWFpbicKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9XSU5ETUlMTF84MDAwCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QGRiLyR7UE9TVEdSRVNfREI6LXdpbmRtaWxsLWRifScKICAgICAgLSBNT0RFPXNlcnZlcgogICAgICAtICdCQVNFX1VSTD0ke1NFUlZJQ0VfRlFETl9XSU5ETUlMTH0nCiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnd29ya2VyLWxvZ3M6L3RtcC93aW5kbWlsbC9sb2dzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwMDAvaGVhbHRoJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLTE6CiAgICBpbWFnZTogJ2doY3IuaW8vd2luZG1pbGwtbGFicy93aW5kbWlsbDptYWluJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QGRiLyR7UE9TVEdSRVNfREI6LXdpbmRtaWxsLWRifScKICAgICAgLSBNT0RFPXdvcmtlcgogICAgICAtIFdPUktFUl9HUk9VUD1kZWZhdWx0CiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnL3Zhci9ydW4vZG9ja2VyLnNvY2s6L3Zhci9ydW4vZG9ja2VyLnNvY2snCiAgICAgIC0gJ3dvcmtlci1kZXBlbmRlbmN5LWNhY2hlOi90bXAvd2luZG1pbGwvY2FjaGUnCiAgICAgIC0gJ3dvcmtlci1sb2dzOi90bXAvd2luZG1pbGwvbG9ncycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLTI6CiAgICBpbWFnZTogJ2doY3IuaW8vd2luZG1pbGwtbGFicy93aW5kbWlsbDptYWluJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QGRiLyR7UE9TVEdSRVNfREI6LXdpbmRtaWxsLWRifScKICAgICAgLSBNT0RFPXdvcmtlcgogICAgICAtIFdPUktFUl9HUk9VUD1kZWZhdWx0CiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnL3Zhci9ydW4vZG9ja2VyLnNvY2s6L3Zhci9ydW4vZG9ja2VyLnNvY2snCiAgICAgIC0gJ3dvcmtlci1kZXBlbmRlbmN5LWNhY2hlOi90bXAvd2luZG1pbGwvY2FjaGUnCiAgICAgIC0gJ3dvcmtlci1sb2dzOi90bXAvd2luZG1pbGwvbG9ncycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLTM6CiAgICBpbWFnZTogJ2doY3IuaW8vd2luZG1pbGwtbGFicy93aW5kbWlsbDptYWluJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QGRiLyR7UE9TVEdSRVNfREI6LXdpbmRtaWxsLWRifScKICAgICAgLSBNT0RFPXdvcmtlcgogICAgICAtIFdPUktFUl9HUk9VUD1kZWZhdWx0CiAgICBkZXBlbmRzX29uOgogICAgICBkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnL3Zhci9ydW4vZG9ja2VyLnNvY2s6L3Zhci9ydW4vZG9ja2VyLnNvY2snCiAgICAgIC0gJ3dvcmtlci1kZXBlbmRlbmN5LWNhY2hlOi90bXAvd2luZG1pbGwvY2FjaGUnCiAgICAgIC0gJ3dvcmtlci1sb2dzOi90bXAvd2luZG1pbGwvbG9ncycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgd2luZG1pbGwtd29ya2VyLW5hdGl2ZToKICAgIGltYWdlOiAnZ2hjci5pby93aW5kbWlsbC1sYWJzL3dpbmRtaWxsOm1haW4nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AZGIvJHtQT1NUR1JFU19EQjotd2luZG1pbGwtZGJ9JwogICAgICAtIE1PREU9d29ya2VyCiAgICAgIC0gV09SS0VSX0dST1VQPW5hdGl2ZQogICAgICAtIE5VTV9XT1JLRVJTPTgKICAgICAgLSBTTEVFUF9RVUVVRT0yMDAKICAgIGRlcGVuZHNfb246CiAgICAgIGRiOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICB2b2x1bWVzOgogICAgICAtICd3b3JrZXItbG9nczovdG1wL3dpbmRtaWxsL2xvZ3MnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2V4aXQgMCcKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwogIGxzcDoKICAgIGltYWdlOiAnZ2hjci5pby93aW5kbWlsbC1sYWJzL3dpbmRtaWxsLWxzcDpsYXRlc3QnCiAgICB2b2x1bWVzOgogICAgICAtICdsc3AtY2FjaGU6L3Jvb3QvLmNhY2hlJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdleGl0IDAnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICAgICAgc3RhcnRfcGVyaW9kOiAyMHMK", "tags": [ "windmill", "workflow", From 2315bdb93f4371ac6f92300f48f68b146fdbcdd5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 14:56:36 +0200 Subject: [PATCH 076/120] ui updates on server --- .../{RemoveServer.php => DeleteServer.php} | 4 +- app/Actions/Server/StartSentinel.php | 4 +- .../Controllers/Api/ServersController.php | 5 +- app/Livewire/Destination/Show.php | 2 +- app/Livewire/Server/Advanced.php | 61 +++++ app/Livewire/Server/CloudflareTunnels.php | 45 ++++ app/Livewire/Server/Delete.php | 6 +- app/Livewire/Server/Form.php | 50 +++- app/Livewire/Server/Proxy/Modal.php | 16 -- app/Livewire/Server/Resources.php | 26 +- app/Livewire/Server/ShowPrivateKey.php | 33 ++- app/Models/Server.php | 37 +-- app/Models/ServerSetting.php | 51 +++- bootstrap/helpers/shared.php | 2 +- ...0_17_093722_add_soft_delete_to_servers.php | 28 +++ database/seeders/SentinelSeeder.php | 25 +- .../views/components/server/navbar.blade.php | 38 +-- .../views/livewire/destination/show.blade.php | 6 +- .../views/livewire/server/advanced.blade.php | 84 +++++++ .../server/cloudflare-tunnels.blade.php | 42 ++++ .../views/livewire/server/delete.blade.php | 2 +- .../server/destination/show.blade.php | 2 +- .../views/livewire/server/form.blade.php | 230 +++++------------- .../livewire/server/log-drains.blade.php | 2 +- .../server/private-key/show.blade.php | 1 - .../livewire/server/proxy/modal.blade.php | 12 - .../views/livewire/server/resources.blade.php | 65 +++-- .../server/show-private-key.blade.php | 32 ++- .../views/livewire/server/show.blade.php | 76 +++++- 29 files changed, 614 insertions(+), 373 deletions(-) rename app/Actions/Server/{RemoveServer.php => DeleteServer.php} (81%) create mode 100644 app/Livewire/Server/Advanced.php create mode 100644 app/Livewire/Server/CloudflareTunnels.php delete mode 100644 app/Livewire/Server/Proxy/Modal.php create mode 100644 database/migrations/2024_10_17_093722_add_soft_delete_to_servers.php create mode 100644 resources/views/livewire/server/advanced.blade.php create mode 100644 resources/views/livewire/server/cloudflare-tunnels.blade.php delete mode 100644 resources/views/livewire/server/proxy/modal.blade.php diff --git a/app/Actions/Server/RemoveServer.php b/app/Actions/Server/DeleteServer.php similarity index 81% rename from app/Actions/Server/RemoveServer.php rename to app/Actions/Server/DeleteServer.php index 8e92a51ae..15c892e75 100644 --- a/app/Actions/Server/RemoveServer.php +++ b/app/Actions/Server/DeleteServer.php @@ -5,13 +5,13 @@ use App\Models\Server; use Lorisleiva\Actions\Concerns\AsAction; -class RemoveServer +class DeleteServer { use AsAction; public function handle(Server $server) { StopSentinel::run($server); - $server->delete(); + $server->forceDelete(); } } diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php index 3fbe4b3a3..cca8138b9 100644 --- a/app/Actions/Server/StartSentinel.php +++ b/app/Actions/Server/StartSentinel.php @@ -34,9 +34,9 @@ public function handle(Server $server, $version = 'next', bool $restart = false) 'COLLECTOR_RETENTION_PERIOD_DAYS' => $metrics_history, ]; if (isDev()) { - data_set($environments, 'DEBUG', 'true'); + // data_set($environments, 'DEBUG', 'true'); $mount_dir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/sentinel'; - $image = 'sentinel'; + // $image = 'sentinel'; } $docker_environments = '-e "' . implode('" -e "', array_map(fn($key, $value) => "$key=$value", array_keys($environments), $environments)) . '"'; diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index 6d47769a9..540069f85 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Api; -use App\Actions\Server\RemoveServer; +use App\Actions\Server\DeleteServer; use App\Actions\Server\ValidateServer; use App\Enums\ProxyStatus; use App\Enums\ProxyTypes; @@ -726,7 +726,8 @@ public function delete_server(Request $request) if ($server->definedResources()->count() > 0) { return response()->json(['message' => 'Server has resources, so you need to delete them before.'], 400); } - RemoveServer::dispatch($server); + $server->delete(); + DeleteServer::dispatch($server); return response()->json(['message' => 'Server deleted.']); } diff --git a/app/Livewire/Destination/Show.php b/app/Livewire/Destination/Show.php index 5650e82ba..37583a944 100644 --- a/app/Livewire/Destination/Show.php +++ b/app/Livewire/Destination/Show.php @@ -66,7 +66,7 @@ public function scan() return ! $alreadyAddedNetworks->contains('network', $network['Name']); }); if ($this->networks->count() === 0) { - $this->dispatch('success', 'No new networks found.'); + $this->dispatch('success', 'No new destinations found on this server.'); return; } diff --git a/app/Livewire/Server/Advanced.php b/app/Livewire/Server/Advanced.php new file mode 100644 index 000000000..0103ac5f6 --- /dev/null +++ b/app/Livewire/Server/Advanced.php @@ -0,0 +1,61 @@ + 'required|integer|min:1', + 'server.settings.dynamic_timeout' => 'required|integer|min:1', + 'server.settings.force_docker_cleanup' => 'required|boolean', + 'server.settings.docker_cleanup_frequency' => 'required_if:server.settings.force_docker_cleanup,true|string', + 'server.settings.docker_cleanup_threshold' => 'required_if:server.settings.force_docker_cleanup,false|integer|min:1|max:100', + 'server.settings.delete_unused_volumes' => 'boolean', + 'server.settings.delete_unused_networks' => 'boolean', + ]; + + protected $validationAttributes = [ + + 'server.settings.concurrent_builds' => 'Concurrent Builds', + 'server.settings.dynamic_timeout' => 'Dynamic Timeout', + 'server.settings.force_docker_cleanup' => 'Force Docker Cleanup', + 'server.settings.docker_cleanup_frequency' => 'Docker Cleanup Frequency', + 'server.settings.docker_cleanup_threshold' => 'Docker Cleanup Threshold', + 'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', + 'server.settings.delete_unused_networks' => 'Delete Unused Networks', + ]; + public function instantSave() + { + try { + $this->validate(); + $this->server->settings->save(); + $this->dispatch('success', 'Server updated.'); + $this->dispatch('refreshServerShow'); + } catch (\Throwable $e) { + $this->server->settings->refresh(); + return handleError($e, $this); + } + } + public function submit() + { + try { + $frequency = $this->server->settings->docker_cleanup_frequency; + if (empty($frequency) || ! validate_cron_expression($frequency)) { + $this->server->settings->docker_cleanup_frequency = '*/10 * * * *'; + throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency. Resetting to default 10 minutes.'); + } + $this->server->settings->save(); + $this->dispatch('success', 'Server updated.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function render() + { + return view('livewire.server.advanced'); + } +} diff --git a/app/Livewire/Server/CloudflareTunnels.php b/app/Livewire/Server/CloudflareTunnels.php new file mode 100644 index 000000000..5b0f43329 --- /dev/null +++ b/app/Livewire/Server/CloudflareTunnels.php @@ -0,0 +1,45 @@ + 'required|boolean', + ]; + + protected $validationAttributes = [ + 'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel', + ]; + + public function instantSave() + { + try { + $this->validate(); + $this->server->settings->save(); + $this->dispatch('success', 'Server updated.'); + $this->dispatch('refreshServerShow'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + + public function manualCloudflareConfig() + { + $this->server->settings->is_cloudflare_tunnel = true; + $this->server->settings->save(); + $this->server->refresh(); + $this->dispatch('success', 'Cloudflare Tunnels enabled.'); + } + + public function render() + { + return view('livewire.server.cloudflare-tunnels'); + } +} diff --git a/app/Livewire/Server/Delete.php b/app/Livewire/Server/Delete.php index 2af56cb1c..0c1fa2745 100644 --- a/app/Livewire/Server/Delete.php +++ b/app/Livewire/Server/Delete.php @@ -2,7 +2,7 @@ namespace App\Livewire\Server; -use App\Actions\Server\RemoveServer; +use App\Actions\Server\DeleteServer; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; @@ -28,8 +28,8 @@ public function delete($password) return; } - RemoveServer::run($this->server); - + $this->server->delete(); + DeleteServer::dispatch($this->server); return redirect()->route('server.index'); } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 40bff3873..1fbe4f880 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -89,7 +89,7 @@ public function getListeners() 'server.settings.sentinel_metrics_history_days' => 'Metrics History', 'server.settings.sentinel_push_interval_seconds' => 'Push Interval', 'server.settings.is_sentinel_enabled' => 'Server API', - 'server.settings.sentinel_custom_url' => 'Sentinel URL', + 'server.settings.sentinel_custom_url' => 'Coolify URL', 'server.settings.server_timezone' => 'Server Timezone', 'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', 'server.settings.delete_unused_networks' => 'Delete Unused Networks', @@ -106,7 +106,8 @@ public function mount(Server $server) $this->server->settings->delete_unused_networks = $server->settings->delete_unused_networks; } - public function checkSyncStatus(){ + public function checkSyncStatus() + { $this->server->refresh(); $this->server->settings->refresh(); } @@ -114,9 +115,10 @@ public function checkSyncStatus(){ public function regenerateSentinelToken() { try { - $this->server->generateSentinelToken(); + $this->server->settings->generateSentinelToken(); $this->server->settings->refresh(); - $this->dispatch('success', 'Sentinel token regenerated. Please restart your Sentinel.'); + $this->restartSentinel(notification: false); + $this->dispatch('success', 'Token regenerated & Sentinel restarted.'); } catch (\Throwable $e) { return handleError($e, $this); } @@ -152,18 +154,28 @@ public function updatedServerSettingsIsBuildServer() $this->dispatch('proxyStatusUpdated'); } - public function updatedServerSettingsIsSentinelEnabled($value){ - if($value === false){ + public function updatedServerSettingsIsSentinelEnabled($value) + { + $this->validate(); + $this->validate([ + 'server.settings.sentinel_custom_url' => 'required|url', + ]); + if ($value === false) { StopSentinel::dispatch($this->server); $this->server->settings->is_metrics_enabled = false; $this->server->settings->save(); $this->server->sentinelHeartbeat(isReset: true); } else { - StartSentinel::run($this->server); + try { + StartSentinel::run($this->server); + } catch (\Throwable $e) { + return handleError($e, $this); + } } } - public function updatedServerSettingsIsMetricsEnabled(){ + public function updatedServerSettingsIsMetricsEnabled() + { $this->restartSentinel(); } @@ -171,6 +183,7 @@ public function updatedServerSettingsIsMetricsEnabled(){ public function instantSave() { try { + $this->validate(); refresh_server_connection($this->server->privateKey); $this->validateServer(false); @@ -179,6 +192,14 @@ public function instantSave() $this->dispatch('success', 'Server updated.'); $this->dispatch('refreshServerShow'); + // if ($this->server->isSentinelEnabled()) { + // StartSentinel::run($this->server); + // } else { + // StopSentinel::run($this->server); + // $this->server->settings->is_metrics_enabled = false; + // $this->server->settings->save(); + // $this->server->sentinelHeartbeat(isReset: true); + // } // if ($this->server->isSentinelEnabled()) { // PullSentinelImageJob::dispatchSync($this->server); // ray('Sentinel is enabled'); @@ -196,16 +217,23 @@ public function instantSave() // $this->checkPortForServerApi(); } catch (\Throwable $e) { + $this->server->settings->refresh(); return handleError($e, $this); } } - public function restartSentinel() + public function restartSentinel($notification = true) { try { + $this->validate(); + $this->validate([ + 'server.settings.sentinel_custom_url' => 'required|url', + ]); $version = get_latest_sentinel_version(); StartSentinel::run($this->server, $version, true); - $this->dispatch('success', 'Sentinel started.'); + if ($notification) { + $this->dispatch('success', 'Sentinel started.'); + } } catch (\Throwable $e) { return handleError($e, $this); } @@ -227,7 +255,7 @@ public function checkLocalhostConnection() $this->server->settings->save(); $this->dispatch('proxyStatusUpdated'); } else { - $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: '.$error); + $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: ' . $error); return; } diff --git a/app/Livewire/Server/Proxy/Modal.php b/app/Livewire/Server/Proxy/Modal.php deleted file mode 100644 index 5679944d0..000000000 --- a/app/Livewire/Server/Proxy/Modal.php +++ /dev/null @@ -1,16 +0,0 @@ -dispatch('proxyStatusUpdated'); - } -} diff --git a/app/Livewire/Server/Resources.php b/app/Livewire/Server/Resources.php index 800344ac3..f549b43cb 100644 --- a/app/Livewire/Server/Resources.php +++ b/app/Livewire/Server/Resources.php @@ -15,7 +15,9 @@ class Resources extends Component public $parameters = []; - public Collection $unmanagedContainers; + public Collection $containers; + + public $activeTab = 'managed'; public function getListeners() { @@ -50,14 +52,29 @@ public function stopUnmanaged($id) public function refreshStatus() { $this->server->refresh(); - $this->loadUnmanagedContainers(); + if ($this->activeTab === 'managed') { + $this->loadManagedContainers(); + } else { + $this->loadUnmanagedContainers(); + } $this->dispatch('success', 'Resource statuses refreshed.'); } + public function loadManagedContainers() + { + try { + $this->activeTab = 'managed'; + $this->containers = $this->server->refresh()->definedResources(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function loadUnmanagedContainers() { + $this->activeTab = 'unmanaged'; try { - $this->unmanagedContainers = $this->server->loadUnmanagedContainers(); + $this->containers = $this->server->loadUnmanagedContainers(); } catch (\Throwable $e) { return handleError($e, $this); } @@ -65,13 +82,14 @@ public function loadUnmanagedContainers() public function mount() { - $this->unmanagedContainers = collect(); + $this->containers = collect(); $this->parameters = get_route_parameters(); try { $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); if (is_null($this->server)) { return redirect()->route('server.index'); } + $this->loadManagedContainers(); } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Server/ShowPrivateKey.php b/app/Livewire/Server/ShowPrivateKey.php index 92869c44b..1be22882d 100644 --- a/app/Livewire/Server/ShowPrivateKey.php +++ b/app/Livewire/Server/ShowPrivateKey.php @@ -2,7 +2,6 @@ namespace App\Livewire\Server; -use App\Models\PrivateKey; use App\Models\Server; use Livewire\Component; @@ -14,15 +13,29 @@ class ShowPrivateKey extends Component public $parameters; + public function mount() + { + $this->parameters = get_route_parameters(); + } + public function setPrivateKey($privateKeyId) { + $originalPrivateKeyId = $this->server->getOriginal('private_key_id'); try { - $privateKey = PrivateKey::findOrFail($privateKeyId); - $this->server->update(['private_key_id' => $privateKey->id]); - $this->server->refresh(); - $this->dispatch('success', 'Private key updated successfully.'); + $this->server->update(['private_key_id' => $privateKeyId]); + ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(); + if ($uptime) { + $this->dispatch('success', 'Private key updated successfully.'); + } else { + throw new \Exception('Server is not reachable.

Check this documentation for further help.

Error: '.$error); + } } catch (\Exception $e) { + $this->server->update(['private_key_id' => $originalPrivateKeyId]); + $this->server->validateConnection(); $this->dispatch('error', 'Failed to update private key: '.$e->getMessage()); + } finally { + $this->dispatch('refreshServerShow'); + $this->server->refresh(); } } @@ -33,18 +46,16 @@ public function checkConnection() if ($uptime) { $this->dispatch('success', 'Server is reachable.'); } else { - ray($error); $this->dispatch('error', 'Server is not reachable.

Check this documentation for further help.

Error: '.$error); - return; } } catch (\Throwable $e) { return handleError($e, $this); + } finally { + $this->dispatch('refreshServerShow'); + $this->server->refresh(); } } - public function mount() - { - $this->parameters = get_route_parameters(); - } + } diff --git a/app/Models/Server.php b/app/Models/Server.php index cb5aa4524..2468fc2b4 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -7,6 +7,7 @@ use App\Jobs\PullSentinelImageJob; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; @@ -17,7 +18,6 @@ use Spatie\SchemalessAttributes\Casts\SchemalessAttributes; use Spatie\SchemalessAttributes\SchemalessAttributesTrait; use Spatie\Url\Url; -use Illuminate\Support\Str; use Symfony\Component\Yaml\Yaml; #[OA\Schema( @@ -45,7 +45,7 @@ class Server extends BaseModel { - use SchemalessAttributesTrait; + use SchemalessAttributesTrait,SoftDeletes; public static $batch_counter = 0; @@ -97,7 +97,8 @@ protected static function booted() } } }); - static::deleting(function ($server) { + + static::forceDeleting(function ($server) { $server->destinations()->each(function ($destination) { $destination->delete(); }); @@ -527,34 +528,6 @@ public function forceDisableServer() Storage::disk('ssh-mux')->delete($this->muxFilename()); } - public function generateSentinelUrl() { - if ($this->isLocalhost()) { - return 'http://host.docker.internal:8000'; - } - $settings = InstanceSettings::get(); - if ($settings->fqdn) { - return $settings->fqdn; - } - if ($settings->ipv4) { - return $settings->ipv4 . ':8000'; - } - if ($settings->ipv6) { - return $settings->ipv6 . ':8000'; - } - return null; - } - public function generateSentinelToken() - { - $data = [ - 'server_uuid' => $this->uuid, - ]; - $token = json_encode($data); - $encrypted = encrypt($token); - $this->settings->sentinel_token = $encrypted; - $this->settings->save(); - - return $encrypted; - } public function sentinelHeartbeat(bool $isReset = false) { @@ -568,7 +541,7 @@ public function isSentinelLive() public function isSentinelEnabled() { - return $this->isMetricsEnabled() || $this->isServerApiEnabled() || !$this->isBuildServer(); + return ($this->isMetricsEnabled() || $this->isServerApiEnabled()) && !$this->isBuildServer(); } public function isMetricsEnabled() diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index 2b9ce0cd0..8ef1420e0 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -59,10 +59,59 @@ class ServerSetting extends Model protected static function booted() { static::creating(function ($setting) { - $setting->is_sentinel_enabled = true; + try { + if (str($setting->sentinel_token)->isEmpty()) { + $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; + } + } + } catch (\Throwable $e) { + loggy('Error creating server setting: ' . $e->getMessage()); + } }); } + public function generateSentinelToken(bool $save = true) + { + $data = [ + 'server_uuid' => $this->server->uuid, + ]; + $token = json_encode($data); + $encrypted = encrypt($token); + $this->sentinel_token = $encrypted; + if ($save) { + $this->save(); + } + + return $encrypted; + } + + public function generateSentinelUrl(bool $save = true) + { + $domain = null; + $settings = InstanceSettings::get(); + if ($this->server->isLocalhost()) { + $domain = 'http://host.docker.internal:8000'; + } else if ($settings->fqdn) { + $domain = $settings->fqdn; + } else if ($settings->ipv4) { + $domain = $settings->ipv4 . ':8000'; + } else if ($settings->ipv6) { + $domain = $settings->ipv6 . ':8000'; + } + $this->sentinel_custom_url = $domain; + if ($save) { + $this->save(); + } + return $domain; + } + public function server() { return $this->belongsTo(Server::class); diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index b619d1dd1..14f44ed47 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -126,7 +126,7 @@ function refreshSession(?Team $team = null): void } function handleError(?Throwable $error = null, ?Livewire\Component $livewire = null, ?string $customErrorMessage = null) { - ray($error); + loggy($error); if ($error instanceof TooManyRequestsException) { if (isset($livewire)) { return $livewire->dispatch('error', "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds."); diff --git a/database/migrations/2024_10_17_093722_add_soft_delete_to_servers.php b/database/migrations/2024_10_17_093722_add_soft_delete_to_servers.php new file mode 100644 index 000000000..7a7f28e24 --- /dev/null +++ b/database/migrations/2024_10_17_093722_add_soft_delete_to_servers.php @@ -0,0 +1,28 @@ +softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('servers', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + } +}; diff --git a/database/seeders/SentinelSeeder.php b/database/seeders/SentinelSeeder.php index 2d29c1a8d..117ba6782 100644 --- a/database/seeders/SentinelSeeder.php +++ b/database/seeders/SentinelSeeder.php @@ -9,22 +9,23 @@ class SentinelSeeder extends Seeder { public function run() { - try { - Server::chunk(100, function ($servers) { - foreach ($servers as $server) { + Server::chunk(100, function ($servers) { + foreach ($servers as $server) { + try { if (str($server->settings->sentinel_token)->isEmpty()) { - $server->generateSentinelToken(); + $server->settings->generateSentinelToken(); } if (str($server->settings->sentinel_custom_url)->isEmpty()) { - $url = $server->generateSentinelUrl(); - $server->settings->sentinel_custom_url = $url; - $server->settings->save(); + $url = $server->settings->generateSentinelUrl(); + if (str($url)->isEmpty()) { + $server->settings->is_sentinel_enabled = false; + $server->settings->save(); + } } + } catch (\Throwable $e) { + loggy("Error: {$e->getMessage()}\n"); } - }); - } catch (\Throwable $e) { - echo "Error: {$e->getMessage()}\n"; - ray($e->getMessage()); - } + } + }); } } diff --git a/resources/views/components/server/navbar.blade.php b/resources/views/components/server/navbar.blade.php index 18f923289..162514278 100644 --- a/resources/views/components/server/navbar.blade.php +++ b/resources/views/components/server/navbar.blade.php @@ -1,5 +1,14 @@
- + + + + + + + Close + + +

Server

@if ($server->proxySet()) @@ -13,20 +22,9 @@ href="{{ route('server.show', [ 'server_uuid' => data_get($parameters, 'server_uuid'), ]) }}"> - - - - - - - + + @if (!$server->isSwarmWorker() && !$server->settings->is_build_server) - - - - - - @endif
diff --git a/resources/views/livewire/destination/show.blade.php b/resources/views/livewire/destination/show.blade.php index ecc68dc5c..be36899b6 100644 --- a/resources/views/livewire/destination/show.blade.php +++ b/resources/views/livewire/destination/show.blade.php @@ -5,10 +5,10 @@ - Scan Destinations + Scan for Destinations
-
Destinations are used to segregate resources by network.
-
+
Destinations are used to segregate resources by network.
+
Available for using: @forelse ($server->standaloneDockers as $docker) diff --git a/resources/views/livewire/server/advanced.blade.php b/resources/views/livewire/server/advanced.blade.php new file mode 100644 index 000000000..b1d21402a --- /dev/null +++ b/resources/views/livewire/server/advanced.blade.php @@ -0,0 +1,84 @@ +
+
+
+

Advanced

+ Save + +
+
Advanced configuration for your server.
+
+
+
+
+

Docker Cleanup

+ +
+
+ @if ($server->settings->force_docker_cleanup) + + @else + + @endif +
+ +
+ +
+

+ Warning: Enable these + options only if you fully understand their implications and + consequences!
Improper use will result in data loss and could cause + functional issues. +

+
+ + +
+
+
+

Builds

+
Customize the build process.
+
+ + +
+
+
+
diff --git a/resources/views/livewire/server/cloudflare-tunnels.blade.php b/resources/views/livewire/server/cloudflare-tunnels.blade.php new file mode 100644 index 000000000..acca66d60 --- /dev/null +++ b/resources/views/livewire/server/cloudflare-tunnels.blade.php @@ -0,0 +1,42 @@ +
diff --git a/resources/views/livewire/server/delete.blade.php b/resources/views/livewire/server/delete.blade.php index 360e1e0c6..917000273 100644 --- a/resources/views/livewire/server/delete.blade.php +++ b/resources/views/livewire/server/delete.blade.php @@ -1,6 +1,6 @@
@if ($server->id !== 0) -

Danger Zone

+

Danger Zone

Woah. I hope you know what are you doing.

Delete Server

This will remove this server from Coolify. Beware! There is no coming diff --git a/resources/views/livewire/server/destination/show.blade.php b/resources/views/livewire/server/destination/show.blade.php index 1a1bbeb1b..fb9ab4fbb 100644 --- a/resources/views/livewire/server/destination/show.blade.php +++ b/resources/views/livewire/server/destination/show.blade.php @@ -2,6 +2,6 @@ {{ data_get_str($server, 'name')->limit(10) }} > Server Destinations | Coolify - + {{-- --}}
diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 43d982b6c..f75b9762f 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -119,197 +119,82 @@ class="px-4 py-2 text-gray-800 cursor-pointer hover:bg-gray-100 dark:hover:bg-co
-
+
@if (!$server->isLocalhost()) - -
-
-

Cloudflare Tunnels

- -
- @if ($server->settings->is_cloudflare_tunnel) -
- -
- @elseif (!$server->isFunctional()) -
- To automatically configure Cloudflare Tunnels, please - validate your server first. Then you will need a Cloudflare token and an SSH - domain configured. -
- To manually configure Cloudflare Tunnels, please - click here, then you should validate the server. -

- For more information, please read our documentation. -
- @endif - @if (!$server->settings->is_cloudflare_tunnel && $server->isFunctional()) - - - - @endif - @if ($server->isFunctional() && !$server->settings->is_cloudflare_tunnel) -
- I have configured Cloudflare Tunnels manually -
- @endif - +
+
+ @if (!$server->isBuildServer() && !$server->settings->is_cloudflare_tunnel)

Swarm (experimental)

Read the docs here.
- @if ($server->settings->is_swarm_worker) - - @else - - @endif +
+ @if ($server->settings->is_swarm_worker) + + @else + + @endif - @if ($server->settings->is_swarm_manager) - - @else - - @endif + @if ($server->settings->is_swarm_manager) + + @else + + @endif +
@endif @endif
- - @if ($server->isFunctional()) -

Settings

-
-
-
-
- -
- -
- @if ($server->settings->force_docker_cleanup) - - @else - - @endif -
- -
-

Warning: Enable these - options only if you fully understand their implications and - consequences!
Improper use will result in data loss and could cause - functional issues.

- - -
-
-
- -
- - -
-
- @if (isDev()) -
-

Sentinel

- @if ($server->isSentinelEnabled()) -
settings->sentinel_push_interval_seconds }}s="checkSyncStatus"> - @if ($server->isSentinelLive()) - - @else - - @endif + @if (isDev()) +
+

Sentinel

+ @if ($server->isSentinelEnabled()) +
settings->sentinel_push_interval_seconds }}s="checkSyncStatus"> + @if ($server->isSentinelLive()) + Restart -
- @endif -
-
-
- - @if ($server->isSentinelEnabled()) - @else - + + Sync @endif
+ @endif +
+
+
+ + @if ($server->isSentinelEnabled()) + + @else + + @endif +
+ @if ($server->isSentinelEnabled())
- - Regenerate
+ + +
helper="How many seconds should the metrics data should be pushed to the collector." />
-
- @endif + @endif +
@endif +
diff --git a/resources/views/livewire/server/log-drains.blade.php b/resources/views/livewire/server/log-drains.blade.php index 1c19e3662..ac905e8bb 100644 --- a/resources/views/livewire/server/log-drains.blade.php +++ b/resources/views/livewire/server/log-drains.blade.php @@ -2,7 +2,7 @@ {{ data_get_str($server, 'name')->limit(10) }} > Server LogDrains | Coolify - + {{-- --}} @if ($server->isFunctional())

Log Drains

Sends service logs to 3rd party tools.
diff --git a/resources/views/livewire/server/private-key/show.blade.php b/resources/views/livewire/server/private-key/show.blade.php index 3cf190bca..014de2e7c 100644 --- a/resources/views/livewire/server/private-key/show.blade.php +++ b/resources/views/livewire/server/private-key/show.blade.php @@ -2,6 +2,5 @@ Server Connection | Coolify -
diff --git a/resources/views/livewire/server/proxy/modal.blade.php b/resources/views/livewire/server/proxy/modal.blade.php deleted file mode 100644 index 3dfb2d31c..000000000 --- a/resources/views/livewire/server/proxy/modal.blade.php +++ /dev/null @@ -1,12 +0,0 @@ -
- - - - - - - Close - - - -
diff --git a/resources/views/livewire/server/resources.blade.php b/resources/views/livewire/server/resources.blade.php index 1e361728c..609995f8e 100644 --- a/resources/views/livewire/server/resources.blade.php +++ b/resources/views/livewire/server/resources.blade.php @@ -2,24 +2,30 @@ {{ data_get_str($server, 'name')->limit(10) }} > Server Resources | Coolify - -
- + {{-- --}} +
-
-
-
-

Resources

- Refresh -
-
Here you can find all resources that are managed by Coolify.
+
+
+

Resources

+ Refresh
- @if ($server->definedResources()->count() > 0) +
Here you can find all resources that are managed by Coolify.
+
+
$activeTab === 'managed', + ]) wire:click="loadManagedContainers"> + Managed
+
$activeTab === 'unmanaged', + ]) wire:click="loadUnmanagedContainers"> + Unmanaged
+
+
+ @if ($containers->count() > 0) + @if ($activeTab === 'managed')
@@ -78,19 +84,7 @@
- @else -
No resources found.
- @endif -
-
-
-
-

Resources

- Refresh -
-
Here you can find all other containers running on the server.
-
- @if ($unmanagedContainers->count() > 0) + @elseif ($activeTab === 'unmanaged')
@@ -114,7 +108,7 @@ - @forelse ($unmanagedContainers->sortBy('name',SORT_NATURAL) as $resource) + @forelse ($containers->sortBy('name',SORT_NATURAL) as $resource) {{ data_get($resource, 'Names') }} @@ -152,11 +146,14 @@
-
- @else -
No resources found.
@endif -
+ @else + @if ($activeTab === 'managed') +
No managed resources found.
+ @elseif ($activeTab === 'unmanaged') +
No unmanaged resources found.
+ @endif + @endif
diff --git a/resources/views/livewire/server/show-private-key.blade.php b/resources/views/livewire/server/show-private-key.blade.php index 86bf2568e..f84086bff 100644 --- a/resources/views/livewire/server/show-private-key.blade.php +++ b/resources/views/livewire/server/show-private-key.blade.php @@ -1,5 +1,5 @@
-
+

Private Key

@@ -9,29 +9,25 @@
-
- @if (data_get($server, 'privateKey.uuid')) -
- Currently attached Private Key: - - - -
- @else -
No private key attached.
- @endif - +
+
Change your server's private key.
-

Choose another Key

-
+
@forelse ($privateKeys as $private_key) -
+
{{ $private_key->name }}
{{ $private_key->description }}
+ @if (data_get($server, 'privateKey.uuid') !== $private_key->uuid) + + Use this key + + @else + + Currently used + + @endif
@empty
No private keys found.
diff --git a/resources/views/livewire/server/show.blade.php b/resources/views/livewire/server/show.blade.php index 4a2729d3c..458d8cd2f 100644 --- a/resources/views/livewire/server/show.blade.php +++ b/resources/views/livewire/server/show.blade.php @@ -3,11 +3,75 @@ {{ data_get_str($server, 'name')->limit(10) }} > Server Configurations | Coolify - - @if ($server->isFunctional() && $server->isMetricsEnabled()) -
- +
+
+ General + @if ($server->isFunctional()) + Advanced + + @endif + Private + Key + @if ($server->isFunctional()) + Cloudflare Tunnels + Resources + Destinations + Log + Drains + Metrics + @endif + @if (!$server->isLocalhost()) + Danger + @endif
- @endif - +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ @if ($server->isFunctional() && $server->isMetricsEnabled()) +
+ +
+ @else + No metrics available. + @endif +
+ @if (!$server->isLocalhost()) +
+ +
+ @endif +
+
From 4bf995acf74b22c77d96bc12f2cf372d5f009944 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:08:23 +0200 Subject: [PATCH 077/120] fix grafana-with-postgresql.yaml --- .../compose/grafana-with-postgresql.yaml | 63 ++++++++----------- templates/service-templates.json | 18 +++--- 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/templates/compose/grafana-with-postgresql.yaml b/templates/compose/grafana-with-postgresql.yaml index 5656069fb..0ccdd235d 100644 --- a/templates/compose/grafana-with-postgresql.yaml +++ b/templates/compose/grafana-with-postgresql.yaml @@ -1,52 +1,41 @@ - - -# documentation: https://docs.mindsdb.com/what-is-mindsdb -# slogan: MindsDB is the platform for building AI from enterprise data, enabling smarter organizations. -# tags: mysql, postgresdb, machine-learning, ai -# logo: svgs/mindsdb.png -# port: 47334 +# documentation: https://grafana.com +# slogan: Grafana is the open source analytics & monitoring solution for every database. +# tags: grafana,analytics,monitoring,dashboard +# logo: svgs/grafana.svg +# port: 3000 services: - mindsdb: - image: mindsdb/mindsdb - restart: always - container_name: mindsdb + grafana: + image: grafana/grafana-oss environment: - - SERVICE_FQDN_MINDSDB_47334 - - SERVICE_FQDN_API_47335=/api - - MINDSDB_DOCKER_ENV=true - - MINDSDB_STORAGE_DIR=/mindsdb/var - - FLASK_DEBUG=1 # This will make sure http requests are logged regardless of log level - - OPENAI_API_KEY=$OPENAI_API_KEY - - LANGFUSE_HOST=$LANGFUSE_HOST - - LANGFUSE_PUBLIC_KEY=$LANGFUSE_PUBLIC_KEY - - LANGFUSE_SECRET_KEY=$LANGFUSE_SECRET_KEY - - LANGFUSE_RELEASE="local" - # - LANGFUSE_DEBUG="True" - - LANGFUSE_TIMEOUT="10" - - LANGFUSE_SAMPLE_RATE="1.0" - - MINDSDB_DB_CON=postgresql://postgres:postgres@postgresql - # ports: - # - 47335:47335 - # - 47336:47336 + - SERVICE_FQDN_GRAFANA_3000 + - GF_SERVER_ROOT_URL=${SERVICE_FQDN_GRAFANA} + - GF_SERVER_DOMAIN=${SERVICE_FQDN_GRAFANA} + - GF_SECURITY_ADMIN_PASSWORD=${SERVICE_PASSWORD_GRAFANA} + - GF_DATABASE_TYPE=postgres + - GF_DATABASE_HOST=postgresql + - GF_DATABASE_USER=$SERVICE_USER_POSTGRES + - GF_DATABASE_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - GF_DATABASE_NAME=${POSTGRES_DB:-grafana} volumes: - - mindsdb-data:/mindsdb/var + - grafana-data:/var/lib/grafana healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:47334/api/util/ping"] - interval: 30s - timeout: 4s - retries: 100 + test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/api/health"] + interval: 5s + timeout: 20s + retries: 10 + depends_on: + - postgresql postgresql: image: postgres:16-alpine volumes: - postgresql-data:/var/lib/postgresql/data environment: - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=postgres - - POSTGRES_DB=mindsdb + - POSTGRES_USER=$SERVICE_USER_POSTGRES + - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - POSTGRES_DB=${POSTGRES_DB:-grafana} healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 20s retries: 10 - diff --git a/templates/service-templates.json b/templates/service-templates.json index 56466eb58..be67f694a 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -999,18 +999,18 @@ "port": "8080" }, "grafana-with-postgresql": { - "documentation": "https://docs.mindsdb.com/what-is-mindsdb?utm_source=coolify.io", - "slogan": "MindsDB is the platform for building AI from enterprise data, enabling smarter organizations.", - "compose": "c2VydmljZXM6CiAgbWluZHNkYjoKICAgIGltYWdlOiBtaW5kc2RiL21pbmRzZGIKICAgIHJlc3RhcnQ6IGFsd2F5cwogICAgY29udGFpbmVyX25hbWU6IG1pbmRzZGIKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NSU5EU0RCXzQ3MzM0CiAgICAgIC0gU0VSVklDRV9GUUROX0FQSV80NzMzNT0vYXBpCiAgICAgIC0gTUlORFNEQl9ET0NLRVJfRU5WPXRydWUKICAgICAgLSBNSU5EU0RCX1NUT1JBR0VfRElSPS9taW5kc2RiL3ZhcgogICAgICAtIEZMQVNLX0RFQlVHPTEKICAgICAgLSBPUEVOQUlfQVBJX0tFWT0kT1BFTkFJX0FQSV9LRVkKICAgICAgLSBMQU5HRlVTRV9IT1NUPSRMQU5HRlVTRV9IT1NUCiAgICAgIC0gTEFOR0ZVU0VfUFVCTElDX0tFWT0kTEFOR0ZVU0VfUFVCTElDX0tFWQogICAgICAtIExBTkdGVVNFX1NFQ1JFVF9LRVk9JExBTkdGVVNFX1NFQ1JFVF9LRVkKICAgICAgLSAnTEFOR0ZVU0VfUkVMRUFTRT0ibG9jYWwiJwogICAgICAtICdMQU5HRlVTRV9USU1FT1VUPSIxMCInCiAgICAgIC0gJ0xBTkdGVVNFX1NBTVBMRV9SQVRFPSIxLjAiJwogICAgICAtICdNSU5EU0RCX0RCX0NPTj1wb3N0Z3Jlc3FsOi8vcG9zdGdyZXM6cG9zdGdyZXNAcG9zdGdyZXNxbCcKICAgIHZvbHVtZXM6CiAgICAgIC0gJ21pbmRzZGItZGF0YTovbWluZHNkYi92YXInCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6NDczMzQvYXBpL3V0aWwvcGluZycKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiA0cwogICAgICByZXRyaWVzOiAxMDAKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPXBvc3RncmVzCiAgICAgIC0gUE9TVEdSRVNfREI9bWluZHNkYgogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=", + "documentation": "https://grafana.com?utm_source=coolify.io", + "slogan": "Grafana is the open source analytics & monitoring solution for every database.", + "compose": "c2VydmljZXM6CiAgZ3JhZmFuYToKICAgIGltYWdlOiBncmFmYW5hL2dyYWZhbmEtb3NzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fR1JBRkFOQV8zMDAwCiAgICAgIC0gJ0dGX1NFUlZFUl9ST09UX1VSTD0ke1NFUlZJQ0VfRlFETl9HUkFGQU5BfScKICAgICAgLSAnR0ZfU0VSVkVSX0RPTUFJTj0ke1NFUlZJQ0VfRlFETl9HUkFGQU5BfScKICAgICAgLSAnR0ZfU0VDVVJJVFlfQURNSU5fUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX0dSQUZBTkF9JwogICAgICAtIEdGX0RBVEFCQVNFX1RZUEU9cG9zdGdyZXMKICAgICAgLSBHRl9EQVRBQkFTRV9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBHRl9EQVRBQkFTRV9VU0VSPSRTRVJWSUNFX1VTRVJfUE9TVEdSRVMKICAgICAgLSBHRl9EQVRBQkFTRV9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFUwogICAgICAtICdHRl9EQVRBQkFTRV9OQU1FPSR7UE9TVEdSRVNfREI6LWdyYWZhbmF9JwogICAgdm9sdW1lczoKICAgICAgLSAnZ3JhZmFuYS1kYXRhOi92YXIvbGliL2dyYWZhbmEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMC9hcGkvaGVhbHRoJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICBkZXBlbmRzX29uOgogICAgICAtIHBvc3RncmVzcWwKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotZ3JhZmFuYX0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==", "tags": [ - "mysql", - "postgresdb", - "machine-learning", - "ai" + "grafana", + "analytics", + "monitoring", + "dashboard" ], - "logo": "svgs/mindsdb.png", + "logo": "svgs/grafana.svg", "minversion": "0.0.0", - "port": "47334" + "port": "3000" }, "grafana": { "documentation": "https://grafana.com?utm_source=coolify.io", From a74d2e8f625860313066e80c872638a49fa8bb7d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 15:43:24 +0200 Subject: [PATCH 078/120] refactor --- app/Livewire/Server/Form.php | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 1fbe4f880..109306e54 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -7,7 +7,6 @@ use App\Jobs\DockerCleanupJob; use App\Jobs\PullSentinelImageJob; use App\Models\Server; -use Illuminate\Support\Facades\Http; use Livewire\Component; class Form extends Component @@ -47,27 +46,19 @@ public function getListeners() 'server.ip' => 'required', 'server.user' => 'required', 'server.port' => 'required', - 'server.settings.is_cloudflare_tunnel' => 'required|boolean', + 'wildcard_domain' => 'nullable|url', 'server.settings.is_reachable' => 'required', 'server.settings.is_swarm_manager' => 'required|boolean', 'server.settings.is_swarm_worker' => 'required|boolean', 'server.settings.is_build_server' => 'required|boolean', - 'server.settings.concurrent_builds' => 'required|integer|min:1', - 'server.settings.dynamic_timeout' => 'required|integer|min:1', 'server.settings.is_metrics_enabled' => 'required|boolean', 'server.settings.sentinel_token' => 'required', 'server.settings.sentinel_metrics_refresh_rate_seconds' => 'required|integer|min:1', 'server.settings.sentinel_metrics_history_days' => 'required|integer|min:1', 'server.settings.sentinel_push_interval_seconds' => 'required|integer|min:10', - 'wildcard_domain' => 'nullable|url', 'server.settings.sentinel_custom_url' => 'nullable|url', 'server.settings.is_sentinel_enabled' => 'required|boolean', 'server.settings.server_timezone' => 'required|string|timezone', - 'server.settings.force_docker_cleanup' => 'required|boolean', - 'server.settings.docker_cleanup_frequency' => 'required_if:server.settings.force_docker_cleanup,true|string', - 'server.settings.docker_cleanup_threshold' => 'required_if:server.settings.force_docker_cleanup,false|integer|min:1|max:100', - 'server.settings.delete_unused_volumes' => 'boolean', - 'server.settings.delete_unused_networks' => 'boolean', ]; protected $validationAttributes = [ @@ -76,13 +67,10 @@ public function getListeners() 'server.ip' => 'IP address/Domain', 'server.user' => 'User', 'server.port' => 'Port', - 'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel', 'server.settings.is_reachable' => 'Is reachable', 'server.settings.is_swarm_manager' => 'Swarm Manager', 'server.settings.is_swarm_worker' => 'Swarm Worker', 'server.settings.is_build_server' => 'Build Server', - 'server.settings.concurrent_builds' => 'Concurrent Builds', - 'server.settings.dynamic_timeout' => 'Dynamic Timeout', 'server.settings.is_metrics_enabled' => 'Metrics', 'server.settings.sentinel_token' => 'Metrics Token', 'server.settings.sentinel_metrics_refresh_rate_seconds' => 'Metrics Interval', @@ -91,8 +79,6 @@ public function getListeners() 'server.settings.is_sentinel_enabled' => 'Server API', 'server.settings.sentinel_custom_url' => 'Coolify URL', 'server.settings.server_timezone' => 'Server Timezone', - 'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', - 'server.settings.delete_unused_networks' => 'Delete Unused Networks', ]; public function mount(Server $server) @@ -100,10 +86,6 @@ public function mount(Server $server) $this->server = $server; $this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray(); $this->wildcard_domain = $this->server->settings->wildcard_domain; - $this->server->settings->docker_cleanup_threshold = $this->server->settings->docker_cleanup_threshold; - $this->server->settings->docker_cleanup_frequency = $this->server->settings->docker_cleanup_frequency; - $this->server->settings->delete_unused_volumes = $server->settings->delete_unused_volumes; - $this->server->settings->delete_unused_networks = $server->settings->delete_unused_networks; } public function checkSyncStatus() @@ -179,7 +161,6 @@ public function updatedServerSettingsIsMetricsEnabled() $this->restartSentinel(); } - public function instantSave() { try { @@ -218,6 +199,7 @@ public function instantSave() } catch (\Throwable $e) { $this->server->settings->refresh(); + return handleError($e, $this); } } @@ -255,7 +237,7 @@ public function checkLocalhostConnection() $this->server->settings->save(); $this->dispatch('proxyStatusUpdated'); } else { - $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: ' . $error); + $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: '.$error); return; } From 6545d04c465efe2d4a25f84ee195d1b8d6919457 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 15:50:43 +0200 Subject: [PATCH 079/120] Refactor Livewire Server Advanced and Form components --- app/Livewire/Server/Advanced.php | 16 ++++++++++ app/Livewire/Server/Form.php | 53 +++----------------------------- 2 files changed, 21 insertions(+), 48 deletions(-) diff --git a/app/Livewire/Server/Advanced.php b/app/Livewire/Server/Advanced.php index 0103ac5f6..b8003803a 100644 --- a/app/Livewire/Server/Advanced.php +++ b/app/Livewire/Server/Advanced.php @@ -2,12 +2,14 @@ namespace App\Livewire\Server; +use App\Jobs\DockerCleanupJob; use App\Models\Server; use Livewire\Component; class Advanced extends Component { public Server $server; + protected $rules = [ 'server.settings.concurrent_builds' => 'required|integer|min:1', 'server.settings.dynamic_timeout' => 'required|integer|min:1', @@ -28,6 +30,7 @@ class Advanced extends Component 'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', 'server.settings.delete_unused_networks' => 'Delete Unused Networks', ]; + public function instantSave() { try { @@ -37,9 +40,21 @@ public function instantSave() $this->dispatch('refreshServerShow'); } catch (\Throwable $e) { $this->server->settings->refresh(); + return handleError($e, $this); } } + + public function manualCleanup() + { + try { + DockerCleanupJob::dispatch($this->server, true); + $this->dispatch('success', 'Manual cleanup job started. Depending on the amount of data, this might take a while.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function submit() { try { @@ -54,6 +69,7 @@ public function submit() return handleError($e, $this); } } + public function render() { return view('livewire.server.advanced'); diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 109306e54..a2f04074a 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -4,8 +4,6 @@ use App\Actions\Server\StartSentinel; use App\Actions\Server\StopSentinel; -use App\Jobs\DockerCleanupJob; -use App\Jobs\PullSentinelImageJob; use App\Models\Server; use Livewire\Component; @@ -172,30 +170,7 @@ public function instantSave() $this->server->save(); $this->dispatch('success', 'Server updated.'); $this->dispatch('refreshServerShow'); - - // if ($this->server->isSentinelEnabled()) { - // StartSentinel::run($this->server); - // } else { - // StopSentinel::run($this->server); - // $this->server->settings->is_metrics_enabled = false; - // $this->server->settings->save(); - // $this->server->sentinelHeartbeat(isReset: true); - // } - // if ($this->server->isSentinelEnabled()) { - // PullSentinelImageJob::dispatchSync($this->server); - // ray('Sentinel is enabled'); - // if ($this->server->settings->isDirty('is_metrics_enabled')) { - // $this->dispatch('reloadWindow'); - // } - // if ($this->server->settings->isDirty('is_sentinel_enabled') && $this->server->settings->is_sentinel_enabled === true) { - // ray('Starting sentinel'); - // } - // } else { - // ray('Sentinel is not enabled'); - // StopSentinel::dispatch($this->server); - // } $this->server->settings->save(); - // $this->checkPortForServerApi(); } catch (\Throwable $e) { $this->server->settings->refresh(); @@ -272,11 +247,11 @@ public function submit() } refresh_server_connection($this->server->privateKey); $this->server->settings->wildcard_domain = $this->wildcard_domain; - if ($this->server->settings->force_docker_cleanup) { - $this->server->settings->docker_cleanup_frequency = $this->server->settings->docker_cleanup_frequency; - } else { - $this->server->settings->docker_cleanup_threshold = $this->server->settings->docker_cleanup_threshold; - } + // if ($this->server->settings->force_docker_cleanup) { + // $this->server->settings->docker_cleanup_frequency = $this->server->settings->docker_cleanup_frequency; + // } else { + // $this->server->settings->docker_cleanup_threshold = $this->server->settings->docker_cleanup_threshold; + // } $currentTimezone = $this->server->settings->getOriginal('server_timezone'); $newTimezone = $this->server->settings->server_timezone; if ($currentTimezone !== $newTimezone || $currentTimezone === '') { @@ -290,22 +265,4 @@ public function submit() return handleError($e, $this); } } - - public function manualCleanup() - { - try { - DockerCleanupJob::dispatch($this->server, true); - $this->dispatch('success', 'Manual cleanup job started. Depending on the amount of data, this might take a while.'); - } catch (\Throwable $e) { - return handleError($e, $this); - } - } - - public function manualCloudflareConfig() - { - $this->server->settings->is_cloudflare_tunnel = true; - $this->server->settings->save(); - $this->server->refresh(); - $this->dispatch('success', 'Cloudflare Tunnels enabled.'); - } } From 192677d05aaf72456497f8ecf98c1c1c39aad23c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 16:30:18 +0200 Subject: [PATCH 080/120] Refactor .env.development.example file --- .env.development.example | 3 --- 1 file changed, 3 deletions(-) diff --git a/.env.development.example b/.env.development.example index 00098446c..9419492fe 100644 --- a/.env.development.example +++ b/.env.development.example @@ -8,9 +8,6 @@ APP_PORT=8000 APP_DEBUG=true SSH_MUX_ENABLED=true -# Enable Laravel Telescope for debugging -TELESCOPE_ENABLED=false - # Selenium Driver URL for Dusk DUSK_DRIVER_URL=http://selenium:4444 DUSK_EMAIL=test@example.com From 4572bf0fbad98b685f4ab0639602c6490b10de6c Mon Sep 17 00:00:00 2001 From: Nathan James Date: Thu, 17 Oct 2024 17:44:05 +0100 Subject: [PATCH 081/120] change heading to match others --- resources/views/livewire/settings/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php index f9293e7d7..7128a2477 100644 --- a/resources/views/livewire/settings/index.blade.php +++ b/resources/views/livewire/settings/index.blade.php @@ -95,7 +95,7 @@ class="px-4 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-coolgray-300 tex
-
Update
+

Update

@if (!is_null(env('AUTOUPDATE', null)))
From becaf92fd8992745fcef6bd649cc988c9615bfc8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:15:48 +0200 Subject: [PATCH 082/120] test dusk gh --- .env.development.example | 5 --- .env.dusk.ci | 15 +++++++ .github/workflows/browser-tests.yml | 65 +++++++++++++++++++++++++++++ tests/Browser/LoginTest.php | 8 ++-- tests/DuskTestCase.php | 56 ++----------------------- tests/How_To_Use_Dusk.md | 53 ----------------------- 6 files changed, 88 insertions(+), 114 deletions(-) create mode 100644 .env.dusk.ci create mode 100644 .github/workflows/browser-tests.yml delete mode 100644 tests/How_To_Use_Dusk.md diff --git a/.env.development.example b/.env.development.example index 9419492fe..d4daed4f7 100644 --- a/.env.development.example +++ b/.env.development.example @@ -8,11 +8,6 @@ APP_PORT=8000 APP_DEBUG=true SSH_MUX_ENABLED=true -# Selenium Driver URL for Dusk -DUSK_DRIVER_URL=http://selenium:4444 -DUSK_EMAIL=test@example.com -DUSK_PASSWORD=password - # PostgreSQL Database Configuration DB_DATABASE=coolify DB_USERNAME=coolify diff --git a/.env.dusk.ci b/.env.dusk.ci new file mode 100644 index 000000000..9660de7b4 --- /dev/null +++ b/.env.dusk.ci @@ -0,0 +1,15 @@ +APP_ENV=production +APP_NAME="Coolify Staging" +APP_ID=development +APP_KEY= +APP_URL=http://localhost +APP_PORT=8000 +SSH_MUX_ENABLED=true + +# PostgreSQL Database Configuration +DB_DATABASE=coolify +DB_USERNAME=coolify +DB_PASSWORD=password +DB_HOST=localhost +DB_PORT=5432 + diff --git a/.github/workflows/browser-tests.yml b/.github/workflows/browser-tests.yml new file mode 100644 index 000000000..fd9d17dbb --- /dev/null +++ b/.github/workflows/browser-tests.yml @@ -0,0 +1,65 @@ +name: Dusk +on: + push: + branches: [ "next" ] +jobs: + dusk: + runs-on: ubuntu-latest + + services: + redis: + image: redis + env: + REDIS_HOST: localhost + REDIS_PORT: 6379 + ports: + - 6379:6379 + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v4 + - name: Set up PostgreSQL + run: | + sudo systemctl start postgresql + sudo -u postgres psql -c "CREATE DATABASE coolify;" + sudo -u postgres psql -c "CREATE USER coolify WITH PASSWORD 'password';" + sudo -u postgres psql -c "ALTER ROLE coolify SET client_encoding TO 'utf8';" + sudo -u postgres psql -c "ALTER ROLE coolify SET default_transaction_isolation TO 'read committed';" + sudo -u postgres psql -c "ALTER ROLE coolify SET timezone TO 'UTC';" + sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE coolify TO coolify;" + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + - name: Copy .env + run: cp .env.dusk.ci .env + - name: Install Dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + - name: Generate key + run: php artisan key:generate + - name: Install Chrome binaries + run: php artisan dusk:chrome-driver --detect + - name: Start Chrome Driver + run: ./vendor/laravel/dusk/bin/chromedriver-linux & + - name: Build assets + run: npm install && npm run build + - name: Run Laravel Server + run: php artisan serve --no-reload & + - name: Execute tests + run: php artisan dusk + - name: Upload Screenshots + if: failure() + uses: actions/upload-artifact@v4 + with: + name: screenshots + path: tests/Browser/screenshots + - name: Upload Console Logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: console + path: tests/Browser/console diff --git a/tests/Browser/LoginTest.php b/tests/Browser/LoginTest.php index ffa83d09b..cac9a65fe 100644 --- a/tests/Browser/LoginTest.php +++ b/tests/Browser/LoginTest.php @@ -13,18 +13,20 @@ class LoginTest extends DuskTestCase * Login with the test user and assert that the user is redirected to the dashboard. * * @return void + * * @throws Throwable */ public function testLogin() { - $email = config('testing.dusk_test_email'); - $password = config('testing.dusk_test_password'); + $email = 'test@example.com'; + $password = 'password'; $this->browse(function (Browser $browser) use ($password, $email) { $browser->visit('/login') ->type('email', $email) ->type('password', $password) ->press('Login') - ->assertPathIs('/'); + ->assertPathIs('/') + ->screenshot('login'); }); } } diff --git a/tests/DuskTestCase.php b/tests/DuskTestCase.php index d909d1c21..1e7a3d4b6 100644 --- a/tests/DuskTestCase.php +++ b/tests/DuskTestCase.php @@ -2,74 +2,24 @@ namespace Tests; -use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; -use Illuminate\Support\Collection; use Laravel\Dusk\TestCase as BaseTestCase; abstract class DuskTestCase extends BaseTestCase { use CreatesApplication; - /** - * Prepare for Dusk test execution. - * - * @beforeClass - */ - public static function prepare(): void - { - if (! static::runningInSail()) { - static::startChromeDriver(); - } - } - - /** - * Create the RemoteWebDriver instance. - */ protected function driver(): RemoteWebDriver { - $options = (new ChromeOptions)->addArguments(collect([ - $this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080', - ])->unless($this->hasHeadlessDisabled(), function (Collection $items) { - return $items->merge([ - '--disable-gpu', - '--headless=new', - ]); - })->all()); - return RemoteWebDriver::create( - $_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515', - DesiredCapabilities::chrome()->setCapability( - ChromeOptions::CAPABILITY, - $options - ) + env('DUSK_DRIVER_URL'), + DesiredCapabilities::chrome() ); } - /** - * Determine if the browser window should start maximized. - */ - protected function shouldStartMaximized(): bool - { - return isset($_SERVER['DUSK_START_MAXIMIZED']) || - isset($_ENV['DUSK_START_MAXIMIZED']); - } - - /** - * Determine whether the Dusk command has disabled headless mode. - */ - protected function hasHeadlessDisabled(): bool - { - return isset($_SERVER['DUSK_HEADLESS_DISABLED']) || - isset($_ENV['DUSK_HEADLESS_DISABLED']); - } - protected function baseUrl() { - $app_url = config('app.url'); - $port = config('app.port'); - - return $app_url.':'.$port; + return 'https://staging.heyandras.dev'; } } diff --git a/tests/How_To_Use_Dusk.md b/tests/How_To_Use_Dusk.md deleted file mode 100644 index fc10bff8c..000000000 --- a/tests/How_To_Use_Dusk.md +++ /dev/null @@ -1,53 +0,0 @@ -# How to use Laravel Dusk in local development - -## Pre-requisites - -- Google Chrome installed on your machine (for the Chrome driver) -- everything else is already set up in the project - - -## Running Dusk in local development - -In order to use Laravel Dusk in local development, you need to run these commands: - -```bash -docker exec -it coolify php artisan dusk:chrome-driver --detect -``` - -The chrome driver will be installed under `./vendor/laravel/dusk/bin/chromedriver-linux`. - -Then you need to run the chrome-driver by hand. You can find the driver in the following path: -```bash -docker exec -it coolify ./vendor/laravel/dusk/bin/chromedriver-linux --port=9515 -``` - -### Running the tests on Apple Silicon - -If you are using an Apple Silicon machine, you need to install the Chrome driver locally on your machine with the following command: - -```bash -php artisan dusk:chrome-driver --detect -# then run it with the following command -./vendor/laravel/dusk/bin/chromedriver-mac-arm --port=9515 130 ↵ -``` - -### Running the tests - -Finally, you can run the tests with the following command: -```bash -docker exec -it coolify php artisan dusk -``` - -That's it. You should see the tests running in the terminal. -For proof, you can check the screenshot in the `tests/Browser/screenshots` folder. - -``` - - PASS Tests\Browser\LoginTest - ✓ login 3.63s - - Tests: 1 passed (1 assertions) - Duration: 3.79s - - -``` \ No newline at end of file From 8bb021e62ad653fe470bc9bb18f6f87c57757075 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:18:37 +0200 Subject: [PATCH 083/120] Refactor DuskTestCase to support headless Chrome and maximize window size --- tests/DuskTestCase.php | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/tests/DuskTestCase.php b/tests/DuskTestCase.php index 1e7a3d4b6..4cde3e963 100644 --- a/tests/DuskTestCase.php +++ b/tests/DuskTestCase.php @@ -2,24 +2,59 @@ namespace Tests; +use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; +use Illuminate\Support\Collection; use Laravel\Dusk\TestCase as BaseTestCase; abstract class DuskTestCase extends BaseTestCase { use CreatesApplication; + /** + * Prepare for Dusk test execution. + * + * @beforeClass + */ + public static function prepare(): void + { + if (! static::runningInSail()) { + static::startChromeDriver(); + } + } + + /** + * Create the RemoteWebDriver instance. + */ protected function driver(): RemoteWebDriver { + $options = (new ChromeOptions)->addArguments(collect([ + $this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080', + ])->unless($this->hasHeadlessDisabled(), function (Collection $items) { + return $items->merge([ + '--disable-gpu', + '--headless=new', + ]); + })->all()); + return RemoteWebDriver::create( - env('DUSK_DRIVER_URL'), - DesiredCapabilities::chrome() + 'http://localhost:9515', + DesiredCapabilities::chrome()->setCapability( + ChromeOptions::CAPABILITY, + $options + ) ); } + /** + * Determine if the browser window should start maximized. + */ protected function baseUrl() { - return 'https://staging.heyandras.dev'; + $app_url = config('app.url'); + $port = config('app.port'); + + return $app_url.':'.$port; } } From 8e8752a9372cdb5ba80493ae72ea4d0610d5c3bc Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:20:08 +0200 Subject: [PATCH 084/120] Refactor PostgreSQL setup in browser-tests.yml --- .github/workflows/browser-tests.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/browser-tests.yml b/.github/workflows/browser-tests.yml index fd9d17dbb..42627ca81 100644 --- a/.github/workflows/browser-tests.yml +++ b/.github/workflows/browser-tests.yml @@ -25,12 +25,12 @@ jobs: - name: Set up PostgreSQL run: | sudo systemctl start postgresql - sudo -u postgres psql -c "CREATE DATABASE coolify;" - sudo -u postgres psql -c "CREATE USER coolify WITH PASSWORD 'password';" - sudo -u postgres psql -c "ALTER ROLE coolify SET client_encoding TO 'utf8';" - sudo -u postgres psql -c "ALTER ROLE coolify SET default_transaction_isolation TO 'read committed';" - sudo -u postgres psql -c "ALTER ROLE coolify SET timezone TO 'UTC';" - sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE coolify TO coolify;" + psql -c "CREATE DATABASE coolify;" + psql -c "CREATE USER coolify WITH PASSWORD 'password';" + psql -c "ALTER ROLE coolify SET client_encoding TO 'utf8';" + psql -c "ALTER ROLE coolify SET default_transaction_isolation TO 'read committed';" + psql -c "ALTER ROLE coolify SET timezone TO 'UTC';" + psql -c "GRANT ALL PRIVILEGES ON DATABASE coolify TO coolify;" - name: Setup PHP uses: shivammathur/setup-php@v2 with: From cbff462a5a900e058a4af2157cf6b94cc277a3a3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:20:55 +0200 Subject: [PATCH 085/120] Refactor Chrome Driver port in browser-tests.yml and DuskTestCase.php --- .github/workflows/browser-tests.yml | 2 +- tests/DuskTestCase.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/browser-tests.yml b/.github/workflows/browser-tests.yml index 42627ca81..0c3fdb94e 100644 --- a/.github/workflows/browser-tests.yml +++ b/.github/workflows/browser-tests.yml @@ -44,7 +44,7 @@ jobs: - name: Install Chrome binaries run: php artisan dusk:chrome-driver --detect - name: Start Chrome Driver - run: ./vendor/laravel/dusk/bin/chromedriver-linux & + run: ./vendor/laravel/dusk/bin/chromedriver-linux --port=4444 & - name: Build assets run: npm install && npm run build - name: Run Laravel Server diff --git a/tests/DuskTestCase.php b/tests/DuskTestCase.php index 4cde3e963..d3f7e655c 100644 --- a/tests/DuskTestCase.php +++ b/tests/DuskTestCase.php @@ -39,7 +39,7 @@ protected function driver(): RemoteWebDriver })->all()); return RemoteWebDriver::create( - 'http://localhost:9515', + 'http://localhost:4444', DesiredCapabilities::chrome()->setCapability( ChromeOptions::CAPABILITY, $options From 45729e6e3748fcb5d6cae5610ee17e126431fdf8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:22:09 +0200 Subject: [PATCH 086/120] Refactor PostgreSQL setup in browser-tests.yml --- .github/workflows/browser-tests.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/browser-tests.yml b/.github/workflows/browser-tests.yml index 0c3fdb94e..d8961956f 100644 --- a/.github/workflows/browser-tests.yml +++ b/.github/workflows/browser-tests.yml @@ -25,12 +25,12 @@ jobs: - name: Set up PostgreSQL run: | sudo systemctl start postgresql - psql -c "CREATE DATABASE coolify;" - psql -c "CREATE USER coolify WITH PASSWORD 'password';" - psql -c "ALTER ROLE coolify SET client_encoding TO 'utf8';" - psql -c "ALTER ROLE coolify SET default_transaction_isolation TO 'read committed';" - psql -c "ALTER ROLE coolify SET timezone TO 'UTC';" - psql -c "GRANT ALL PRIVILEGES ON DATABASE coolify TO coolify;" + sudo -u postgres psql -c "CREATE DATABASE coolify;" + sudo -u postgres psql -c "CREATE USER coolify WITH PASSWORD 'password';" + sudo -u postgres psql -c "ALTER ROLE coolify SET client_encoding TO 'utf8';" + sudo -u postgres psql -c "ALTER ROLE coolify SET default_transaction_isolation TO 'read committed';" + sudo -u postgres psql -c "ALTER ROLE coolify SET timezone TO 'UTC';" + sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE coolify TO coolify;" - name: Setup PHP uses: shivammathur/setup-php@v2 with: From 3835dc3fd7d9be1654faf77671859185c53f971b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:26:06 +0200 Subject: [PATCH 087/120] Refactor DuskTestCase.php to use a hardcoded base URL --- tests/DuskTestCase.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/DuskTestCase.php b/tests/DuskTestCase.php index d3f7e655c..98e90fa79 100644 --- a/tests/DuskTestCase.php +++ b/tests/DuskTestCase.php @@ -52,9 +52,6 @@ protected function driver(): RemoteWebDriver */ protected function baseUrl() { - $app_url = config('app.url'); - $port = config('app.port'); - - return $app_url.':'.$port; + return 'http://localhost:8000'; } } From 6220172f7058fb77eddabdd8d0ec5281a015421b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:28:52 +0200 Subject: [PATCH 088/120] Refactor branch filter in browser-tests.yml --- .github/workflows/browser-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/browser-tests.yml b/.github/workflows/browser-tests.yml index d8961956f..b06c9e97c 100644 --- a/.github/workflows/browser-tests.yml +++ b/.github/workflows/browser-tests.yml @@ -1,7 +1,7 @@ name: Dusk on: push: - branches: [ "next" ] + branches: [ "not-existing" ] jobs: dusk: runs-on: ubuntu-latest From a6259d8a52fce8503f5479888c332ab3f5ad15b8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:48:38 +0200 Subject: [PATCH 089/120] Refactor BaseComponent to initialize route parameters in the boot method --- app/Livewire/BaseComponent.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 app/Livewire/BaseComponent.php diff --git a/app/Livewire/BaseComponent.php b/app/Livewire/BaseComponent.php new file mode 100644 index 000000000..ee9fa238f --- /dev/null +++ b/app/Livewire/BaseComponent.php @@ -0,0 +1,20 @@ +parameters = $this->getRouteParameters(); + } + + protected function getRouteParameters() + { + return get_route_parameters(); + } +} From df4e4c2b4ed7681603ff5560e7ca4f8687e3aaa8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:48:43 +0200 Subject: [PATCH 090/120] Refactor Show component to initialize server and remove unused code --- app/Livewire/Server/Show.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/app/Livewire/Server/Show.php b/app/Livewire/Server/Show.php index a5e94a19a..0e07ec0a1 100644 --- a/app/Livewire/Server/Show.php +++ b/app/Livewire/Server/Show.php @@ -2,28 +2,22 @@ namespace App\Livewire\Server; +use App\Livewire\BaseComponent; use App\Models\Server; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; -use Livewire\Component; -class Show extends Component +class Show extends BaseComponent { use AuthorizesRequests; - public ?Server $server = null; - - public $parameters = []; + public Server $server; protected $listeners = ['refreshServerShow']; public function mount() { - $this->parameters = get_route_parameters(); try { - $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); - if (is_null($this->server)) { - return redirect()->route('server.index'); - } + $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->firstOrFail(); } catch (\Throwable $e) { return handleError($e, $this); } From bfa9a8776ec1a114681a8469f307f308742b1f08 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 21:48:47 +0200 Subject: [PATCH 091/120] Refactor handleError function to handle ModelNotFoundException --- bootstrap/helpers/shared.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 14f44ed47..90cec7d69 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -142,6 +142,10 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n return 'Duplicate entry found. Please use a different name.'; } + if ($error instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) { + abort(404); + } + if ($error instanceof Throwable) { $message = $error->getMessage(); } else { @@ -3983,13 +3987,14 @@ function instanceSettings() return InstanceSettings::get(); } -function loadConfigFromGit(string $repository, string $branch, string $base_directory, int $server_id, int $team_id) { +function loadConfigFromGit(string $repository, string $branch, string $base_directory, int $server_id, int $team_id) +{ $server = Server::find($server_id)->where('team_id', $team_id)->first(); - if (!$server) { + if (! $server) { return; } - $uuid = new Cuid2(); + $uuid = new Cuid2; $cloneCommand = "git clone --no-checkout -b $branch $repository ."; $workdir = rtrim($base_directory, '/'); $fileList = collect([".$workdir/coolify.json"]); @@ -4007,13 +4012,13 @@ function loadConfigFromGit(string $repository, string $branch, string $base_dire try { return instant_remote_process($commands, $server); } catch (\Exception $e) { - // continue + // continue } } function loggy($message = null, array $context = []) { - if (!isDev()) { + if (! isDev()) { return; } if (function_exists('ray') && config('app.debug')) { From 513c74a7e31bf529298a80d2ff90e894a3202ef9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 22:00:27 +0200 Subject: [PATCH 092/120] Refactor BaseComponent to remove unused code and initialize route parameters in the boot method --- app/Livewire/BaseComponent.php | 20 -------------------- app/Livewire/Project/DeleteEnvironment.php | 14 +++++++++----- app/Livewire/Server/Show.php | 7 +++++-- 3 files changed, 14 insertions(+), 27 deletions(-) delete mode 100644 app/Livewire/BaseComponent.php diff --git a/app/Livewire/BaseComponent.php b/app/Livewire/BaseComponent.php deleted file mode 100644 index ee9fa238f..000000000 --- a/app/Livewire/BaseComponent.php +++ /dev/null @@ -1,20 +0,0 @@ -parameters = $this->getRouteParameters(); - } - - protected function getRouteParameters() - { - return get_route_parameters(); - } -} diff --git a/app/Livewire/Project/DeleteEnvironment.php b/app/Livewire/Project/DeleteEnvironment.php index e01741770..6d8c3aff7 100644 --- a/app/Livewire/Project/DeleteEnvironment.php +++ b/app/Livewire/Project/DeleteEnvironment.php @@ -7,18 +7,22 @@ class DeleteEnvironment extends Component { - public array $parameters; - public int $environment_id; public bool $disabled = false; public string $environmentName = ''; + public array $parameters; + public function mount() { - $this->parameters = get_route_parameters(); - $this->environmentName = Environment::findOrFail($this->environment_id)->name; + try { + $this->environmentName = Environment::findOrFail($this->environment_id)->name; + $this->parameters = get_route_parameters(); + } catch (\Exception $e) { + return handleError($e, $this); + } } public function delete() @@ -30,7 +34,7 @@ public function delete() if ($environment->isEmpty()) { $environment->delete(); - return redirect()->route('project.show', ['project_uuid' => $this->parameters['project_uuid']]); + return redirect()->route('project.show', parameters: ['project_uuid' => $this->parameters['project_uuid']]); } return $this->dispatch('error', 'Environment has defined resources, please delete them first.'); diff --git a/app/Livewire/Server/Show.php b/app/Livewire/Server/Show.php index 0e07ec0a1..85c5f95f8 100644 --- a/app/Livewire/Server/Show.php +++ b/app/Livewire/Server/Show.php @@ -2,22 +2,25 @@ namespace App\Livewire\Server; -use App\Livewire\BaseComponent; use App\Models\Server; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; +use Livewire\Component; -class Show extends BaseComponent +class Show extends Component { use AuthorizesRequests; public Server $server; + public array $parameters; + protected $listeners = ['refreshServerShow']; public function mount() { try { $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->firstOrFail(); + $this->parameters = get_route_parameters(); } catch (\Throwable $e) { return handleError($e, $this); } From 9044c655b884b25f843a44bf4cf4cfe53066eb42 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 22:06:48 +0200 Subject: [PATCH 093/120] Refactor Show component to use firstOrFail method when retrieving server by UUID --- app/Livewire/Server/Proxy/Show.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/Livewire/Server/Proxy/Show.php b/app/Livewire/Server/Proxy/Show.php index d70e44e55..5ecb56a69 100644 --- a/app/Livewire/Server/Proxy/Show.php +++ b/app/Livewire/Server/Proxy/Show.php @@ -22,10 +22,7 @@ public function mount() { $this->parameters = get_route_parameters(); try { - $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first(); - if (is_null($this->server)) { - return redirect()->route('server.index'); - } + $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->firstOrFail(); } catch (\Throwable $e) { return handleError($e, $this); } From b75c2dc604960723f6c00911c35e7ca7eac0d9d7 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 17 Oct 2024 22:08:23 +0200 Subject: [PATCH 094/120] pint --- app/Actions/Application/GenerateConfig.php | 1 + app/Actions/Server/StartSentinel.php | 3 +- app/Actions/Server/StopSentinel.php | 1 - app/Livewire/Project/Application/General.php | 8 ++-- .../Project/New/PublicGitRepository.php | 1 + app/Livewire/Project/Service/EditDomain.php | 3 ++ app/Livewire/Project/Service/Navbar.php | 2 +- .../Service/ServiceApplicationView.php | 7 ++-- app/Livewire/Project/Shared/UploadConfig.php | 8 +++- app/Livewire/Server/CloudflareTunnels.php | 1 - app/Livewire/Server/Delete.php | 1 + app/Livewire/Server/ShowPrivateKey.php | 3 +- app/Livewire/Settings/Index.php | 3 +- app/Models/ScheduledDatabaseBackup.php | 1 - app/Models/Server.php | 38 ++++++++++--------- app/Models/ServerSetting.php | 13 ++++--- app/Models/Service.php | 8 ++-- bootstrap/helpers/docker.php | 11 +++--- 18 files changed, 62 insertions(+), 51 deletions(-) diff --git a/app/Actions/Application/GenerateConfig.php b/app/Actions/Application/GenerateConfig.php index 69365f921..d38f9c28b 100644 --- a/app/Actions/Application/GenerateConfig.php +++ b/app/Actions/Application/GenerateConfig.php @@ -12,6 +12,7 @@ class GenerateConfig public function handle(Application $application, bool $is_json = false) { ray()->clearAll(); + return $application->generateConfig(is_json: $is_json); } } diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php index cca8138b9..119513002 100644 --- a/app/Actions/Server/StartSentinel.php +++ b/app/Actions/Server/StartSentinel.php @@ -2,7 +2,6 @@ namespace App\Actions\Server; -use App\Models\InstanceSettings; use App\Models\Server; use Lorisleiva\Actions\Concerns\AsAction; @@ -38,7 +37,7 @@ public function handle(Server $server, $version = 'next', bool $restart = false) $mount_dir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/sentinel'; // $image = 'sentinel'; } - $docker_environments = '-e "' . implode('" -e "', array_map(fn($key, $value) => "$key=$value", array_keys($environments), $environments)) . '"'; + $docker_environments = '-e "'.implode('" -e "', array_map(fn ($key, $value) => "$key=$value", array_keys($environments), $environments)).'"'; $docker_command = "docker run -d $docker_environments --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v $mount_dir:/app/db --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 --add-host=host.docker.internal:host-gateway $image"; diff --git a/app/Actions/Server/StopSentinel.php b/app/Actions/Server/StopSentinel.php index edb6843af..aecb96c87 100644 --- a/app/Actions/Server/StopSentinel.php +++ b/app/Actions/Server/StopSentinel.php @@ -3,7 +3,6 @@ namespace App\Actions\Server; use App\Models\Server; -use Carbon\Carbon; use Lorisleiva\Actions\Concerns\AsAction; class StopSentinel diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index 2e327d80f..096e18617 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -241,7 +241,6 @@ public function updatedApplicationBaseDirectory() } } - public function updatedApplicationBuildPack() { if ($this->application->build_pack !== 'nixpacks') { @@ -314,7 +313,7 @@ public function checkFqdns($showToaster = true) public function set_redirect() { try { - $has_www = collect($this->application->fqdns)->filter(fn($fqdn) => str($fqdn)->contains('www.'))->count(); + $has_www = collect($this->application->fqdns)->filter(fn ($fqdn) => str($fqdn)->contains('www.'))->count(); if ($has_www === 0 && $this->application->redirect === 'www') { $this->dispatch('error', 'You want to redirect to www, but you do not have a www domain set.

Please add www to your domain list and as an A DNS record (if applicable).'); @@ -335,6 +334,7 @@ public function submit($showToaster = true) $this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim(); $this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) { Url::fromString($domain, ['http', 'https']); + return str($domain)->trim()->lower(); }); $this->application->fqdn = $this->application->fqdn->unique()->implode(','); @@ -409,11 +409,13 @@ public function submit($showToaster = true) if ($originalFqdn !== $this->application->fqdn) { $this->application->fqdn = $originalFqdn; } + return handleError($e, $this); } finally { $this->dispatch('configurationChanged'); } } + public function downloadConfig() { $config = GenerateConfig::run($this->application, true); @@ -423,7 +425,7 @@ public function downloadConfig() echo $config; }, $fileName, [ 'Content-Type' => 'application/json', - 'Content-Disposition' => 'attachment; filename=' . $fileName, + 'Content-Disposition' => 'attachment; filename='.$fileName, ]); } } diff --git a/app/Livewire/Project/New/PublicGitRepository.php b/app/Livewire/Project/New/PublicGitRepository.php index 971d4700b..a6601a898 100644 --- a/app/Livewire/Project/New/PublicGitRepository.php +++ b/app/Livewire/Project/New/PublicGitRepository.php @@ -317,6 +317,7 @@ public function submit() // $application->setConfig($config); // } } + return redirect()->route('project.application.configuration', [ 'application_uuid' => $application->uuid, 'environment_name' => $environment->name, diff --git a/app/Livewire/Project/Service/EditDomain.php b/app/Livewire/Project/Service/EditDomain.php index 4138f720e..b7ef978a8 100644 --- a/app/Livewire/Project/Service/EditDomain.php +++ b/app/Livewire/Project/Service/EditDomain.php @@ -21,6 +21,7 @@ public function mount() { $this->application = ServiceApplication::find($this->applicationId); } + public function submit() { try { @@ -28,6 +29,7 @@ public function submit() $this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim(); $this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) { Url::fromString($domain, ['http', 'https']); + return str($domain)->trim()->lower(); }); $this->application->fqdn = $this->application->fqdn->unique()->implode(','); @@ -48,6 +50,7 @@ public function submit() if ($originalFqdn !== $this->application->fqdn) { $this->application->fqdn = $originalFqdn; } + return handleError($e, $this); } } diff --git a/app/Livewire/Project/Service/Navbar.php b/app/Livewire/Project/Service/Navbar.php index fa76ee26f..7db6d9834 100644 --- a/app/Livewire/Project/Service/Navbar.php +++ b/app/Livewire/Project/Service/Navbar.php @@ -39,7 +39,7 @@ public function getListeners() return [ "echo-private:user.{$userId},ServiceStatusChanged" => 'serviceStarted', - "envsUpdated" => '$refresh', + 'envsUpdated' => '$refresh', ]; } diff --git a/app/Livewire/Project/Service/ServiceApplicationView.php b/app/Livewire/Project/Service/ServiceApplicationView.php index ba37313fd..23caa9f72 100644 --- a/app/Livewire/Project/Service/ServiceApplicationView.php +++ b/app/Livewire/Project/Service/ServiceApplicationView.php @@ -30,10 +30,7 @@ class ServiceApplicationView extends Component 'application.is_stripprefix_enabled' => 'nullable|boolean', ]; - public function updatedApplicationFqdn() - { - - } + public function updatedApplicationFqdn() {} public function instantSave() { @@ -82,6 +79,7 @@ public function submit() $this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim(); $this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) { Url::fromString($domain, ['http', 'https']); + return str($domain)->trim()->lower(); }); $this->application->fqdn = $this->application->fqdn->unique()->implode(','); @@ -101,6 +99,7 @@ public function submit() if ($originalFqdn !== $this->application->fqdn) { $this->application->fqdn = $originalFqdn; } + return handleError($e, $this); } } diff --git a/app/Livewire/Project/Shared/UploadConfig.php b/app/Livewire/Project/Shared/UploadConfig.php index dea842651..3859b387a 100644 --- a/app/Livewire/Project/Shared/UploadConfig.php +++ b/app/Livewire/Project/Shared/UploadConfig.php @@ -8,8 +8,11 @@ class UploadConfig extends Component { public $config; + public $applicationId; - public function mount() { + + public function mount() + { if (isDev()) { $this->config = '{ "build_pack": "nixpacks", @@ -22,6 +25,7 @@ public function mount() { }'; } } + public function uploadConfig() { try { @@ -30,10 +34,12 @@ public function uploadConfig() $this->dispatch('success', 'Application settings updated'); } catch (\Exception $e) { $this->dispatch('error', $e->getMessage()); + return; } } + public function render() { return view('livewire.project.shared.upload-config'); diff --git a/app/Livewire/Server/CloudflareTunnels.php b/app/Livewire/Server/CloudflareTunnels.php index 5b0f43329..82bc789db 100644 --- a/app/Livewire/Server/CloudflareTunnels.php +++ b/app/Livewire/Server/CloudflareTunnels.php @@ -29,7 +29,6 @@ public function instantSave() } } - public function manualCloudflareConfig() { $this->server->settings->is_cloudflare_tunnel = true; diff --git a/app/Livewire/Server/Delete.php b/app/Livewire/Server/Delete.php index 0c1fa2745..6fa92198d 100644 --- a/app/Livewire/Server/Delete.php +++ b/app/Livewire/Server/Delete.php @@ -30,6 +30,7 @@ public function delete($password) } $this->server->delete(); DeleteServer::dispatch($this->server); + return redirect()->route('server.index'); } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Livewire/Server/ShowPrivateKey.php b/app/Livewire/Server/ShowPrivateKey.php index 1be22882d..b76c0a405 100644 --- a/app/Livewire/Server/ShowPrivateKey.php +++ b/app/Livewire/Server/ShowPrivateKey.php @@ -47,6 +47,7 @@ public function checkConnection() $this->dispatch('success', 'Server is reachable.'); } else { $this->dispatch('error', 'Server is not reachable.

Check this documentation for further help.

Error: '.$error); + return; } } catch (\Throwable $e) { @@ -56,6 +57,4 @@ public function checkConnection() $this->server->refresh(); } } - - } diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php index eb492e691..f60c454f0 100644 --- a/app/Livewire/Settings/Index.php +++ b/app/Livewire/Settings/Index.php @@ -28,6 +28,7 @@ class Index extends Component protected string $dynamic_config_path = '/data/coolify/proxy/dynamic'; protected Server $server; + public $timezones; protected $rules = [ @@ -57,7 +58,6 @@ class Index extends Component 'settings.instance_timezone' => 'Instance Timezone', ]; - public function mount() { if (isInstanceAdmin()) { @@ -171,7 +171,6 @@ public function checkManually() } } - public function render() { return view('livewire.settings.index'); diff --git a/app/Models/ScheduledDatabaseBackup.php b/app/Models/ScheduledDatabaseBackup.php index 3921e32e4..473fc7b4b 100644 --- a/app/Models/ScheduledDatabaseBackup.php +++ b/app/Models/ScheduledDatabaseBackup.php @@ -51,7 +51,6 @@ public function server() } } - return null; } } diff --git a/app/Models/Server.php b/app/Models/Server.php index 2468fc2b4..04380fad9 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -169,7 +169,7 @@ public function proxySet() public function setupDefault404Redirect() { - $dynamic_conf_path = $this->proxyPath() . '/dynamic'; + $dynamic_conf_path = $this->proxyPath().'/dynamic'; $proxy_type = $this->proxyType(); $redirect_url = $this->proxy->redirect_url; if ($proxy_type === ProxyTypes::TRAEFIK->value) { @@ -183,8 +183,8 @@ public function setupDefault404Redirect() respond 404 }'; $conf = - "# This file is automatically generated by Coolify.\n" . - "# Do not edit it manually (only if you know what are you doing).\n\n" . + "# This file is automatically generated by Coolify.\n". + "# Do not edit it manually (only if you know what are you doing).\n\n". $conf; $base64 = base64_encode($conf); instant_remote_process([ @@ -246,8 +246,8 @@ public function setupDefault404Redirect() ]; $conf = Yaml::dump($dynamic_conf, 12, 2); $conf = - "# This file is automatically generated by Coolify.\n" . - "# Do not edit it manually (only if you know what are you doing).\n\n" . + "# This file is automatically generated by Coolify.\n". + "# Do not edit it manually (only if you know what are you doing).\n\n". $conf; $base64 = base64_encode($conf); @@ -256,8 +256,8 @@ public function setupDefault404Redirect() redir $redirect_url }"; $conf = - "# This file is automatically generated by Coolify.\n" . - "# Do not edit it manually (only if you know what are you doing).\n\n" . + "# This file is automatically generated by Coolify.\n". + "# Do not edit it manually (only if you know what are you doing).\n\n". $conf; $base64 = base64_encode($conf); } @@ -275,7 +275,7 @@ public function setupDefault404Redirect() public function setupDynamicProxyConfiguration() { $settings = instanceSettings(); - $dynamic_config_path = $this->proxyPath() . '/dynamic'; + $dynamic_config_path = $this->proxyPath().'/dynamic'; if ($this->proxyType() === ProxyTypes::TRAEFIK->value) { $file = "$dynamic_config_path/coolify.yaml"; if (empty($settings->fqdn) || (isCloud() && $this->id !== 0) || ! $this->isLocalhost()) { @@ -394,8 +394,8 @@ public function setupDynamicProxyConfiguration() } $yaml = Yaml::dump($traefik_dynamic_conf, 12, 2); $yaml = - "# This file is automatically generated by Coolify.\n" . - "# Do not edit it manually (only if you know what are you doing).\n\n" . + "# This file is automatically generated by Coolify.\n". + "# Do not edit it manually (only if you know what are you doing).\n\n". $yaml; $base64 = base64_encode($yaml); @@ -459,13 +459,13 @@ public function proxyPath() if (isDev()) { $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/caddy'; } else { - $proxy_path = $proxy_path . '/caddy'; + $proxy_path = $proxy_path.'/caddy'; } } elseif ($proxyType === ProxyTypes::NGINX->value) { if (isDev()) { $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/nginx'; } else { - $proxy_path = $proxy_path . '/nginx'; + $proxy_path = $proxy_path.'/nginx'; } } @@ -528,12 +528,12 @@ public function forceDisableServer() Storage::disk('ssh-mux')->delete($this->muxFilename()); } - public function sentinelHeartbeat(bool $isReset = false) { - $this->sentinel_updated_at = $isReset ? now()->subMinutes(6000) : now(); + $this->sentinel_updated_at = $isReset ? now()->subMinutes(6000) : now(); $this->save(); } + public function isSentinelLive() { return Carbon::parse($this->sentinel_updated_at)->isAfter(now()->subMinutes(4)); @@ -541,7 +541,7 @@ public function isSentinelLive() public function isSentinelEnabled() { - return ($this->isMetricsEnabled() || $this->isServerApiEnabled()) && !$this->isBuildServer(); + return ($this->isMetricsEnabled() || $this->isServerApiEnabled()) && ! $this->isBuildServer(); } public function isMetricsEnabled() @@ -611,8 +611,9 @@ public function getCpuMetrics(int $mins = 5) } $cpu = json_decode($cpu, true); $parsedCollection = collect($cpu)->map(function ($metric) { - return [(int)$metric['time'], (float)$metric['percent']]; + return [(int) $metric['time'], (float) $metric['percent']]; }); + return $parsedCollection; } @@ -640,8 +641,8 @@ public function getMemoryMetrics(int $mins = 5) throw new \Exception($error); } $memory = json_decode($memory, true); - $parsedCollection = collect($memory)->map(function ($metric) { - return [(int)$metric['time'], (float)$metric['usedPercent']]; + $parsedCollection = collect($memory)->map(function ($metric) { + return [(int) $metric['time'], (float) $metric['usedPercent']]; }); return $parsedCollection->toArray(); @@ -1092,6 +1093,7 @@ public function status(): bool return true; } + public function validateConnection($isManualCheck = true) { config()->set('constants.ssh.mux_enabled', ! $isManualCheck); diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index 8ef1420e0..b1ed92d95 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -72,7 +72,7 @@ protected static function booted() } } } catch (\Throwable $e) { - loggy('Error creating server setting: ' . $e->getMessage()); + loggy('Error creating server setting: '.$e->getMessage()); } }); } @@ -98,17 +98,18 @@ public function generateSentinelUrl(bool $save = true) $settings = InstanceSettings::get(); if ($this->server->isLocalhost()) { $domain = 'http://host.docker.internal:8000'; - } else if ($settings->fqdn) { + } elseif ($settings->fqdn) { $domain = $settings->fqdn; - } else if ($settings->ipv4) { - $domain = $settings->ipv4 . ':8000'; - } else if ($settings->ipv6) { - $domain = $settings->ipv6 . ':8000'; + } elseif ($settings->ipv4) { + $domain = $settings->ipv4.':8000'; + } elseif ($settings->ipv6) { + $domain = $settings->ipv6.':8000'; } $this->sentinel_custom_url = $domain; if ($save) { $this->save(); } + return $domain; } diff --git a/app/Models/Service.php b/app/Models/Service.php index 16e11ecb6..0af1adf22 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -297,7 +297,7 @@ public function extraFields() 'key' => 'CP_DISABLE_HTTPS', 'value' => data_get($disable_https, 'value'), 'rules' => 'required', - 'customHelper' => "If you want to use https, set this to 0. Variable name: CP_DISABLE_HTTPS", + 'customHelper' => 'If you want to use https, set this to 0. Variable name: CP_DISABLE_HTTPS', ], ]); } @@ -997,8 +997,8 @@ public function extraFields() break; case $image->contains('mysql'): $userVariables = ['SERVICE_USER_MYSQL', 'SERVICE_USER_WORDPRESS', 'MYSQL_USER']; - $passwordVariables = ['SERVICE_PASSWORD_MYSQL', 'SERVICE_PASSWORD_WORDPRESS', 'MYSQL_PASSWORD','SERVICE_PASSWORD_64_MYSQL']; - $rootPasswordVariables = ['SERVICE_PASSWORD_MYSQLROOT', 'SERVICE_PASSWORD_ROOT','SERVICE_PASSWORD_64_MYSQLROOT']; + $passwordVariables = ['SERVICE_PASSWORD_MYSQL', 'SERVICE_PASSWORD_WORDPRESS', 'MYSQL_PASSWORD', 'SERVICE_PASSWORD_64_MYSQL']; + $rootPasswordVariables = ['SERVICE_PASSWORD_MYSQLROOT', 'SERVICE_PASSWORD_ROOT', 'SERVICE_PASSWORD_64_MYSQLROOT']; $dbNameVariables = ['MYSQL_DATABASE']; $mysql_user = $this->environment_variables()->whereIn('key', $userVariables)->first(); $mysql_password = $this->environment_variables()->whereIn('key', $passwordVariables)->first(); @@ -1326,9 +1326,9 @@ protected function isDeployable(): Attribute return false; } } + return true; } ); } - } diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 397bce029..55985b84f 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -335,10 +335,11 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_ if (preg_match('/coolify\.traefik\.middlewares=(.*)/', $item, $matches)) { return explode(',', $matches[1]); } + return null; })->flatten() - ->filter() - ->unique(); + ->filter() + ->unique(); } foreach ($domains as $loop => $domain) { try { @@ -388,7 +389,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_ if ($path !== '/') { // Middleware handling $middlewares = collect([]); - if ($is_stripprefix_enabled && !str($image)->contains('ghost')) { + if ($is_stripprefix_enabled && ! str($image)->contains('ghost')) { $labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}"); $middlewares->push("{$https_label}-stripprefix"); } @@ -402,7 +403,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_ $labels = $labels->merge($redirect_to_non_www); $middlewares->push($to_non_www_name); } - if ($redirect_direction === 'www' && !str($host)->startsWith('www.')) { + if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) { $labels = $labels->merge($redirect_to_www); $middlewares->push($to_www_name); } @@ -417,7 +418,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_ $middlewares = collect([]); if ($is_gzip_enabled) { $middlewares->push('gzip'); - } + } if (str($image)->contains('ghost')) { $middlewares->push('redir-ghost'); } From 56b1faab411ff9f05b2a7957bd725da496f088fe Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Thu, 17 Oct 2024 23:02:57 +0100 Subject: [PATCH 095/120] Fix empty credentials. --- templates/compose/mosquitto.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index 5789bd607..fe983106e 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -13,8 +13,8 @@ services: - "8883:8883" environment: - SERVICE_FQDN_MOSQUITTO - - MQTT_USERNAME=${MQTT_USERNAME:-mosquitto} - - MQTT_PASSWORD=${MQTT_PASSWORD:-mosquitto} + - MQTT_USERNAME=${MQTT_USERNAME} + - MQTT_PASSWORD=${MQTT_PASSWORD} - REQUIRE_CERTIFICATE=${REQUIRE_CERTIFICATE:-false} - ALLOW_ANONYMOUS=${ALLOW_ANONYMOUS:-true} volumes: @@ -31,15 +31,14 @@ services: fi && echo ''require_certificate ''$REQUIRE_CERTIFICATE >> /mosquitto/config/mosquitto.conf && echo ''allow_anonymous ''$ALLOW_ANONYMOUS >> /mosquitto/config/mosquitto.conf && + if [ -n ''$MQTT_USERNAME''] && [ -n ''$MQTT_USERNAME'' ]; then echo ''password_file /mosquitto/config/passwords'' >> /mosquitto/config/mosquitto.conf && touch /mosquitto/config/passwords && - mosquitto_passwd -b -c /mosquitto/config/passwords $MQTT_USERNAME $MQTT_PASSWORD && chmod 0700 /mosquitto/config/passwords && chown root:root /mosquitto/config/passwords && - chown mosquitto:mosquitto /mosquitto/config/passwords && - chmod 0700 /certs/ && - chown root:root /certs/ && - chown mosquitto:mosquitto /certs/ && + mosquitto_passwd -b -c /mosquitto/config/passwords $MQTT_USERNAME $MQTT_PASSWORD && + chown mosquitto:mosquitto /mosquitto/config/passwords; + fi && exec mosquitto -c /mosquitto/config/mosquitto.conf "' labels: From ba91ca4e84e487d8372b8fb43dffb6e57f094d13 Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Fri, 18 Oct 2024 14:50:11 +0100 Subject: [PATCH 096/120] Remove exposed ports. --- templates/compose/mosquitto.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index fe983106e..5f21f395a 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -8,9 +8,6 @@ services: mosquitto: image: eclipse-mosquitto restart: unless-stopped - ports: - - "1883:1883" - - "8883:8883" environment: - SERVICE_FQDN_MOSQUITTO - MQTT_USERNAME=${MQTT_USERNAME} From 972002b5374d6f26ab740d1ac9ee2641bf89844b Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 18 Oct 2024 21:48:16 +0200 Subject: [PATCH 097/120] fix mosquitto --- templates/compose/mosquitto.yaml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index 5f21f395a..e985f3e2d 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -7,16 +7,21 @@ services: mosquitto: image: eclipse-mosquitto - restart: unless-stopped environment: - - SERVICE_FQDN_MOSQUITTO - - MQTT_USERNAME=${MQTT_USERNAME} - - MQTT_PASSWORD=${MQTT_PASSWORD} + - SERVICE_FQDN_MOSQUITTO_1883 + - MQTT_USERNAME=${SERVICE_USER_MOSQUITTO} + - MQTT_PASSWORD=${SERVICE_PASSWORD_MOSQUITTO} - REQUIRE_CERTIFICATE=${REQUIRE_CERTIFICATE:-false} - ALLOW_ANONYMOUS=${ALLOW_ANONYMOUS:-true} volumes: - - "./mosquitto/config:/mosquitto/config" - - "./certs:/certs" + - mosquitto-config:/mosquitto/config + - mosquitto-certs:/certs + healthcheck: + test: ["CMD-SHELL", "exit 0"] + interval: 30s + timeout: 10s + retries: 3 + entrypoint: 'sh -c " if [ ''$REQUIRE_CERTIFICATE'' = ''true'' ]; then echo ''listener 8883'' > /mosquitto/config/mosquitto.conf && @@ -28,17 +33,16 @@ services: fi && echo ''require_certificate ''$REQUIRE_CERTIFICATE >> /mosquitto/config/mosquitto.conf && echo ''allow_anonymous ''$ALLOW_ANONYMOUS >> /mosquitto/config/mosquitto.conf && - if [ -n ''$MQTT_USERNAME''] && [ -n ''$MQTT_USERNAME'' ]; then + if [ -n ''$SERVICE_USER_MOSQUITTO''] && [ -n ''$SERVICE_PASSWORD_MOSQUITTO'' ]; then echo ''password_file /mosquitto/config/passwords'' >> /mosquitto/config/mosquitto.conf && touch /mosquitto/config/passwords && chmod 0700 /mosquitto/config/passwords && chown root:root /mosquitto/config/passwords && - mosquitto_passwd -b -c /mosquitto/config/passwords $MQTT_USERNAME $MQTT_PASSWORD && + mosquitto_passwd -b -c /mosquitto/config/passwords $SERVICE_USER_MOSQUITTO $SERVICE_PASSWORD_MOSQUITTO && chown mosquitto:mosquitto /mosquitto/config/passwords; fi && exec mosquitto -c /mosquitto/config/mosquitto.conf "' labels: - - traefik.enable=true - traefik.tcp.routers.mqtt.entrypoints=mqtt - traefik.tcp.routers.mqtts.entrypoints=mqtts From e301e777c840b744cf4a8a9275fc8c2554705e86 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 18 Oct 2024 21:49:10 +0200 Subject: [PATCH 098/120] Update mosquitto.yaml --- templates/compose/mosquitto.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index e985f3e2d..1ec6f0cdc 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -1,8 +1,8 @@ -# Documentation: https://mosquitto.org/documentation/ -# Slogan: Mosquitto is lightweight and suitable for use on all devices, from low-power single-board computers to full servers. -# Tags: mosquitto, mqtt, open-source -# Logo: svgs/mosquitto.png -# Port: 1883 +# documentation: https://mosquitto.org/documentation/ +# slogan: Mosquitto is lightweight and suitable for use on all devices, from low-power single-board computers to full servers. +# tags: mosquitto, mqtt, open-source +# logo: svgs/mosquitto.svg +# port: 1883 services: mosquitto: From d535eb5d0d40c3de4d831ad14baa1f92a14cf76a Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 18 Oct 2024 21:50:15 +0200 Subject: [PATCH 099/120] Update service-templates.json --- templates/service-templates.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/templates/service-templates.json b/templates/service-templates.json index be67f694a..644864ade 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -1612,6 +1612,19 @@ "minversion": "0.0.0", "port": "8080" }, + "mosquitto": { + "documentation": "https://mosquitto.org/documentation/?utm_source=coolify.io", + "slogan": "Mosquitto is lightweight and suitable for use on all devices, from low-power single-board computers to full servers.", + "compose": "c2VydmljZXM6CiAgbW9zcXVpdHRvOgogICAgaW1hZ2U6IGVjbGlwc2UtbW9zcXVpdHRvCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fTU9TUVVJVFRPXzE4ODMKICAgICAgLSAnTVFUVF9VU0VSTkFNRT0ke1NFUlZJQ0VfVVNFUl9NT1NRVUlUVE99JwogICAgICAtICdNUVRUX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NT1NRVUlUVE99JwogICAgICAtICdSRVFVSVJFX0NFUlRJRklDQVRFPSR7UkVRVUlSRV9DRVJUSUZJQ0FURTotZmFsc2V9JwogICAgICAtICdBTExPV19BTk9OWU1PVVM9JHtBTExPV19BTk9OWU1PVVM6LXRydWV9JwogICAgdm9sdW1lczoKICAgICAgLSAnbW9zcXVpdHRvLWNvbmZpZzovbW9zcXVpdHRvL2NvbmZpZycKICAgICAgLSAnbW9zcXVpdHRvLWNlcnRzOi9jZXJ0cycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgICBlbnRyeXBvaW50OiAic2ggLWMgXCIgaWYgWyAnJFJFUVVJUkVfQ0VSVElGSUNBVEUnID0gJ3RydWUnIF07IHRoZW4gZWNobyAnbGlzdGVuZXIgODg4MycgPiAvbW9zcXVpdHRvL2NvbmZpZy9tb3NxdWl0dG8uY29uZiAmJiBlY2hvICdjYWZpbGUgL2NlcnRzL2NhLmNydCcgPj4gL21vc3F1aXR0by9jb25maWcvbW9zcXVpdHRvLmNvbmYgJiYgZWNobyAnY2VydGZpbGUgL2NlcnRzL3NlcnZlci5jcnQnID4+IC9tb3NxdWl0dG8vY29uZmlnL21vc3F1aXR0by5jb25mICYmIGVjaG8gJ2tleWZpbGUgIC9jZXJ0cy9zZXJ2ZXIua2V5JyA+PiAvbW9zcXVpdHRvL2NvbmZpZy9tb3NxdWl0dG8uY29uZjsgZWxzZSBlY2hvICdsaXN0ZW5lciAxODgzJyA+IC9tb3NxdWl0dG8vY29uZmlnL21vc3F1aXR0by5jb25mOyBmaSAmJiBlY2hvICdyZXF1aXJlX2NlcnRpZmljYXRlICckUkVRVUlSRV9DRVJUSUZJQ0FURSA+PiAvbW9zcXVpdHRvL2NvbmZpZy9tb3NxdWl0dG8uY29uZiAmJiBlY2hvICdhbGxvd19hbm9ueW1vdXMgJyRBTExPV19BTk9OWU1PVVMgPj4gL21vc3F1aXR0by9jb25maWcvbW9zcXVpdHRvLmNvbmYgJiYgaWYgWyAtbiAnJFNFUlZJQ0VfVVNFUl9NT1NRVUlUVE8nXSAmJiBbIC1uICckU0VSVklDRV9QQVNTV09SRF9NT1NRVUlUVE8nIF07IHRoZW4gZWNobyAncGFzc3dvcmRfZmlsZSAvbW9zcXVpdHRvL2NvbmZpZy9wYXNzd29yZHMnID4+IC9tb3NxdWl0dG8vY29uZmlnL21vc3F1aXR0by5jb25mICYmIHRvdWNoIC9tb3NxdWl0dG8vY29uZmlnL3Bhc3N3b3JkcyAmJiBjaG1vZCAwNzAwIC9tb3NxdWl0dG8vY29uZmlnL3Bhc3N3b3JkcyAmJiBjaG93biByb290OnJvb3QgL21vc3F1aXR0by9jb25maWcvcGFzc3dvcmRzICYmIG1vc3F1aXR0b19wYXNzd2QgLWIgLWMgL21vc3F1aXR0by9jb25maWcvcGFzc3dvcmRzICRTRVJWSUNFX1VTRVJfTU9TUVVJVFRPICRTRVJWSUNFX1BBU1NXT1JEX01PU1FVSVRUTyAmJiBjaG93biBtb3NxdWl0dG86bW9zcXVpdHRvIC9tb3NxdWl0dG8vY29uZmlnL3Bhc3N3b3JkczsgZmkgJiYgZXhlYyBtb3NxdWl0dG8gLWMgL21vc3F1aXR0by9jb25maWcvbW9zcXVpdHRvLmNvbmYgXCIiCiAgICBsYWJlbHM6CiAgICAgIC0gdHJhZWZpay50Y3Aucm91dGVycy5tcXR0LmVudHJ5cG9pbnRzPW1xdHQKICAgICAgLSB0cmFlZmlrLnRjcC5yb3V0ZXJzLm1xdHRzLmVudHJ5cG9pbnRzPW1xdHRzCg==", + "tags": [ + "mosquitto", + "mqtt", + "open-source" + ], + "logo": "svgs/mosquitto.svg", + "minversion": "0.0.0", + "port": "1883" + }, "n8n-with-postgresql": { "documentation": "https://n8n.io?utm_source=coolify.io", "slogan": "n8n is an extendable workflow automation tool.", From 5d8a3d0eec19a9d793a558f793db6f39e981dd64 Mon Sep 17 00:00:00 2001 From: Frank Hufnagel Date: Sat, 19 Oct 2024 12:57:29 +0200 Subject: [PATCH 100/120] update openapi spec for healthcheck --- app/Http/Controllers/Api/OtherController.php | 2 +- openapi.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/OtherController.php b/app/Http/Controllers/Api/OtherController.php index 2414b7a42..062cc04e7 100644 --- a/app/Http/Controllers/Api/OtherController.php +++ b/app/Http/Controllers/Api/OtherController.php @@ -160,7 +160,7 @@ public function feedback(Request $request) #[OA\Get( summary: 'Healthcheck', description: 'Healthcheck endpoint.', - path: '/healthcheck', + path: '/health', operationId: 'healthcheck', responses: [ new OA\Response( diff --git a/openapi.yaml b/openapi.yaml index 91d5c1443..1110bfd72 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3093,7 +3093,7 @@ paths: security: - bearerAuth: [] - /healthcheck: + /health: get: summary: Healthcheck description: 'Healthcheck endpoint.' From 55d92e6913edc33b4c41902bc84ba76ae6c05be9 Mon Sep 17 00:00:00 2001 From: Strider27 Date: Sun, 20 Oct 2024 17:52:38 +0100 Subject: [PATCH 101/120] Fixed bookstack.yaml - Added APP_KEY as it was not defined and container was erroring out. - Changed DB_USER and DB_PASS to the correct var's (DB_USERNAME and DB_PASSWORD) - Changed healthcheck from wget to curl, as wget kept getting redirected to the external/local ip and failing instead of loading header from localhost 127.0.0.1. Major props to Darren from the discord server for helping/doing all the work really. Just changing it here so others don't have to mess with it. --- templates/compose/bookstack.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/compose/bookstack.yaml b/templates/compose/bookstack.yaml index 0bfe4f8e9..d6a86dcd9 100644 --- a/templates/compose/bookstack.yaml +++ b/templates/compose/bookstack.yaml @@ -10,13 +10,14 @@ services: environment: - SERVICE_FQDN_BOOKSTACK_80 - APP_URL=${SERVICE_FQDN_BOOKSTACK} + - APP_KEY=${SERVICE_PASSWORD_APPKEY} - PUID=1000 - PGID=1000 - TZ=${TZ:-Europe/Berlin} - DB_HOST=mariadb - DB_PORT=3306 - - DB_USER=${SERVICE_USER_MYSQL} - - DB_PASS=${SERVICE_PASSWORD_MYSQL} + - DB_USERNAME=${SERVICE_USER_MYSQL} + - DB_PASSWORD=${SERVICE_PASSWORD_MYSQL} - DB_DATABASE=${MYSQL_DATABASE:-bookstackapp} - QUEUE_CONNECTION=${QUEUE_CONNECTION} # You will need to set up an authentication provider as described at https://www.bookstackapp.com/docs/admin/third-party-auth/. @@ -27,7 +28,7 @@ services: healthcheck: test: - CMD-SHELL - - 'wget -qO- http://127.0.0.1:80/' + - 'curl -f http://127.0.0.1:80/' interval: 5s timeout: 20s retries: 10 From 0d2584e44eedb9cfa0a18721d233c6da35135a09 Mon Sep 17 00:00:00 2001 From: Strider27 Date: Sun, 20 Oct 2024 19:21:35 +0100 Subject: [PATCH 102/120] Added SMTP mail support variables to bookstack.yaml More info can be seen here https://www.bookstackapp.com/docs/admin/email-webhooks/#email-configuration/ --- templates/compose/bookstack.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/templates/compose/bookstack.yaml b/templates/compose/bookstack.yaml index d6a86dcd9..dd9719471 100644 --- a/templates/compose/bookstack.yaml +++ b/templates/compose/bookstack.yaml @@ -23,6 +23,15 @@ services: # You will need to set up an authentication provider as described at https://www.bookstackapp.com/docs/admin/third-party-auth/. - GITHUB_APP_ID=${GITHUB_APP_ID} - GITHUB_APP_SECRET=${GITHUB_APP_SECRET} + # SMTP Mail variables as per https://www.bookstackapp.com/docs/admin/email-webhooks/#email-configuration/. + - MAIL_DRIVER=${MAIL_DRIVER:-smtp} + - MAIL_HOST=${MAIL_HOST} + - MAIL_PORT=${MAIL_PORT:-587} + - MAIL_ENCRYPTION=${MAIL_ENCRYPTION:-tls} + - MAIL_USERNAME=${MAIL_USERNAME} + - MAIL_PASSWORD=${MAIL_PASSWORD} + - MAIL_FROM=${MAIL_FROM} + - MAIL_FROM_NAME=${MAIL_FROM_NAME:-BookStack} volumes: - 'bookstack-data:/config' healthcheck: From 97aab8ba286355fbabf9fdb46717371cb16706f2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 20 Oct 2024 22:15:31 +0200 Subject: [PATCH 103/120] feat: show warning if people would like to use sslip with https --- app/Livewire/Project/Application/General.php | 7 ++++++- app/Livewire/Project/Service/EditDomain.php | 6 +++++- .../Project/Service/ServiceApplicationView.php | 9 +++++---- bootstrap/helpers/shared.php | 13 ++++++++++++- lang/en.json | 3 ++- .../livewire/project/service/database.blade.php | 1 - 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index 096e18617..9af0c8d8d 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -337,7 +337,12 @@ public function submit($showToaster = true) return str($domain)->trim()->lower(); }); + $this->application->fqdn = $this->application->fqdn->unique()->implode(','); + $warning = sslipDomainWarning($this->application->fqdn); + if ($warning) { + $this->dispatch('warning', __('warning.sslipdomain')); + } $this->resetDefaultLabels(); if ($this->application->isDirty('redirect')) { @@ -403,7 +408,7 @@ public function submit($showToaster = true) } $this->application->custom_labels = base64_encode($this->customLabels); $this->application->save(); - $showToaster && $this->dispatch('success', 'Application settings updated!'); + $showToaster && ! $warning && $this->dispatch('success', 'Application settings updated!'); } catch (\Throwable $e) { $originalFqdn = $this->application->getOriginal('fqdn'); if ($originalFqdn !== $this->application->fqdn) { diff --git a/app/Livewire/Project/Service/EditDomain.php b/app/Livewire/Project/Service/EditDomain.php index b7ef978a8..e89aeda85 100644 --- a/app/Livewire/Project/Service/EditDomain.php +++ b/app/Livewire/Project/Service/EditDomain.php @@ -33,6 +33,10 @@ public function submit() return str($domain)->trim()->lower(); }); $this->application->fqdn = $this->application->fqdn->unique()->implode(','); + $warning = sslipDomainWarning($this->application->fqdn); + if ($warning) { + $this->dispatch('warning', __('warning.sslipdomain')); + } check_domain_usage(resource: $this->application); $this->validate(); $this->application->save(); @@ -40,7 +44,7 @@ public function submit() if (str($this->application->fqdn)->contains(',')) { $this->dispatch('warning', 'Some services do not support multiple domains, which can lead to problems and is NOT RECOMMENDED.

Only use multiple domains if you know what you are doing.'); } else { - $this->dispatch('success', 'Service saved.'); + ! $warning && $this->dispatch('success', 'Service saved.'); } $this->application->service->parse(); $this->dispatch('refresh'); diff --git a/app/Livewire/Project/Service/ServiceApplicationView.php b/app/Livewire/Project/Service/ServiceApplicationView.php index 23caa9f72..fab51d180 100644 --- a/app/Livewire/Project/Service/ServiceApplicationView.php +++ b/app/Livewire/Project/Service/ServiceApplicationView.php @@ -30,8 +30,6 @@ class ServiceApplicationView extends Component 'application.is_stripprefix_enabled' => 'nullable|boolean', ]; - public function updatedApplicationFqdn() {} - public function instantSave() { $this->submit(); @@ -83,7 +81,10 @@ public function submit() return str($domain)->trim()->lower(); }); $this->application->fqdn = $this->application->fqdn->unique()->implode(','); - + $warning = sslipDomainWarning($this->application->fqdn); + if ($warning) { + $this->dispatch('warning', __('warning.sslipdomain')); + } check_domain_usage(resource: $this->application); $this->validate(); $this->application->save(); @@ -91,7 +92,7 @@ public function submit() if (str($this->application->fqdn)->contains(',')) { $this->dispatch('warning', 'Some services do not support multiple domains, which can lead to problems and is NOT RECOMMENDED.

Only use multiple domains if you know what you are doing.'); } else { - $this->dispatch('success', 'Service saved.'); + ! $warning && $this->dispatch('success', 'Service saved.'); } $this->dispatch('generateDockerCompose'); } catch (\Throwable $e) { diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 90cec7d69..cd0eb709a 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -3789,7 +3789,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int service_name: $serviceName, image: $image, predefinedPort: $predefinedPort - )); } } @@ -4030,3 +4029,15 @@ function loggy($message = null, array $context = []) return app('log')->debug($message, $context); } +function sslipDomainWarning(string $domains) +{ + $domains = str($domains)->trim()->explode(','); + $showSslipHttpsWarning = false; + $domains->each(function ($domain) use (&$showSslipHttpsWarning) { + if (str($domain)->contains('https') && str($domain)->contains('sslip')) { + $showSslipHttpsWarning = true; + } + }); + + return $showSslipHttpsWarning; +} diff --git a/lang/en.json b/lang/en.json index fa69c7035..5ea474b02 100644 --- a/lang/en.json +++ b/lang/en.json @@ -33,5 +33,6 @@ "resource.delete_volumes": "Permanently delete all volumes associated with this resource.", "resource.delete_connected_networks": "Permanently delete all non-predefined networks associated with this resource.", "resource.delete_configurations": "Permanently delete all configuration files from the server.", - "database.delete_backups_locally": "All backups will be permanently deleted from local storage." + "database.delete_backups_locally": "All backups will be permanently deleted from local storage.", + "warning.sslipdomain": "Your configuration is saved, but sslip domain with https is NOT recommended, because Let's Encrypt servers with this public domain are rate limited (SSL certificate validation will fail).

Use your own domain instead." } diff --git a/resources/views/livewire/project/service/database.blade.php b/resources/views/livewire/project/service/database.blade.php index de8b522be..c18473a14 100644 --- a/resources/views/livewire/project/service/database.blade.php +++ b/resources/views/livewire/project/service/database.blade.php @@ -17,7 +17,6 @@ label="Image Tag" id="database.image">
- From 6e0ff8bec5089f25c75010f4a4ac0b0d5effb4d9 Mon Sep 17 00:00:00 2001 From: NiftyBit Date: Mon, 21 Oct 2024 05:52:25 +0200 Subject: [PATCH 104/120] Update .env.windows-docker-desktop.example DB_USERNAME variable required for successful installation on self hosted, docker desktop for windows --- .env.windows-docker-desktop.example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.windows-docker-desktop.example b/.env.windows-docker-desktop.example index 02a5a4174..b067b4c5c 100644 --- a/.env.windows-docker-desktop.example +++ b/.env.windows-docker-desktop.example @@ -4,6 +4,7 @@ APP_ID=coolify-windows-docker-desktop APP_NAME=Coolify APP_KEY=base64:ssTlCmrIE/q7whnKMvT6DwURikg69COzGsAwFVROm80= +DB_USERNAME=coolify DB_PASSWORD=coolify REDIS_PASSWORD=coolify From 673ec963e2f28e1a5fe1dd687fe03598c490e841 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 21 Oct 2024 09:51:19 +0200 Subject: [PATCH 105/120] fix: is_static through API --- app/Http/Controllers/Api/ApplicationsController.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index 2a1f846d3..46dd8120e 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -1579,11 +1579,16 @@ public function update_by_uuid(Request $request) $request->offsetUnset('docker_compose_domains'); } $instantDeploy = $request->instant_deploy; + $isStatic = $request->is_static; + $useBuildServer = $request->use_build_server; - $use_build_server = $request->use_build_server; + if (isset($useBuildServer)) { + $application->settings->is_build_server_enabled = $useBuildServer; + $application->settings->save(); + } - if (isset($use_build_server)) { - $application->settings->is_build_server_enabled = $use_build_server; + if (isset($isStatic)) { + $application->settings->is_static = $isStatic; $application->settings->save(); } From bc05070f4c11e8f83b71b26d86369ba72f9ec512 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 21 Oct 2024 11:02:44 +0200 Subject: [PATCH 106/120] Refactor modal-confirmation.blade.php for improved readability and maintainability --- .../components/modal-confirmation.blade.php | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/resources/views/components/modal-confirmation.blade.php b/resources/views/components/modal-confirmation.blade.php index 4dc4e83e7..7cc0dfaa5 100644 --- a/resources/views/components/modal-confirmation.blade.php +++ b/resources/views/components/modal-confirmation.blade.php @@ -159,8 +159,8 @@ class="relative w-auto h-auto">