From 7caf70941381ffe6320875c7c9d147eb08254a37 Mon Sep 17 00:00:00 2001 From: Jere Salonen Date: Tue, 23 Apr 2024 19:59:16 +0200 Subject: [PATCH 001/100] 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/100] 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 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 003/100] 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 @@ abstract class DuskTestCase extends BaseTestCase 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 004/100] 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 67b17e871fe75e04a872da0f06c79ecb6df0aa39 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Thu, 3 Oct 2024 13:26:27 -0400 Subject: [PATCH 005/100] 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 006/100] 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 007/100] 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 008/100] 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 009/100] 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 010/100] 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 @@ class Index extends Component { $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 011/100] 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 012/100] 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 013/100] 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 014/100] 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 de75ae2eb4a1a610729be1864b1004653e20a315 Mon Sep 17 00:00:00 2001 From: Franck Kerbiriou Date: Thu, 29 Aug 2024 15:20:06 +0200 Subject: [PATCH 015/100] Add Calcom template --- public/svgs/calcom.svg | 9 ++++++ templates/compose/calcom.yaml | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 public/svgs/calcom.svg create mode 100644 templates/compose/calcom.yaml diff --git a/public/svgs/calcom.svg b/public/svgs/calcom.svg new file mode 100644 index 000000000..446b16655 --- /dev/null +++ b/public/svgs/calcom.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/templates/compose/calcom.yaml b/templates/compose/calcom.yaml new file mode 100644 index 000000000..ac737f8aa --- /dev/null +++ b/templates/compose/calcom.yaml @@ -0,0 +1,59 @@ +# documentation: https://cal.com/docs +# slogan: Scheduling infrastructure for everyone. +# tags: calcom,calendso,scheduling,open,source +# logo: svgs/calcom.svg +# port: 3000 + +services: + 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:-calendso} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 5s + timeout: 20s + retries: 10 + calcom: + image: calcom.docker.scarf.sh/calcom/cal.com + environment: + # Some variables still uses Calcom previous name, Calendso + # Full list https://github.com/calcom/cal.com/blob/main/.env.example + - SERVICE_FQDN_CALCOM_3000 + - NEXT_PUBLIC_LICENSE_CONSENT=agree + - NODE_ENV=production + - NEXT_PUBLIC_WEBAPP_URL=$SERVICE_FQDN_CALCOM + - NEXT_PUBLIC_API_V2_URL=${SERVICE_FQDN_CALCOM}/api/v2 + # NEXTAUTH_URL=http://localhost:3000/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=$SERVICE_BASE64_CALCOM_SECRET + # 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=$SERVICE_BASE64_CALCOM_KEY + - POSTGRES_USER=$SERVICE_USER_POSTGRES + - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - POSTGRES_DB=${POSTGRES_DB:-calendso} + - DATABASE_HOST=postgresql + - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@${DATABASE_HOST}/${POSTGRES_DB:-calendso} + # Needed to run migrations while using a connection pooler like PgBouncer + # Use the same one as DATABASE_URL if you're not using a connection pooler + - DATABASE_DIRECT_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@${DATABASE_HOST}/${POSTGRES_DB:-calendso} + # GOOGLE_API_CREDENTIALS={} + # Set this to '1' if you don't want Cal to collect anonymous usage + - CALCOM_TELEMETRY_DISABLED=1 + # E-mail settings + # Configures the global From: header whilst sending emails. + - EMAIL_FROM=$EMAIL_FROM + - EMAIL_FROM_NAME=$EMAIL_FROM_NAME + # Configure SMTP settings (@see https://nodemailer.com/smtp/). + - EMAIL_SERVER_HOST=$EMAIL_SERVER_HOST + - EMAIL_SERVER_PORT=$EMAIL_SERVER_PORT + - EMAIL_SERVER_USER=$EMAIL_SERVER_USER + - EMAIL_SERVER_PASSWORD=$EMAIL_SERVER_PASSWORD + - NEXT_PUBLIC_APP_NAME="Cal.com" + depends_on: + - postgresql From 4f76dc835b6b577d03363a1961a6381750c78110 Mon Sep 17 00:00:00 2001 From: Franck Kerbiriou Date: Sat, 12 Oct 2024 14:04:57 -0500 Subject: [PATCH 016/100] Refactor service --- templates/compose/calcom.yaml | 66 ++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/templates/compose/calcom.yaml b/templates/compose/calcom.yaml index ac737f8aa..c7ea7744c 100644 --- a/templates/compose/calcom.yaml +++ b/templates/compose/calcom.yaml @@ -5,55 +5,63 @@ # port: 3000 services: - 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:-calendso} - healthcheck: - test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] - interval: 5s - timeout: 20s - retries: 10 calcom: image: calcom.docker.scarf.sh/calcom/cal.com environment: # Some variables still uses Calcom previous name, Calendso + # # Full list https://github.com/calcom/cal.com/blob/main/.env.example - SERVICE_FQDN_CALCOM_3000 - NEXT_PUBLIC_LICENSE_CONSENT=agree - NODE_ENV=production - - NEXT_PUBLIC_WEBAPP_URL=$SERVICE_FQDN_CALCOM + - NEXT_PUBLIC_WEBAPP_URL=${SERVICE_FQDN_CALCOM} - NEXT_PUBLIC_API_V2_URL=${SERVICE_FQDN_CALCOM}/api/v2 - # NEXTAUTH_URL=http://localhost:3000/api/auth + # https://next-auth.js.org/configuration/options#nextauth_url + # From https://github.com/calcom/docker?tab=readme-ov-file#important-run-time-variables, it should be ${NEXT_PUBLIC_WEBAPP_URL}/api/auth + - 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=$SERVICE_BASE64_CALCOM_SECRET + - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-$SERVICE_BASE64_CALCOM_SECRET} # 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=$SERVICE_BASE64_CALCOM_KEY - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - CALENDSO_ENCRYPTION_KEY=${CALENDSO_ENCRYPTION_KEY:-$SERVICE_BASE64_CALCOM_KEY} + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} - POSTGRES_DB=${POSTGRES_DB:-calendso} - DATABASE_HOST=postgresql - - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@${DATABASE_HOST}/${POSTGRES_DB:-calendso} + - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@${DATABASE_HOST:-postgresql}/${POSTGRES_DB:-calendso} # Needed to run migrations while using a connection pooler like PgBouncer - # Use the same one as DATABASE_URL if you're not using a connection pooler - - DATABASE_DIRECT_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@${DATABASE_HOST}/${POSTGRES_DB:-calendso} + # Use the same one as DATABASE_URL if you are not using a connection pooler + - DATABASE_DIRECT_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@${DATABASE_HOST:-postgresql}/${POSTGRES_DB:-calendso} # GOOGLE_API_CREDENTIALS={} - # Set this to '1' if you don't want Cal to collect anonymous usage + # Set this to 1 if you don't want Cal to collect anonymous usage - CALCOM_TELEMETRY_DISABLED=1 # E-mail settings # Configures the global From: header whilst sending emails. - - EMAIL_FROM=$EMAIL_FROM - - EMAIL_FROM_NAME=$EMAIL_FROM_NAME + - EMAIL_FROM=${EMAIL_FROM} + - EMAIL_FROM_NAME=${EMAIL_FROM_NAME} # Configure SMTP settings (@see https://nodemailer.com/smtp/). - - EMAIL_SERVER_HOST=$EMAIL_SERVER_HOST - - EMAIL_SERVER_PORT=$EMAIL_SERVER_PORT - - EMAIL_SERVER_USER=$EMAIL_SERVER_USER - - EMAIL_SERVER_PASSWORD=$EMAIL_SERVER_PASSWORD + - EMAIL_SERVER_HOST=${EMAIL_SERVER_HOST} + - EMAIL_SERVER_PORT=${EMAIL_SERVER_PORT} + - EMAIL_SERVER_USER=${EMAIL_SERVER_USER} + - EMAIL_SERVER_PASSWORD=${EMAIL_SERVER_PASSWORD} - NEXT_PUBLIC_APP_NAME="Cal.com" + # More info on ALLOWED_HOSTNAMES https://github.com/calcom/cal.com/issues/12201 + - ALLOWED_HOSTNAMES=["${SERVICE_FQDN_CALCOM}"] depends_on: - postgresql + postgresql: + image: postgres:16-alpine + environment: + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_DB=${POSTGRES_DATABASE:-calcom} + volumes: + - calcom-postgresql-data:/var/lib/postgresql/data + healthcheck: + test: + - CMD-SHELL + - pg_isready -U ${SERVICE_USER_POSTGRES} -d ${POSTGRES_DATABASE:-calcom} + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped From eb8dfecfd49d9d3d444a8cb1843ea4b4d00345f1 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 08:22:44 +0200 Subject: [PATCH 017/100] push helper to dockerhub --- .github/workflows/coolify-helper-next.yml | 33 ++++++++++++++++++----- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml index 4add8516e..f46c67375 100644 --- a/.github/workflows/coolify-helper-next.yml +++ b/.github/workflows/coolify-helper-next.yml @@ -8,7 +8,8 @@ on: - docker/coolify-helper/Dockerfile env: - REGISTRY: ghcr.io + GITHUB_REGISTRY: ghcr.io + DOCKER_REGISTRY: docker.io IMAGE_NAME: "coollabsio/coolify-helper" jobs: @@ -19,12 +20,18 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} - name: Get Version id: version run: | @@ -47,12 +54,18 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} - name: Get Version id: version run: | @@ -81,12 +94,18 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to ghcr.io + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} - name: Get Version id: version run: | From 4873779973594407e210f973553fc05b8788c935 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 08:38:03 +0200 Subject: [PATCH 018/100] chore: Update Docker build and push actions to v6 --- .github/workflows/coolify-helper-next.yml | 34 ++++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml index f46c67375..d8d230af5 100644 --- a/.github/workflows/coolify-helper-next.yml +++ b/.github/workflows/coolify-helper-next.yml @@ -20,33 +20,39 @@ jobs: packages: write steps: - uses: actions/checkout@v4 + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to ${{ env.DOCKER_REGISTRY }} uses: docker/login-action@v3 with: registry: ${{ env.DOCKER_REGISTRY }} username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/coolify-helper/Dockerfile platforms: linux/amd64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next labels: | coolify.managed=true + aarch64: runs-on: [ self-hosted, arm64 ] permissions: @@ -54,31 +60,36 @@ jobs: packages: write steps: - uses: actions/checkout@v4 + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to ${{ env.DOCKER_REGISTRY }} uses: docker/login-action@v3 with: registry: ${{ env.DOCKER_REGISTRY }} username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/coolify-helper/Dockerfile platforms: linux/aarch64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 labels: | coolify.managed=true merge-manifest: @@ -110,9 +121,12 @@ jobs: id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Create & publish manifest + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next + docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} + run: | + docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next - uses: sarisia/actions-status-discord@v1 if: always() with: From 3383285415683291d6a3d42e331de5be4c11e6cc Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 08:39:09 +0200 Subject: [PATCH 019/100] chore: Update Docker build and push actions to v6 --- .github/workflows/coolify-helper-next.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml index d8d230af5..d03c42cd7 100644 --- a/.github/workflows/coolify-helper-next.yml +++ b/.github/workflows/coolify-helper-next.yml @@ -52,7 +52,6 @@ jobs: ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next labels: | coolify.managed=true - aarch64: runs-on: [ self-hosted, arm64 ] permissions: From de572762ec144344497684c25d75d145e44a9f99 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 08:41:21 +0200 Subject: [PATCH 020/100] chore: Update Docker build and push actions to v6 --- .github/workflows/coolify-helper-next.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml index d03c42cd7..10602aa6f 100644 --- a/.github/workflows/coolify-helper-next.yml +++ b/.github/workflows/coolify-helper-next.yml @@ -79,7 +79,7 @@ jobs: run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build and Push Image + - name: Build and Push Image uses: docker/build-push-action@v6 with: context: . From bd4f47494c85d29568d855a7cad5b549728116b9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 08:48:20 +0200 Subject: [PATCH 021/100] chore: sync coolify-helper to dockerhub as well --- .github/workflows/coolify-helper.yml | 72 ++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/.github/workflows/coolify-helper.yml b/.github/workflows/coolify-helper.yml index a9e8a5dd0..6e5680879 100644 --- a/.github/workflows/coolify-helper.yml +++ b/.github/workflows/coolify-helper.yml @@ -1,4 +1,4 @@ -name: Coolify Helper Image (v4) +name: Coolify Helper Image on: push: @@ -8,7 +8,8 @@ on: - docker/coolify-helper/Dockerfile env: - REGISTRY: ghcr.io + GITHUB_REGISTRY: ghcr.io + DOCKER_REGISTRY: docker.io IMAGE_NAME: "coollabsio/coolify-helper" jobs: @@ -19,25 +20,36 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/coolify-helper/Dockerfile platforms: linux/amd64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} labels: | coolify.managed=true aarch64: @@ -47,25 +59,36 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | - echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 + echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/coolify-helper/Dockerfile platforms: linux/aarch64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 labels: | coolify.managed=true merge-manifest: @@ -81,19 +104,28 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to ghcr.io + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} - name: Get Version id: version run: | - echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Create & publish manifest + echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} + run: | + docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest - uses: sarisia/actions-status-discord@v1 if: always() with: From 104aa447cc304072eb0d63f37f4001dbd0cc64ae Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 08:52:53 +0200 Subject: [PATCH 022/100] chore: push realtime to dockerhub --- .github/workflows/coolify-realtime-next.yml | 82 ++++++++++++++++----- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml index 33e048627..19f4c690f 100644 --- a/.github/workflows/coolify-realtime-next.yml +++ b/.github/workflows/coolify-realtime-next.yml @@ -1,17 +1,18 @@ -name: Coolify Realtime Development (v4) +name: Coolify Realtime Development on: push: branches: [ "next" ] paths: - - .github/workflows/coolify-realtime.yml + - .github/workflows/coolify-realtime-next.yml - docker/coolify-realtime/Dockerfile - docker/coolify-realtime/terminal-server.js - docker/coolify-realtime/package.json - docker/coolify-realtime/soketi-entrypoint.sh env: - REGISTRY: ghcr.io + GITHUB_REGISTRY: ghcr.io + DOCKER_REGISTRY: docker.io IMAGE_NAME: "coollabsio/coolify-realtime" jobs: @@ -22,27 +23,39 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/coolify-realtime/Dockerfile platforms: linux/amd64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next labels: | coolify.managed=true + aarch64: runs-on: [ self-hosted, arm64 ] permissions: @@ -50,27 +63,39 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/coolify-realtime/Dockerfile platforms: linux/aarch64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 labels: | coolify.managed=true + merge-manifest: runs-on: ubuntu-latest permissions: @@ -80,24 +105,41 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up QEMU uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Create & publish manifest + + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next + docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next + + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} + run: | + docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next + - uses: sarisia/actions-status-discord@v1 if: always() with: - webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }} + webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }} From 953a7d3f1ee8ce39cf5bc8ad32f6f65e73eaa1bc Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 08:53:51 +0200 Subject: [PATCH 023/100] fix --- .github/workflows/coolify-realtime-next.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml index 19f4c690f..ba3e7cdf5 100644 --- a/.github/workflows/coolify-realtime-next.yml +++ b/.github/workflows/coolify-realtime-next.yml @@ -83,7 +83,7 @@ jobs: run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build and Push Image + - name: Build and Push Image uses: docker/build-push-action@v6 with: context: . From ca454b297b066e81e1f807a4902c4ebf0296375c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 08:56:45 +0200 Subject: [PATCH 024/100] fix --- .github/workflows/coolify-realtime-next.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml index ba3e7cdf5..c4ed4707f 100644 --- a/.github/workflows/coolify-realtime-next.yml +++ b/.github/workflows/coolify-realtime-next.yml @@ -143,3 +143,13 @@ jobs: if: always() with: webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }} + + - name: Remote -next and -next-aarch64 images from ${{ env.GITHUB_REGISTRY }} + run: | + docker buildx imagetools rmi ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next + docker buildx imagetools rmi ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 + + - name: Remote -next and -next-aarch64 images from ${{ env.DOCKER_REGISTRY }} + run: | + docker buildx imagetools rmi ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next + docker buildx imagetools rmi ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 From afe94b9059cb484a406c905fa34d38d3d3d4c9a5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:00:50 +0200 Subject: [PATCH 025/100] fix --- .github/workflows/coolify-realtime-next.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml index c4ed4707f..6a5650508 100644 --- a/.github/workflows/coolify-realtime-next.yml +++ b/.github/workflows/coolify-realtime-next.yml @@ -144,12 +144,12 @@ jobs: with: webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }} - - name: Remote -next and -next-aarch64 images from ${{ env.GITHUB_REGISTRY }} + - name: Remove -next and -next-aarch64 images from ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools rmi ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next - docker buildx imagetools rmi ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 + docker manifest rm ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next || true + docker manifest rm ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 || true - - name: Remote -next and -next-aarch64 images from ${{ env.DOCKER_REGISTRY }} + - name: Remove -next and -next-aarch64 images from ${{ env.DOCKER_REGISTRY }} run: | - docker buildx imagetools rmi ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next - docker buildx imagetools rmi ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 + docker manifest rm ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next || true + docker manifest rm ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 || true From a3934750b3f42e26ebcb2fbad059847ee4e7acd5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:08:31 +0200 Subject: [PATCH 026/100] fix realtime-next --- .github/workflows/coolify-realtime-next.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml index 6a5650508..ba3e7cdf5 100644 --- a/.github/workflows/coolify-realtime-next.yml +++ b/.github/workflows/coolify-realtime-next.yml @@ -143,13 +143,3 @@ jobs: if: always() with: webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }} - - - name: Remove -next and -next-aarch64 images from ${{ env.GITHUB_REGISTRY }} - run: | - docker manifest rm ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next || true - docker manifest rm ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 || true - - - name: Remove -next and -next-aarch64 images from ${{ env.DOCKER_REGISTRY }} - run: | - docker manifest rm ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next || true - docker manifest rm ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 || true From 16b33df2e18a8fc6284b82ea04b769902e3262ea Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:08:41 +0200 Subject: [PATCH 027/100] fix: helper push --- .github/workflows/coolify-helper.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/coolify-helper.yml b/.github/workflows/coolify-helper.yml index 6e5680879..664e502b0 100644 --- a/.github/workflows/coolify-helper.yml +++ b/.github/workflows/coolify-helper.yml @@ -104,6 +104,7 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: @@ -116,16 +117,20 @@ jobs: registry: ${{ env.DOCKER_REGISTRY }} username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} run: | docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + - uses: sarisia/actions-status-discord@v1 if: always() with: From 6e5df991226f41a6726d32b477fba2b6e5dca4cd Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:08:51 +0200 Subject: [PATCH 028/100] chore: sync coolify-realtime to dockerhub --- .github/workflows/coolify-realtime.yml | 78 ++++++++++++++++++++------ 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/.github/workflows/coolify-realtime.yml b/.github/workflows/coolify-realtime.yml index 30910ae0b..89ce0f0e8 100644 --- a/.github/workflows/coolify-realtime.yml +++ b/.github/workflows/coolify-realtime.yml @@ -1,4 +1,4 @@ -name: Coolify Realtime (v4) +name: Coolify Realtime on: push: @@ -11,7 +11,8 @@ on: - docker/coolify-realtime/soketi-entrypoint.sh env: - REGISTRY: ghcr.io + GITHUB_REGISTRY: ghcr.io + DOCKER_REGISTRY: docker.io IMAGE_NAME: "coollabsio/coolify-realtime" jobs: @@ -22,27 +23,39 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/coolify-realtime/Dockerfile platforms: linux/amd64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} labels: | coolify.managed=true + aarch64: runs-on: [ self-hosted, arm64 ] permissions: @@ -50,27 +63,39 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/coolify-realtime/Dockerfile platforms: linux/aarch64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 labels: | coolify.managed=true + merge-manifest: runs-on: ubuntu-latest permissions: @@ -80,23 +105,40 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up QEMU uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Create & publish manifest + + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} + run: | + docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + - uses: sarisia/actions-status-discord@v1 if: always() with: From da3ef6a7df50831475a5db967ff5eedb9d679ec1 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:18:17 +0200 Subject: [PATCH 029/100] chore: rename workflows --- ...d-prs.yml => chore-lock-closed-issues-discussions-and-prs.yml} | 0 ...e-issues-and-prs.yml => chore-manage-stale-issues-and-prs.yml} | 0 ...n-close.yml => chore-remove-labels-and-assignees-on-close.yml} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{lock-closed-issues-discussions-and-prs.yml => chore-lock-closed-issues-discussions-and-prs.yml} (100%) rename .github/workflows/{manage-stale-issues-and-prs.yml => chore-manage-stale-issues-and-prs.yml} (100%) rename .github/workflows/{remove-labels-and-assignees-on-close.yml => chore-remove-labels-and-assignees-on-close.yml} (100%) diff --git a/.github/workflows/lock-closed-issues-discussions-and-prs.yml b/.github/workflows/chore-lock-closed-issues-discussions-and-prs.yml similarity index 100% rename from .github/workflows/lock-closed-issues-discussions-and-prs.yml rename to .github/workflows/chore-lock-closed-issues-discussions-and-prs.yml diff --git a/.github/workflows/manage-stale-issues-and-prs.yml b/.github/workflows/chore-manage-stale-issues-and-prs.yml similarity index 100% rename from .github/workflows/manage-stale-issues-and-prs.yml rename to .github/workflows/chore-manage-stale-issues-and-prs.yml diff --git a/.github/workflows/remove-labels-and-assignees-on-close.yml b/.github/workflows/chore-remove-labels-and-assignees-on-close.yml similarity index 100% rename from .github/workflows/remove-labels-and-assignees-on-close.yml rename to .github/workflows/chore-remove-labels-and-assignees-on-close.yml From b72505127c94a99903e5a89efa396c4b56948367 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:18:25 +0200 Subject: [PATCH 030/100] fix --- .github/workflows/coolify-helper-next.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml index 10602aa6f..835d15b9e 100644 --- a/.github/workflows/coolify-helper-next.yml +++ b/.github/workflows/coolify-helper-next.yml @@ -1,4 +1,4 @@ -name: Coolify Helper Image Development (v4) +name: Coolify Helper Image Development on: push: From 765cb7360c3c6b2544ffd82615e93ff0df8b052f Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:19:26 +0200 Subject: [PATCH 031/100] chore: rename development to staging build --- .github/workflows/coolify-staging-build.yml | 133 ++++++++++++++++++++ .github/workflows/development-build.yml | 79 ------------ 2 files changed, 133 insertions(+), 79 deletions(-) create mode 100644 .github/workflows/coolify-staging-build.yml delete mode 100644 .github/workflows/development-build.yml diff --git a/.github/workflows/coolify-staging-build.yml b/.github/workflows/coolify-staging-build.yml new file mode 100644 index 000000000..baffe53d6 --- /dev/null +++ b/.github/workflows/coolify-staging-build.yml @@ -0,0 +1,133 @@ +name: Staging Build + +on: + push: + branches-ignore: ["main", "v3"] + paths-ignore: + - .github/workflows/coolify-helper.yml + - .github/workflows/coolify-helper-next.yml + - .github/workflows/coolify-realtime.yml + - .github/workflows/coolify-realtime-next.yml + - docker/coolify-helper/Dockerfile + - docker/coolify-realtime/Dockerfile + - templates/service-templates.json + +env: + GITHUB_REGISTRY: ghcr.io + DOCKER_REGISTRY: docker.io + IMAGE_NAME: "coollabsio/coolify" + +jobs: + amd64: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Login to ${{ env.GITHUB_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.GITHUB_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Build and Push Image + uses: docker/build-push-action@v6 + with: + context: . + file: docker/prod/Dockerfile + platforms: linux/amd64 + push: true + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} + labels: | + coolify.managed=true + + aarch64: + runs-on: [self-hosted, arm64] + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Login to ${{ env.GITHUB_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.GITHUB_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Build and Push Image + uses: docker/build-push-action@v6 + with: + context: . + file: docker/prod/Dockerfile + platforms: linux/aarch64 + push: true + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 + labels: | + coolify.managed=true + + merge-manifest: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + needs: [amd64, aarch64] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to ${{ env.GITHUB_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.GITHUB_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} + run: | + docker buildx imagetools create \ + --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} + + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} + run: | + docker buildx imagetools create \ + --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} + + - uses: sarisia/actions-status-discord@v1 + if: always() + with: + webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }} diff --git a/.github/workflows/development-build.yml b/.github/workflows/development-build.yml deleted file mode 100644 index 268b885ac..000000000 --- a/.github/workflows/development-build.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: Development Build (v4) - -on: - push: - branches-ignore: ["main", "v3"] - paths-ignore: - - .github/workflows/coolify-helper.yml - - docker/coolify-helper/Dockerfile - -env: - REGISTRY: ghcr.io - IMAGE_NAME: "coollabsio/coolify" - -jobs: - amd64: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Login to ghcr.io - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Build image and push to registry - uses: docker/build-push-action@v5 - with: - context: . - file: docker/prod/Dockerfile - platforms: linux/amd64 - push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} - aarch64: - runs-on: [self-hosted, arm64] - permissions: - contents: read - packages: write - steps: - - uses: actions/checkout@v4 - - name: Login to ghcr.io - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Build image and push to registry - uses: docker/build-push-action@v5 - with: - context: . - file: docker/prod/Dockerfile - platforms: linux/aarch64 - push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 - merge-manifest: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - needs: [amd64, aarch64] - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to ghcr.io - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Create & publish manifest - run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} - - uses: sarisia/actions-status-discord@v1 - if: always() - with: - webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }} From 3459e0b0d19d86989d365e29bda293d472b7351a Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:22:33 +0200 Subject: [PATCH 032/100] chore: sync coolify-testing-host to dockerhbu --- .github/workflows/coolify-testing-host.yml | 85 +++++++++++++++++----- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/.github/workflows/coolify-testing-host.yml b/.github/workflows/coolify-testing-host.yml index 5fdc32991..cd3c72cd9 100644 --- a/.github/workflows/coolify-testing-host.yml +++ b/.github/workflows/coolify-testing-host.yml @@ -1,14 +1,15 @@ -name: Coolify Testing Host (v4-non-prod) +name: Coolify Testing Host on: push: - branches: [ "main", "next" ] + branches: [ "next" ] paths: - .github/workflows/coolify-testing-host.yml - docker/testing-host/Dockerfile env: - REGISTRY: ghcr.io + GITHUB_REGISTRY: ghcr.io + DOCKER_REGISTRY: docker.io IMAGE_NAME: "coollabsio/coolify-testing-host" jobs: @@ -19,21 +20,34 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/testing-host/Dockerfile platforms: linux/amd64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}:latest + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}:latest + labels: | + coolify.managed=true + aarch64: runs-on: [ self-hosted, arm64 ] permissions: @@ -41,21 +55,34 @@ jobs: packages: write steps: - uses: actions/checkout@v4 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build image and push to registry - uses: docker/build-push-action@v5 + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Build and Push Image + uses: docker/build-push-action@v6 with: - no-cache: true context: . file: docker/testing-host/Dockerfile platforms: linux/aarch64 push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64 + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}:latest-aarch64 + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}:latest-aarch64 + labels: | + coolify.managed=true + merge-manifest: runs-on: ubuntu-latest permissions: @@ -65,19 +92,39 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up QEMU uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to ghcr.io + + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Create & publish manifest + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker buildx imagetools create \ + --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64 \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} + run: | + docker buildx imagetools create \ + --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64 \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + - uses: sarisia/actions-status-discord@v1 if: always() with: From 6c2c2ee3478ff3618b4699bf54d84b1a28e385ee Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:27:23 +0200 Subject: [PATCH 033/100] fix: format --- .github/workflows/coolify-helper-next.yml | 19 +++++++++++++++++-- .github/workflows/coolify-helper.yml | 13 +++++++++++-- .github/workflows/coolify-realtime-next.yml | 10 ++++++++-- .github/workflows/coolify-realtime.yml | 10 ++++++++-- .github/workflows/coolify-staging-build.yml | 15 ++++++++------- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml index 835d15b9e..50186b95a 100644 --- a/.github/workflows/coolify-helper-next.yml +++ b/.github/workflows/coolify-helper-next.yml @@ -91,6 +91,7 @@ jobs: ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 labels: | coolify.managed=true + merge-manifest: runs-on: ubuntu-latest permissions: @@ -100,32 +101,46 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up QEMU uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to ${{ env.DOCKER_REGISTRY }} uses: docker/login-action@v3 with: registry: ${{ env.DOCKER_REGISTRY }} username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_TOKEN }} + - name: Get Version id: version run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next + docker buildx imagetools create \ + --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next + docker buildx imagetools create \ + --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next + - uses: sarisia/actions-status-discord@v1 if: always() with: diff --git a/.github/workflows/coolify-helper.yml b/.github/workflows/coolify-helper.yml index 664e502b0..2de4c85ba 100644 --- a/.github/workflows/coolify-helper.yml +++ b/.github/workflows/coolify-helper.yml @@ -100,8 +100,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up QEMU uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -111,6 +113,7 @@ jobs: registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to ${{ env.DOCKER_REGISTRY }} uses: docker/login-action@v3 with: @@ -125,11 +128,17 @@ jobs: - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker buildx imagetools create \ + --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker buildx imagetools create \ + --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest - uses: sarisia/actions-status-discord@v1 if: always() diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml index ba3e7cdf5..d8c6e0aad 100644 --- a/.github/workflows/coolify-realtime-next.yml +++ b/.github/workflows/coolify-realtime-next.yml @@ -133,11 +133,17 @@ jobs: - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next + docker buildx imagetools create \ + --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next + docker buildx imagetools create \ + --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next - uses: sarisia/actions-status-discord@v1 if: always() diff --git a/.github/workflows/coolify-realtime.yml b/.github/workflows/coolify-realtime.yml index 89ce0f0e8..6551bdb0a 100644 --- a/.github/workflows/coolify-realtime.yml +++ b/.github/workflows/coolify-realtime.yml @@ -133,11 +133,17 @@ jobs: - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker buildx imagetools create \ + --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} run: | - docker buildx imagetools create --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker buildx imagetools create \ + --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest - uses: sarisia/actions-status-discord@v1 if: always() diff --git a/.github/workflows/coolify-staging-build.yml b/.github/workflows/coolify-staging-build.yml index baffe53d6..0bab2f3ec 100644 --- a/.github/workflows/coolify-staging-build.yml +++ b/.github/workflows/coolify-staging-build.yml @@ -4,13 +4,14 @@ on: push: branches-ignore: ["main", "v3"] paths-ignore: - - .github/workflows/coolify-helper.yml - - .github/workflows/coolify-helper-next.yml - - .github/workflows/coolify-realtime.yml - - .github/workflows/coolify-realtime-next.yml - - docker/coolify-helper/Dockerfile - - docker/coolify-realtime/Dockerfile - - templates/service-templates.json + - .github/workflows/coolify-helper.yml + - .github/workflows/coolify-helper-next.yml + - .github/workflows/coolify-realtime.yml + - .github/workflows/coolify-realtime-next.yml + - docker/coolify-helper/Dockerfile + - docker/coolify-realtime/Dockerfile + - docker/testing-host/Dockerfile + - templates/service-templates.json env: GITHUB_REGISTRY: ghcr.io From bb168086531737404fa17b7dc3240124de1a2c82 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:28:34 +0200 Subject: [PATCH 034/100] fix --- .github/workflows/coolify-realtime.yml | 2 +- .github/workflows/coolify-staging-build.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coolify-realtime.yml b/.github/workflows/coolify-realtime.yml index 6551bdb0a..7bf406ae6 100644 --- a/.github/workflows/coolify-realtime.yml +++ b/.github/workflows/coolify-realtime.yml @@ -83,7 +83,7 @@ jobs: run: | echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT - - name: Build and Push Image + - name: Build and Push Image uses: docker/build-push-action@v6 with: context: . diff --git a/.github/workflows/coolify-staging-build.yml b/.github/workflows/coolify-staging-build.yml index 0bab2f3ec..2d2da6e75 100644 --- a/.github/workflows/coolify-staging-build.yml +++ b/.github/workflows/coolify-staging-build.yml @@ -102,7 +102,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to ${{ env.GITHUB_REGISTRY }} + - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 with: registry: ${{ env.GITHUB_REGISTRY }} From fb80924a51f85ef3539a4dfaa7619c22bbb74cd7 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:31:32 +0200 Subject: [PATCH 035/100] fix --- .github/workflows/coolify-testing-host.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/coolify-testing-host.yml b/.github/workflows/coolify-testing-host.yml index cd3c72cd9..27c836730 100644 --- a/.github/workflows/coolify-testing-host.yml +++ b/.github/workflows/coolify-testing-host.yml @@ -43,8 +43,8 @@ jobs: platforms: linux/amd64 push: true tags: | - ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}:latest - ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}:latest + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest labels: | coolify.managed=true @@ -78,8 +78,8 @@ jobs: platforms: linux/aarch64 push: true tags: | - ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}:latest-aarch64 - ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}:latest-aarch64 + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64 + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64 labels: | coolify.managed=true From 0a3e1ffbe480dad82ad39c3b12cc0c2a6c0dfbc9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:37:17 +0200 Subject: [PATCH 036/100] chore: sync coolify prod image to dockerhub as well --- .../workflows/coolify-production-build.yml | 148 ++++++++++++++++++ .github/workflows/production-build.yml | 89 ----------- 2 files changed, 148 insertions(+), 89 deletions(-) create mode 100644 .github/workflows/coolify-production-build.yml delete mode 100644 .github/workflows/production-build.yml diff --git a/.github/workflows/coolify-production-build.yml b/.github/workflows/coolify-production-build.yml new file mode 100644 index 000000000..9a63fbb27 --- /dev/null +++ b/.github/workflows/coolify-production-build.yml @@ -0,0 +1,148 @@ +name: Production Build (v4) + +on: + push: + branches: ["main"] + paths-ignore: + - .github/workflows/coolify-helper.yml + - .github/workflows/coolify-helper-next.yml + - .github/workflows/coolify-realtime.yml + - .github/workflows/coolify-realtime-next.yml + - docker/coolify-helper/Dockerfile + - docker/coolify-realtime/Dockerfile + - docker/testing-host/Dockerfile + - templates/service-templates.json + +env: + GITHUB_REGISTRY: ghcr.io + DOCKER_REGISTRY: docker.io + IMAGE_NAME: "coollabsio/coolify" + +jobs: + amd64: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Login to ${{ env.GITHUB_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.GITHUB_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Get Version + id: version + run: | + echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT] + + - name: Build and Push Image + uses: docker/build-push-action@v6 + with: + context: . + file: docker/prod/Dockerfile + platforms: linux/amd64 + push: true + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} + labels: | + coolify.managed=true + + aarch64: + runs-on: [self-hosted, arm64] + steps: + - uses: actions/checkout@v4 + + - name: Login to ${{ env.GITHUB_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.GITHUB_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Get Version + id: version + run: | + echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT] + + - name: Build and Push Image + uses: docker/build-push-action@v6 + with: + context: . + file: docker/prod/Dockerfile + platforms: linux/aarch64 + push: true + tags: | + ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 + ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 + labels: | + coolify.managed=true + + merge-manifest: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + needs: [amd64, aarch64] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to ${{ env.GITHUB_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.GITHUB_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to ${{ env.DOCKER_REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Get Version + id: version + run: | + echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT + + - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }} + run: | + docker buildx imagetools create \ + --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \ + --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }} + run: | + docker buildx imagetools create \ + --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \ + --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + - uses: sarisia/actions-status-discord@v1 + if: always() + with: + webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }} diff --git a/.github/workflows/production-build.yml b/.github/workflows/production-build.yml deleted file mode 100644 index c78c865bf..000000000 --- a/.github/workflows/production-build.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: Production Build (v4) - -on: - push: - branches: ["main"] - paths-ignore: - - .github/workflows/coolify-helper.yml - - docker/coolify-helper/Dockerfile - - templates/service-templates.json - -env: - REGISTRY: ghcr.io - IMAGE_NAME: "coollabsio/coolify" - -jobs: - amd64: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Login to ghcr.io - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Get Version - id: version - run: | - echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 - with: - context: . - file: docker/prod/Dockerfile - platforms: linux/amd64 - push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} - aarch64: - runs-on: [self-hosted, arm64] - steps: - - uses: actions/checkout@v4 - - name: Login to ghcr.io - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Get Version - id: version - run: | - echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT - - name: Build image and push to registry - uses: docker/build-push-action@v5 - with: - context: . - file: docker/prod/Dockerfile - platforms: linux/aarch64 - push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 - merge-manifest: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - needs: [amd64, aarch64] - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to ghcr.io - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Get Version - id: version - run: | - echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT - - name: Create & publish manifest - run: | - docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - - uses: sarisia/actions-status-discord@v1 - if: always() - with: - webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }} From d11a363a204463892a9f68451773f97f28299b66 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:39:16 +0200 Subject: [PATCH 037/100] do we need qemu? nah --- .github/workflows/coolify-helper-next.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml index 50186b95a..4354294b1 100644 --- a/.github/workflows/coolify-helper-next.yml +++ b/.github/workflows/coolify-helper-next.yml @@ -99,14 +99,8 @@ jobs: packages: write needs: [ amd64, aarch64 ] steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 From e99b39d584d53479b154bb5e3c506a9513b16c65 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 09:44:22 +0200 Subject: [PATCH 038/100] remove unnecessary things --- .github/workflows/coolify-helper.yml | 9 ++------- .github/workflows/coolify-production-build.yml | 9 ++------- .github/workflows/coolify-realtime-next.yml | 9 ++------- .github/workflows/coolify-realtime.yml | 9 ++------- .github/workflows/coolify-staging-build.yml | 9 ++------- .github/workflows/coolify-testing-host.yml | 9 ++------- 6 files changed, 12 insertions(+), 42 deletions(-) diff --git a/.github/workflows/coolify-helper.yml b/.github/workflows/coolify-helper.yml index 2de4c85ba..6d852a2b3 100644 --- a/.github/workflows/coolify-helper.yml +++ b/.github/workflows/coolify-helper.yml @@ -98,14 +98,9 @@ jobs: packages: write needs: [ amd64, aarch64 ] steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 diff --git a/.github/workflows/coolify-production-build.yml b/.github/workflows/coolify-production-build.yml index 9a63fbb27..771687d4b 100644 --- a/.github/workflows/coolify-production-build.yml +++ b/.github/workflows/coolify-production-build.yml @@ -100,14 +100,9 @@ jobs: packages: write needs: [amd64, aarch64] steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml index d8c6e0aad..7e937d17a 100644 --- a/.github/workflows/coolify-realtime-next.yml +++ b/.github/workflows/coolify-realtime-next.yml @@ -103,14 +103,9 @@ jobs: packages: write needs: [ amd64, aarch64 ] steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 diff --git a/.github/workflows/coolify-realtime.yml b/.github/workflows/coolify-realtime.yml index 7bf406ae6..97bfd52eb 100644 --- a/.github/workflows/coolify-realtime.yml +++ b/.github/workflows/coolify-realtime.yml @@ -103,14 +103,9 @@ jobs: packages: write needs: [ amd64, aarch64 ] steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 diff --git a/.github/workflows/coolify-staging-build.yml b/.github/workflows/coolify-staging-build.yml index 2d2da6e75..dd5e6ebd6 100644 --- a/.github/workflows/coolify-staging-build.yml +++ b/.github/workflows/coolify-staging-build.yml @@ -93,14 +93,9 @@ jobs: packages: write needs: [amd64, aarch64] steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 diff --git a/.github/workflows/coolify-testing-host.yml b/.github/workflows/coolify-testing-host.yml index 27c836730..95a228114 100644 --- a/.github/workflows/coolify-testing-host.yml +++ b/.github/workflows/coolify-testing-host.yml @@ -90,14 +90,9 @@ jobs: packages: write needs: [ amd64, aarch64 ] steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v3 - name: Login to ${{ env.GITHUB_REGISTRY }} uses: docker/login-action@v3 From c137620b81096fe4afa37a318ff4924a6c6ae335 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 10:29:45 +0200 Subject: [PATCH 039/100] chore: update Docker version to 26.0 --- app/Actions/Server/InstallDocker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php index f671f2d2a..2e1df8185 100644 --- a/app/Actions/Server/InstallDocker.php +++ b/app/Actions/Server/InstallDocker.php @@ -17,7 +17,7 @@ class InstallDocker throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: documentation.'); } ray('Installing Docker on server: '.$server->name.' ('.$server->ip.')'.' with OS type: '.$supported_os_type); - $dockerVersion = '24.0'; + $dockerVersion = '26.0'; $config = base64_encode('{ "log-driver": "json-file", "log-opts": { From 1f193d465d79af918d20a4ac01a1033096347dc2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 12:07:37 +0200 Subject: [PATCH 040/100] sentinel updates --- app/Actions/Server/StartSentinel.php | 27 +++- .../Controllers/Api/ServersController.php | 2 +- app/Jobs/PushServerUpdateJob.php | 53 ++++++++ app/Livewire/Server/Form.php | 45 ++++++- app/Models/Application.php | 2 +- app/Models/InstanceSettings.php | 1 + app/Models/Server.php | 42 +++--- app/Models/ServerSetting.php | 7 +- app/Models/StandaloneClickhouse.php | 2 +- app/Models/StandaloneDragonfly.php | 2 +- app/Models/StandaloneKeydb.php | 2 +- app/Models/StandaloneMariadb.php | 2 +- app/Models/StandaloneMongodb.php | 2 +- app/Models/StandaloneMysql.php | 2 +- app/Models/StandalonePostgresql.php | 2 +- app/Models/StandaloneRedis.php | 2 +- bootstrap/helpers/shared.php | 7 - .../2024_06_18_105948_move_server_metrics.php | 2 +- ...pdate_metrics_token_in_server_settings.php | 38 ++++++ openapi.yaml | 6 +- .../views/livewire/server/form.blade.php | 121 ++++++++++-------- routes/api.php | 25 ++++ scripts/install.sh | 2 +- 23 files changed, 293 insertions(+), 103 deletions(-) create mode 100644 app/Jobs/PushServerUpdateJob.php create mode 100644 database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php index b79bc8f67..4b45d0738 100644 --- a/app/Actions/Server/StartSentinel.php +++ b/app/Actions/Server/StartSentinel.php @@ -2,6 +2,7 @@ namespace App\Actions\Server; +use App\Models\InstanceSettings; use App\Models\Server; use Lorisleiva\Actions\Concerns\AsAction; @@ -16,11 +17,25 @@ class StartSentinel } $metrics_history = $server->settings->metrics_history_days; $refresh_rate = $server->settings->metrics_refresh_rate_seconds; - $token = $server->settings->metrics_token; - instant_remote_process([ - "docker run --rm --pull always -d -e \"TOKEN={$token}\" -e \"SCHEDULER=true\" -e \"METRICS_HISTORY={$metrics_history}\" -e \"REFRESH_RATE={$refresh_rate}\" --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify/metrics:/app/metrics -v /data/coolify/logs:/app/logs --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/metrics /data/coolify/logs', - 'chmod -R 700 /data/coolify/metrics /data/coolify/logs', - ], $server, true); + $token = $server->settings->sentinel_token; + $fqdn = InstanceSettings::get()->fqdn; + if (str($fqdn)->startsWith('http')) { + throw new \Exception('You should use https to run Sentinel.'); + } + $environments = [ + 'TOKEN' => $token, + 'ENDPOINT' => InstanceSettings::get()->fqdn, + 'COLLECTOR_ENABLED' => 'true', + 'COLLECTOR_REFRESH_RATE_SECONDS' => $refresh_rate, + '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); } } diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index a49515579..6d512e578 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -23,7 +23,7 @@ class ServersController extends Controller return serializeApiResponse($settings); } $settings = $settings->makeHidden([ - 'metrics_token', + 'sentinel_token', ]); return serializeApiResponse($settings); diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php new file mode 100644 index 000000000..27aa58201 --- /dev/null +++ b/app/Jobs/PushServerUpdateJob.php @@ -0,0 +1,53 @@ +data) { + throw new \Exception('No data provided'); + } + $data = collect($this->data); + $containers = collect(data_get($data, 'containers')); + if ($containers->isEmpty()) { + return; + } + foreach ($containers as $container) { + $containerStatus = data_get($container, 'status', 'exited'); + $containerHealth = data_get($container, 'health', 'unhealthy'); + $containerStatus = "$containerStatus ($containerHealth)"; + $labels = collect(data_get($container, 'labels')); + if ($labels->has('coolify.applicationId')) { + $applicationId = $labels->get('coolify.applicationId'); + } + Log::info("$applicationId, $containerStatus"); + } + } + + +} diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index fe7fc6020..6efff504b 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -7,6 +7,7 @@ use App\Actions\Server\StopSentinel; use App\Jobs\DockerCleanupJob; use App\Jobs\PullSentinelImageJob; use App\Models\Server; +use Illuminate\Support\Facades\Http; use Livewire\Component; class Form extends Component @@ -54,9 +55,9 @@ class Form extends Component '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.metrics_token' => 'required', - 'server.settings.metrics_refresh_rate_seconds' => 'required|integer|min:1', - 'server.settings.metrics_history_days' => 'required|integer|min:1', + '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', 'wildcard_domain' => 'nullable|url', 'server.settings.is_server_api_enabled' => 'required|boolean', 'server.settings.server_timezone' => 'required|string|timezone', @@ -81,9 +82,9 @@ class Form extends Component 'server.settings.concurrent_builds' => 'Concurrent Builds', 'server.settings.dynamic_timeout' => 'Dynamic Timeout', 'server.settings.is_metrics_enabled' => 'Metrics', - 'server.settings.metrics_token' => 'Metrics Token', - 'server.settings.metrics_refresh_rate_seconds' => 'Metrics Interval', - 'server.settings.metrics_history_days' => 'Metrics History', + '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.server_timezone' => 'Server Timezone', 'server.settings.delete_unused_volumes' => 'Delete Unused Volumes', @@ -100,7 +101,15 @@ class Form extends Component $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() { + try { + $this->server->generateSentinelToken(); + $this->server->settings->refresh(); + $this->dispatch('success', 'Metrics token regenerated.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } public function updated($field) { if ($field === 'server.settings.docker_cleanup_frequency') { @@ -174,6 +183,28 @@ class Form extends Component } } + 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 { diff --git a/app/Models/Application.php b/app/Models/Application.php index 07aeb4c5b..10ef8079c 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -1406,7 +1406,7 @@ class Application extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/app/Models/InstanceSettings.php b/app/Models/InstanceSettings.php index bb3d1478b..3ee142050 100644 --- a/app/Models/InstanceSettings.php +++ b/app/Models/InstanceSettings.php @@ -21,6 +21,7 @@ class InstanceSettings extends Model implements SendsEmail 'is_auto_update_enabled' => 'boolean', 'auto_update_frequency' => 'string', 'update_check_frequency' => 'string', + 'sentinel_token' => 'encrypted', ]; public function fqdn(): Attribute diff --git a/app/Models/Server.php b/app/Models/Server.php index 0eca3c168..cd7667c70 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -17,6 +17,8 @@ use Spatie\SchemalessAttributes\Casts\SchemalessAttributes; use Spatie\SchemalessAttributes\SchemalessAttributesTrait; use Spatie\Url\Url; use Symfony\Component\Yaml\Yaml; +use Illuminate\Support\Str; + #[OA\Schema( description: 'Server model', @@ -166,7 +168,7 @@ class Server extends BaseModel 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 @@ class Server extends BaseModel 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 @@ respond 404 ]; $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 @@ respond 404 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 @@ respond 404 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 @@ respond 404 } $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 @@ $schema://$host { 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'; } } @@ -525,6 +527,17 @@ $schema://$host { Storage::disk('ssh-mux')->delete($this->muxFilename()); } + 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 isSentinelEnabled() { return $this->isMetricsEnabled() || $this->isServerApiEnabled(); @@ -555,7 +568,6 @@ $schema://$host { ray($process->exitCode(), $process->output(), $process->errorOutput()); throw new \Exception("Server API is not reachable on http://{$server_ip}:12172"); } - } } @@ -579,7 +591,7 @@ $schema://$host { { if ($this->isMetricsEnabled()) { $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $cpu = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->metrics_token}\" http://localhost:8888/api/cpu/history?from=$from'"], $this, false); + $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?'); @@ -606,7 +618,7 @@ $schema://$host { { if ($this->isMetricsEnabled()) { $from = now()->subMinutes($mins)->toIso8601ZuluString(); - $memory = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->metrics_token}\" http://localhost:8888/api/memory/history?from=$from'"], $this, false); + $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?'); diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index c44a393b4..f5e0f7b0b 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -35,9 +35,9 @@ use OpenApi\Attributes as OA; 'logdrain_highlight_project_id' => ['type' => 'string'], 'logdrain_newrelic_base_uri' => ['type' => 'string'], 'logdrain_newrelic_license_key' => ['type' => 'string'], - 'metrics_history_days' => ['type' => 'integer'], - 'metrics_refresh_rate_seconds' => ['type' => 'integer'], - 'metrics_token' => ['type' => 'string'], + 'sentinel_metrics_history_days' => ['type' => 'integer'], + 'sentinel_metrics_refresh_rate_seconds' => ['type' => 'integer'], + 'sentinel_token' => ['type' => 'string'], 'docker_cleanup_frequency' => ['type' => 'string'], 'docker_cleanup_threshold' => ['type' => 'integer'], 'server_id' => ['type' => 'integer'], @@ -53,6 +53,7 @@ class ServerSetting extends Model protected $casts = [ 'force_docker_cleanup' => 'boolean', 'docker_cleanup_threshold' => 'integer', + 'sentinel_token' => 'encrypted', ]; public function server() diff --git a/app/Models/StandaloneClickhouse.php b/app/Models/StandaloneClickhouse.php index e4341b1b9..6274f51b2 100644 --- a/app/Models/StandaloneClickhouse.php +++ b/app/Models/StandaloneClickhouse.php @@ -272,7 +272,7 @@ class StandaloneClickhouse extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/app/Models/StandaloneDragonfly.php b/app/Models/StandaloneDragonfly.php index 94ab2d745..3555e7afd 100644 --- a/app/Models/StandaloneDragonfly.php +++ b/app/Models/StandaloneDragonfly.php @@ -272,7 +272,7 @@ class StandaloneDragonfly extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/app/Models/StandaloneKeydb.php b/app/Models/StandaloneKeydb.php index 335c8931c..4725ca533 100644 --- a/app/Models/StandaloneKeydb.php +++ b/app/Models/StandaloneKeydb.php @@ -272,7 +272,7 @@ class StandaloneKeydb extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/app/Models/StandaloneMariadb.php b/app/Models/StandaloneMariadb.php index c6c08dee5..8f1a2c1ee 100644 --- a/app/Models/StandaloneMariadb.php +++ b/app/Models/StandaloneMariadb.php @@ -272,7 +272,7 @@ class StandaloneMariadb extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/app/Models/StandaloneMongodb.php b/app/Models/StandaloneMongodb.php index 99893b1d1..41b2ce9eb 100644 --- a/app/Models/StandaloneMongodb.php +++ b/app/Models/StandaloneMongodb.php @@ -292,7 +292,7 @@ class StandaloneMongodb extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/app/Models/StandaloneMysql.php b/app/Models/StandaloneMysql.php index f2a5b5c14..da2ac070f 100644 --- a/app/Models/StandaloneMysql.php +++ b/app/Models/StandaloneMysql.php @@ -273,7 +273,7 @@ class StandaloneMysql extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index 1b18a5ca7..e0f42269d 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -274,7 +274,7 @@ class StandalonePostgresql extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index a5868e243..fe9f6dfc7 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -268,7 +268,7 @@ class StandaloneRedis extends BaseModel $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->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); + $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false); if (str($metrics)->contains('error')) { $error = json_decode($metrics, true); $error = data_get($error, 'error', 'Something is not okay, are you okay?'); diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index ea9d6ff3c..86c6def76 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -1338,13 +1338,6 @@ function isAnyDeploymentInprogress() exit(0); } -function generateSentinelToken() -{ - $token = Str::random(64); - - return $token; -} - function isBase64Encoded($strValue) { return base64_encode(base64_decode($strValue, true)) === $strValue; diff --git a/database/migrations/2024_06_18_105948_move_server_metrics.php b/database/migrations/2024_06_18_105948_move_server_metrics.php index 26a1d1684..a6bccd16a 100644 --- a/database/migrations/2024_06_18_105948_move_server_metrics.php +++ b/database/migrations/2024_06_18_105948_move_server_metrics.php @@ -18,7 +18,7 @@ return new class extends Migration $table->boolean('is_metrics_enabled')->default(false); $table->integer('metrics_refresh_rate_seconds')->default(5); $table->integer('metrics_history_days')->default(30); - $table->string('metrics_token')->default(generateSentinelToken()); + $table->string('metrics_token')->nullable(); }); } 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 new file mode 100644 index 000000000..32b1e5349 --- /dev/null +++ b/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php @@ -0,0 +1,38 @@ +dropColumn('metrics_token'); + $table->dropColumn('metrics_refresh_rate_seconds'); + $table->dropColumn('metrics_history_days'); + $table->text('sentinel_token')->nullable(); + $table->integer('sentinel_metrics_refresh_rate_seconds')->default(5); + $table->integer('sentinel_metrics_history_days')->default(30); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('server_settings', function (Blueprint $table) { + $table->string('metrics_token')->nullable(); + $table->integer('metrics_refresh_rate_seconds')->default(5); + $table->integer('metrics_history_days')->default(30); + $table->dropColumn('sentinel_token'); + $table->dropColumn('sentinel_metrics_refresh_rate_seconds'); + $table->dropColumn('sentinel_metrics_history_days'); + }); + } +}; diff --git a/openapi.yaml b/openapi.yaml index 91d5c1443..3521b7de4 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4981,11 +4981,11 @@ components: type: string logdrain_newrelic_license_key: type: string - metrics_history_days: + sentinel_metrics_refresh_rate_seconds: type: integer - metrics_refresh_rate_seconds: + sentinel_metrics_history_days: type: integer - metrics_token: + sentinel_token: type: string docker_cleanup_frequency: type: string diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index 48c16051e..d3f51625a 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -68,7 +68,8 @@

+ helper="An IP Address (127.0.0.1) or domain (example.com). Make sure there is no protocol like http(s):// so you provide a FQDN not a URL." + required />
@@ -94,7 +95,8 @@
- @@ -129,23 +131,32 @@
@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. +
+ 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) + @if ($server->isFunctional() && !$server->settings->is_cloudflare_tunnel)
I have configured Cloudflare Tunnels manually
@@ -201,57 +212,58 @@ " instantSave id="server.settings.force_docker_cleanup" label="Force Docker Cleanup" />
- + 'Optionally permanently deletes all unused networks (if enabled in advanced options).', + ]" :confirmWithText="false" :confirmWithPassword="false" + step2ButtonText="Trigger 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.

- 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.

+ - " /> + + " />
@@ -269,21 +281,30 @@ {{-- Restart --}} {{-- @endif --}} -
Metrics are disabled until a few bugs are fixed.
- {{--
+ @if (isDev()) + Get Push Data + {{--
-
-
-
- - - + Start Sentinel +
--}} +
+
+ + Regenerate +
+
+ + +
-
--}} + @else +
Metrics are disabled until a few bugs are fixed.
+ @endif @endif
diff --git a/routes/api.php b/routes/api.php index 57f45be5d..76fd93141 100644 --- a/routes/api.php +++ b/routes/api.php @@ -13,6 +13,9 @@ use App\Http\Controllers\Api\TeamController; use App\Http\Middleware\ApiAllowed; use App\Http\Middleware\IgnoreReadOnlyApiToken; use App\Http\Middleware\OnlyRootApiToken; +use App\Jobs\PushServerUpdateJob; +use App\Models\Server; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; Route::get('/health', [OtherController::class, 'healthcheck']); @@ -129,6 +132,28 @@ Route::group([ }); +Route::group([ + 'prefix' => 'v1', +], function () { + Route::post('/sentinel/push', function () { + $token = request()->header('Authorization'); + if (!$token) { + return response()->json(['message' => 'Unauthorized'], 401); + } + $naked_token = str_replace('Bearer ', '', $token); + $decrypted = decrypt($naked_token); + $decrypted_token = json_decode($decrypted, true); + $server_uuid = data_get($decrypted_token, 'server_uuid'); + $server = Server::where('uuid', $server_uuid)->first(); + if (!$server) { + return response()->json(['message' => 'Server not found'], 404); + } + $data = request()->all(); + PushServerUpdateJob::dispatch($server, $data); + return response()->json(['message' => 'ok'], 200); + }); +}); + Route::any('/{any}', function () { return response()->json(['message' => 'Not found.', 'docs' => 'https://coolify.io/docs'], 404); })->where('any', '.*'); diff --git a/scripts/install.sh b/scripts/install.sh index 76a369e62..af3b4d464 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -13,7 +13,7 @@ DOCKER_VERSION="26.0" # TODO: Ask for a user CURRENT_USER=$USER -mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,metrics,logs} +mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,sentinel} mkdir -p /data/coolify/ssh/{keys,mux} mkdir -p /data/coolify/proxy/dynamic From b2e515f770553bd18e1972c5906073331766a14b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 13:32:36 +0200 Subject: [PATCH 041/100] sentinel --- app/Console/Kernel.php | 2 +- app/Jobs/PushServerUpdateJob.php | 101 ++++++++++++++++-- app/Models/Server.php | 31 +++--- ...pdate_metrics_token_in_server_settings.php | 6 ++ .../views/livewire/server/form.blade.php | 2 +- routes/api.php | 7 +- 6 files changed, 120 insertions(+), 29 deletions(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 1430fcdd1..6da32b461 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -38,7 +38,7 @@ class Kernel extends ConsoleKernel $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(); diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 27aa58201..226cf9392 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -2,14 +2,16 @@ namespace App\Jobs; +use App\Actions\Proxy\StartProxy; +use App\Models\Application; +use App\Models\ApplicationPreview; use App\Models\Server; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Arr; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; class PushServerUpdateJob implements ShouldQueue @@ -25,11 +27,19 @@ class PushServerUpdateJob implements ShouldQueue return isDev() ? 1 : 3; } - public function __construct(public Server $server, public $data) {} + 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 + } public function handle() { - if (!$this->data) { + if (! $this->data) { throw new \Exception('No data provided'); } $data = collect($this->data); @@ -37,17 +47,90 @@ class PushServerUpdateJob implements ShouldQueue if ($containers->isEmpty()) { return; } + $foundApplicationIds = collect(); + $foundServiceIds = collect(); + $foundProxy = false; foreach ($containers as $container) { - $containerStatus = data_get($container, 'status', 'exited'); - $containerHealth = data_get($container, 'health', 'unhealthy'); + $containerStatus = data_get($container, 'state', 'exited'); + $containerHealth = data_get($container, 'health_status', 'unhealthy'); $containerStatus = "$containerStatus ($containerHealth)"; $labels = collect(data_get($container, 'labels')); - if ($labels->has('coolify.applicationId')) { - $applicationId = $labels->get('coolify.applicationId'); + $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'); + $foundApplicationIds->push($applicationId); + try { + $this->updateApplicationStatus($applicationId, $pullRequestId, $containerStatus); + } catch (\Exception $e) { + Log::error($e); + } + } elseif ($labels->has('coolify.serviceId')) { + $serviceId = $labels->get('coolify.serviceId'); + $foundServiceIds->push($serviceId); + Log::info("Service: $serviceId, $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"); + } elseif ($type === 'service') { + Log::info("Service: $uuid, $containerStatus"); + } else { + Log::info("Database: $uuid, $containerStatus"); + } + } } - Log::info("$applicationId, $containerStatus"); + } + + // If proxy is not found, start it + if (! $foundProxy && $this->server->isProxyShouldRun()) { + Log::info('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 updateApplicationStatus(string $applicationId, string $pullRequestId, string $containerStatus) + { + if ($pullRequestId === '0') { + $application = Application::find($applicationId); + if (! $application) { + return; + } + $application->status = $containerStatus; + $application->save(); + Log::info('Application updated', ['application_id' => $applicationId, 'status' => $containerStatus]); + } else { + $application = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first(); + if (! $application) { + return; + } + $application->status = $containerStatus; + $application->save(); + } + } + private function updateNotFoundApplications(Collection $applicationIds) + { + $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']); + } + }); + } } diff --git a/app/Models/Server.php b/app/Models/Server.php index cd7667c70..9e947c20b 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -17,8 +17,6 @@ use Spatie\SchemalessAttributes\Casts\SchemalessAttributes; use Spatie\SchemalessAttributes\SchemalessAttributesTrait; use Spatie\Url\Url; use Symfony\Component\Yaml\Yaml; -use Illuminate\Support\Str; - #[OA\Schema( description: 'Server model', @@ -168,7 +166,7 @@ class Server extends BaseModel 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) { @@ -182,8 +180,8 @@ class Server extends BaseModel 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([ @@ -245,8 +243,8 @@ respond 404 ]; $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); @@ -255,8 +253,8 @@ respond 404 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); } @@ -274,7 +272,7 @@ respond 404 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()) { @@ -393,8 +391,8 @@ respond 404 } $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); @@ -458,13 +456,13 @@ $schema://$host { 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'; } } @@ -536,8 +534,10 @@ $schema://$host { $encrypted = encrypt($token); $this->settings->sentinel_token = $encrypted; $this->settings->save(); + return $encrypted; } + public function isSentinelEnabled() { return $this->isMetricsEnabled() || $this->isServerApiEnabled(); @@ -989,7 +989,8 @@ $schema://$host { public function isProxyShouldRun() { - if ($this->proxyType() === ProxyTypes::NONE->value || $this->settings->is_build_server) { + // TODO: Do we need "|| $this->proxy->force_stop" here? + if ($this->proxyType() === ProxyTypes::NONE->value || $this->isBuildServer()) { return 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 32b1e5349..21c871cf4 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 @@ -19,6 +19,9 @@ return new class extends Migration $table->integer('sentinel_metrics_refresh_rate_seconds')->default(5); $table->integer('sentinel_metrics_history_days')->default(30); }); + Schema::table('servers', function (Blueprint $table) { + $table->dateTime('sentinel_update_at')->default(now()); + }); } /** @@ -34,5 +37,8 @@ return new class extends Migration $table->dropColumn('sentinel_metrics_refresh_rate_seconds'); $table->dropColumn('sentinel_metrics_history_days'); }); + Schema::table('servers', function (Blueprint $table) { + $table->dropColumn('sentinel_update_at'); + }); } }; diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php index d3f51625a..ace297712 100644 --- a/resources/views/livewire/server/form.blade.php +++ b/resources/views/livewire/server/form.blade.php @@ -282,7 +282,7 @@ {{-- @endif --}} @if (isDev()) - Get Push Data + Push Test {{--
Start Sentinel diff --git a/routes/api.php b/routes/api.php index 76fd93141..db07921a4 100644 --- a/routes/api.php +++ b/routes/api.php @@ -15,7 +15,6 @@ use App\Http\Middleware\IgnoreReadOnlyApiToken; use App\Http\Middleware\OnlyRootApiToken; use App\Jobs\PushServerUpdateJob; use App\Models\Server; -use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; Route::get('/health', [OtherController::class, 'healthcheck']); @@ -137,7 +136,7 @@ Route::group([ ], function () { Route::post('/sentinel/push', function () { $token = request()->header('Authorization'); - if (!$token) { + if (! $token) { return response()->json(['message' => 'Unauthorized'], 401); } $naked_token = str_replace('Bearer ', '', $token); @@ -145,11 +144,13 @@ Route::group([ $decrypted_token = json_decode($decrypted, true); $server_uuid = data_get($decrypted_token, 'server_uuid'); $server = Server::where('uuid', $server_uuid)->first(); - if (!$server) { + if (! $server) { return response()->json(['message' => 'Server not found'], 404); } $data = request()->all(); + $server->update(['sentinel_update_at' => now()]); PushServerUpdateJob::dispatch($server, $data); + return response()->json(['message' => 'ok'], 200); }); }); 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 042/100] 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 043/100] 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 044/100] 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 045/100] 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 046/100] 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 047/100] 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 048/100] 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 049/100] 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 050/100] 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 051/100] 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue 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 052/100] 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 @@ class PushServerUpdateJob implements ShouldQueue { // 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 @@ class PushServerUpdateJob implements ShouldQueue $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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue } $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 053/100] 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 @@ class Index extends Component } $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 @@
  1. + href="{{ route('project.show', ['project_uuid' => data_get($parameters, 'project_uuid')]) }}"> {{ $project->name }}
  2. @@ -44,7 +44,7 @@
@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 054/100] 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue } $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 @@ class PushServerUpdateJob implements ShouldQueue } $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 @@ class PushServerUpdateJob implements ShouldQueue { $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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue } $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 @@ class PushServerUpdateJob implements ShouldQueue { $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 @@ class PushServerUpdateJob implements ShouldQueue $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 @@ class PushServerUpdateJob implements ShouldQueue $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 @@ class PushServerUpdateJob implements ShouldQueue 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 055/100] 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 @@ class Form extends Component $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 @@ class Form extends Component return handleError($e, $this); } } + public function updated($field) { if ($field === 'server.settings.docker_cleanup_frequency') { @@ -186,25 +189,26 @@ class Form extends Component 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 @@ class Form extends Component return handleError($e, $this); } } + public function manualCleanup() { try { @@ -302,4 +307,10 @@ class Form extends Component $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 @@ {{-- @endif --}}
@if (isDev()) - Push Test - {{--
+
- Start Sentinel -
--}} + Start Sentinel +
Date: Mon, 14 Oct 2024 22:35:18 +0200 Subject: [PATCH 056/100] 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 @@ class StartSentinel $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 057/100] 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue 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 058/100] 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 059/100] 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 @@ class StartSentinel } $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\PullSentinelImageJob; 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\Server; 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 @@ class Kernel extends ConsoleKernel $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 @@ class Kernel extends ConsoleKernel $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 @@ namespace App\Jobs; 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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue $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 @@ class PushServerUpdateJob implements ShouldQueue } } 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 @@ class PushServerUpdateJob implements ShouldQueue $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 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue { 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 @@ class Charts extends Component 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 @@ class Form extends Component '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 @@ class Form extends Component '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 @@ class Form extends Component $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 @@ class Form extends Component $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 @@ class Form extends Component $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 @@ class Form extends Component } } - 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 @@ class Form extends Component $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\Enums\ProxyTypes; 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 OpenApi\Attributes as OA; 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 @@ class Server extends BaseModel 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 @@ class Server extends BaseModel 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 @@ respond 404 ]; $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 @@ respond 404 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 @@ respond 404 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 @@ respond 404 } $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 @@ $schema://$host { 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 @@ $schema://$host { 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 @@ $schema://$host { public function isServerApiEnabled() { - return $this->settings->is_server_api_enabled; + return $this->settings->is_sentinel_enabled; } public function checkServerApi() @@ -591,7 +603,15 @@ $schema://$host { { 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 @@ $schema://$host { } 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 @@ $schema://$host { { 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 @@ $schema://$host { } 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 @@ $schema://$host { 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 @@ use OpenApi\Attributes as OA; '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 @@ return new class extends Migration 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 @@ return new class extends Migration $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 @@ return new class extends Migration $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 @@ class DatabaseSeeder extends Seeder 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 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== $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 @@ Route::group([ 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 060/100] 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 @@ 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 061/100] 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 062/100] 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 @@ class Metrics extends Component 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 @@ class Application extends BaseModel $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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel $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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel public function workdir() { - return application_configuration_dir()."/{$this->uuid}"; + return application_configuration_dir() . "/{$this->uuid}"; } public function isLogDrainEnabled() @@ -841,7 +841,7 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel $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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel 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 @@ Route::group([ $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 063/100] 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 @@ class Form extends Component '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 @@ class Form extends Component '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 @@ $schema://$host { 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 @@ return new class extends Migration $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 @@ return new class extends Migration $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 @@ class DatabaseSeeder extends Seeder 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 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== $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 @@ namespace Database\Seeders; use App\Models\Server; use Illuminate\Database\Seeder; -class GenerateSentinelTokenSeeder extends Seeder +class SentinelSeeder extends Seeder { public function run() { @@ -15,6 +15,12 @@ class GenerateSentinelTokenSeeder extends Seeder 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 @@
+ + Regenerate
From 8c53af088ef257b9b4209f825df4b3a2addd6f78 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 15:45:02 +0200 Subject: [PATCH 064/100] 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 @@ class StartSentinel 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 @@ $schema://$host { 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 2702fbc284f8aaa265603cd5a17ce35903be3257 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 17:03:50 +0200 Subject: [PATCH 065/100] 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 @@ class PushServerUpdateJob implements ShouldQueue } - private function serverStatus(){ + private function serverStatus() + { if ($this->server->isFunctional() === false) { throw new \Exception('Server is not ready.'); } @@ -212,6 +214,7 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class PushServerUpdateJob implements ShouldQueue StartProxy::run($this->server, false); } } catch (\Throwable $e) { - logger()->error($e); } } else { $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); @@ -396,7 +398,8 @@ class PushServerUpdateJob implements ShouldQueue 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 @@ class Application extends BaseModel $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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel $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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel public function workdir() { - return application_configuration_dir() . "/{$this->uuid}"; + return application_configuration_dir()."/{$this->uuid}"; } public function isLogDrainEnabled() @@ -841,7 +841,7 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel } 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 @@ class Application extends BaseModel $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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel 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 @@ class Application extends BaseModel } $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 @@ class Application extends BaseModel } $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 @@ class Application extends BaseModel 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 @@ class SentinelSeeder extends Seeder } 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 @@ Route::group([ 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 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 066/100] 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 067/100] 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 068/100] 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 069/100] 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 070/100] 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 071/100] 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 072/100] 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 @@ return new class extends Migration $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 073/100] 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 074/100] 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 @@ class StartSentinel $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 @@ class ServersController extends Controller 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 @@ class PushServerUpdateJob implements ShouldQueue $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 @@ class Delete extends Component 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 @@ class Form extends Component 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 @@ $schema://$host { 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 @@ $schema://$host { public function isSentinelEnabled() { - return $this->isMetricsEnabled() || $this->isServerApiEnabled(); + return $this->isMetricsEnabled() || $this->isServerApiEnabled() || !$this->isBuildServer(); } public function isMetricsEnabled() 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 075/100] 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 076/100] 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 077/100] 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 @@ namespace App\Actions\Server; 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 @@ class StartSentinel '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 @@ class ServersController extends Controller 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 @@ class Show extends Component 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 @@ class Delete extends Component 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 @@ class Form extends Component '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 @@ class Form extends Component $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 @@ class Form extends Component 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 @@ class Form extends Component $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 @@ class Form extends Component public function instantSave() { try { + $this->validate(); refresh_server_connection($this->server->privateKey); $this->validateServer(false); @@ -179,6 +192,14 @@ class Form extends Component $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 @@ class Form extends Component // $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 @@ class Form extends Component $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 @@ class Resources extends Component 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 @@ class Resources extends Component 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 @@ class ShowPrivateKey extends Component 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\Enums\ProxyTypes; 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 OpenApi\Attributes as OA; 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 @@ use Symfony\Component\Yaml\Yaml; class Server extends BaseModel { - use SchemalessAttributesTrait; + use SchemalessAttributesTrait,SoftDeletes; public static $batch_counter = 0; @@ -97,7 +97,8 @@ class Server extends BaseModel } } }); - static::deleting(function ($server) { + + static::forceDeleting(function ($server) { $server->destinations()->each(function ($destination) { $destination->delete(); }); @@ -527,34 +528,6 @@ $schema://$host { 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 @@ $schema://$host { 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 @@
-
+
@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
+ + +
-
- @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 078/100] 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 079/100] 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\Actions\Server\StopSentinel; 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 @@ class Form extends Component '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 @@ class Form extends Component '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 @@ class Form extends Component '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 @@ class Form extends Component $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 @@ class Form extends Component $this->restartSentinel(); } - public function instantSave() { try { @@ -218,6 +199,7 @@ class Form extends Component } catch (\Throwable $e) { $this->server->settings->refresh(); + return handleError($e, $this); } } @@ -255,7 +237,7 @@ class Form extends Component $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 080/100] 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 @@ class Advanced extends Component $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 @@ class Advanced extends Component 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 @@ namespace App\Livewire\Server; 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 @@ class Form extends Component $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 @@ class Form extends Component } 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 @@ class Form extends Component 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 081/100] 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 082/100] 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 @@
-
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 083/100] 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 084/100] 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 085/100] 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 086/100] 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 @@ abstract class DuskTestCase extends BaseTestCase })->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 087/100] 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 088/100] 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 @@ abstract class DuskTestCase extends BaseTestCase */ 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 089/100] 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 090/100] 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 091/100] 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 092/100] 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 093/100] 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 @@ use Livewire\Component; 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 @@ class DeleteEnvironment extends Component 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 094/100] 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 @@ class Show extends Component { $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 095/100] 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 @@ class StartSentinel $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 @@ class General extends Component } } - public function updatedApplicationBuildPack() { if ($this->application->build_pack !== 'nixpacks') { @@ -314,7 +313,7 @@ class General extends Component 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 @@ class General extends Component $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 @@ class General extends Component 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 @@ class General extends Component 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 @@ class PublicGitRepository extends Component // $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 @@ class EditDomain extends Component { $this->application = ServiceApplication::find($this->applicationId); } + public function submit() { try { @@ -28,6 +29,7 @@ class EditDomain extends Component $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 @@ class EditDomain extends Component 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 @@ class Navbar extends Component 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 @@ class ServiceApplicationView extends Component $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 @@ class ServiceApplicationView extends Component 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 @@ use Livewire\Component; 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 @@ class UploadConfig extends Component }'; } } + public function uploadConfig() { try { @@ -30,10 +34,12 @@ class UploadConfig extends Component $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 @@ class CloudflareTunnels extends Component } } - 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 @@ class Delete extends Component } $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 @@ class ShowPrivateKey extends Component $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 @@ class ShowPrivateKey extends Component $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 @@ class Index extends Component } } - 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 @@ class ScheduledDatabaseBackup extends BaseModel } } - 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 @@ class Server extends BaseModel 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 @@ class Server extends BaseModel 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 @@ respond 404 ]; $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 @@ respond 404 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 @@ respond 404 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 @@ respond 404 } $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 @@ $schema://$host { 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 @@ $schema://$host { 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 @@ $schema://$host { public function isSentinelEnabled() { - return ($this->isMetricsEnabled() || $this->isServerApiEnabled()) && !$this->isBuildServer(); + return ($this->isMetricsEnabled() || $this->isServerApiEnabled()) && ! $this->isBuildServer(); } public function isMetricsEnabled() @@ -611,8 +611,9 @@ $schema://$host { } $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 @@ $schema://$host { 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 @@ $schema://$host { 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 @@ class ServerSetting extends Model } } } catch (\Throwable $e) { - loggy('Error creating server setting: ' . $e->getMessage()); + loggy('Error creating server setting: '.$e->getMessage()); } }); } @@ -98,17 +98,18 @@ class ServerSetting extends Model $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 @@ class Service extends BaseModel '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 @@ class Service extends BaseModel 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 @@ class Service extends BaseModel 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 096/100] 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 097/100] 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 098/100] 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 099/100] 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 100/100] 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.",