From 7caf70941381ffe6320875c7c9d147eb08254a37 Mon Sep 17 00:00:00 2001 From: Jere Salonen Date: Tue, 23 Apr 2024 19:59:16 +0200 Subject: [PATCH 0001/1011] 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 0002/1011] 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 0ac6180479fea22ee9ea740a7c0a540950971df5 Mon Sep 17 00:00:00 2001 From: Luan Estradioto Date: Mon, 3 Jun 2024 17:58:44 -0300 Subject: [PATCH 0003/1011] feat: add jitsi template --- public/svgs/jitsi.svg | 8 +++ templates/compose/jitsi.env | 8 +++ templates/compose/jitsi.yaml | 120 +++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 public/svgs/jitsi.svg create mode 100644 templates/compose/jitsi.env create mode 100644 templates/compose/jitsi.yaml diff --git a/public/svgs/jitsi.svg b/public/svgs/jitsi.svg new file mode 100644 index 000000000..6257659ee --- /dev/null +++ b/public/svgs/jitsi.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/templates/compose/jitsi.env b/templates/compose/jitsi.env new file mode 100644 index 000000000..46816cb73 --- /dev/null +++ b/templates/compose/jitsi.env @@ -0,0 +1,8 @@ +JITSI_IMAGE_VERSION=unstable +JIBRI_RECORDER_PASSWORD=$SERVICE_PASSWORD_JITSI +JIBRI_XMPP_PASSWORD=$SERVICE_PASSWORD_JITSI +JICOFO_AUTH_PASSWORD=$SERVICE_PASSWORD_JITSI +JIGASI_XMPP_PASSWORD=$SERVICE_PASSWORD_JITSI +JVB_AUTH_PASSWORD=$SERVICE_PASSWORD_JITSI +PUBLIC_URL= +TZ=UTC \ No newline at end of file diff --git a/templates/compose/jitsi.yaml b/templates/compose/jitsi.yaml new file mode 100644 index 000000000..34155701a --- /dev/null +++ b/templates/compose/jitsi.yaml @@ -0,0 +1,120 @@ +# documentation: https://jitsi.github.io/handbook/docs/intro +# slogan: World's easiest way to add meetings to your apps +# env_file: jitsi.env +# logo: svgs/jitsi.svg +# tags: video, conferencing, meetings, communication, open-source + +services: + jitsi-web: + image: "jitsi/web:${JITSI_IMAGE_VERSION}" + container_name: jitsi-web + restart: unless-stopped + ports: + - "8001:80" + - "8443:443" + volumes: + - ~/.jitsi-meet-cfg/web:/config:Z + - ~/.jitsi-meet-cfg/web/crontabs:/var/spool/cron/crontabs:Z + - ~/.jitsi-meet-cfg/transcripts:/usr/share/jitsi-meet/transcripts:Z + environment: + - SERVICE_FQDN_JITSI + - PUBLIC_URL=$SERVICE_FQDN_JITSI + - TZ + networks: + meet.jitsi: + aliases: + - meet.jitsi + depends_on: + - jvb + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost"] + interval: 2s + timeout: 10s + retries: 15 + + prosody: + image: "jitsi/prosody:${JITSI_IMAGE_VERSION}" + expose: + - '5222' + - '5347' + - '5280' + container_name: jitsi-xmpp + restart: unless-stopped + volumes: + - ~/.jitsi-meet-cfg/prosody/config:/config:Z + - ~/.jitsi-meet-cfg/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z + environment: + - JICOFO_AUTH_PASSWORD + - JVB_AUTH_PASSWORD + - PUBLIC_URL=$SERVICE_FQDN_JITSI + - TZ + networks: + meet.jitsi: + aliases: + - xmpp.meet.jitsi + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5280/http-bind"] + interval: 2s + timeout: 10s + retries: 15 + + jicofo: + image: "jitsi/jicofo:${JITSI_IMAGE_VERSION}" + container_name: jitsi-jicofo + restart: unless-stopped + volumes: + - ~/.jitsi-meet-cfg/jicofo:/config:Z + environment: + - XMPP_SERVER=prosody + - JICOFO_AUTH_PASSWORD + - TZ + - JICOFO_ENABLE_HEALTH_CHECKS=1 + depends_on: + - prosody + networks: + meet.jitsi: + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8888/about/health"] + interval: 2s + timeout: 10s + retries: 15 + + jvb: + image: "jitsi/jvb:${JITSI_IMAGE_VERSION}" + container_name: jitsi-jvb + restart: unless-stopped + expose: + - '10000:10000/udp' + - '8080:8080' + - '10000' + volumes: + - ~/.jitsi-meet-cfg/jvb:/config:Z + environment: + - JVB_ADVERTISE_IPS + - JVB_AUTH_PASSWORD + - PUBLIC_URL=$SERVICE_FQDN_JITSI + - TZ + - XMPP_SERVER=prosody + depends_on: + - prosody + networks: + meet.jitsi: + labels: + - "traefik.enable=true" + - "traefik.udp.routers.my-udp-router.entrypoints=video" + - "traefik.udp.routers.my-udp-router.service=my-udp-service" + - "traefik.udp.services.my-udp-service.loadbalancer.server.port=10000" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/about/health"] + interval: 2s + timeout: 10s + retries: 15 + +networks: + meet.jitsi: + +volumes: + jitsi-web: + jitsi-xmpp: + jitsi-jicofo: + jitsi-jvb: \ No newline at end of file From e2db5e0b1eb6e04a7823d9e70cc9e0dfab3e8ce1 Mon Sep 17 00:00:00 2001 From: Matheus Pratta Date: Sun, 16 Jun 2024 01:22:44 -0300 Subject: [PATCH 0004/1011] fix: show proper error message on invalid Git source --- app/Models/Application.php | 121 +++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/app/Models/Application.php b/app/Models/Application.php index 6e55f6626..e3d05bc2c 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -704,6 +704,121 @@ class Application extends BaseModel return $git_clone_command; } + public function getGitRemoteStatus(string $deployment_uuid) + { + try { + ['commands' => $lsRemoteCommand] = $this->generateGitLsRemoteCommands(deployment_uuid: $deployment_uuid, exec_in_docker: false); + instant_remote_process([$lsRemoteCommand], $this->destination->server, true); + return [ + 'is_accessible' => true, + 'error' => null, + ]; + } catch (\RuntimeException $ex) { + return [ + 'is_accessible' => false, + 'error' => $ex->getMessage(), + ]; + } + } + + public function generateGitLsRemoteCommands(string $deployment_uuid, bool $exec_in_docker = true) + { + $branch = $this->git_branch; + ['repository' => $customRepository, 'port' => $customPort] = $this->customRepository(); + $commands = collect([]); + $base_command = "git ls-remote"; + + if ($this->deploymentType() === 'source') { + $source_html_url = data_get($this, 'source.html_url'); + $url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL)); + $source_html_url_host = $url['host']; + $source_html_url_scheme = $url['scheme']; + + if ($this->source->getMorphClass() == 'App\Models\GithubApp') { + if ($this->source->is_public) { + $fullRepoUrl = "{$this->source->html_url}/{$customRepository}"; + $base_command = "{$base_command} {$this->source->html_url}/{$customRepository}"; + } else { + $github_access_token = generate_github_installation_token($this->source); + + if ($exec_in_docker) { + $base_command = "{$base_command} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git"; + $fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git"; + } else { + $base_command = "{$base_command} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}"; + $fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}"; + } + } + + if ($exec_in_docker) { + $commands->push(executeInDocker($deployment_uuid, $base_command)); + } else { + $commands->push($base_command); + } + + return [ + 'commands' => $commands->implode(' && '), + 'branch' => $branch, + 'fullRepoUrl' => $fullRepoUrl, + ]; + } + } + + if ($this->deploymentType() === 'deploy_key') { + $fullRepoUrl = $customRepository; + $private_key = data_get($this, 'private_key.private_key'); + if (is_null($private_key)) { + throw new RuntimeException('Private key not found. Please add a private key to the application and try again.'); + } + $private_key = base64_encode($private_key); + $base_comamnd = "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\" {$base_command} {$customRepository}"; + + if ($exec_in_docker) { + $commands = collect([ + executeInDocker($deployment_uuid, 'mkdir -p /root/.ssh'), + executeInDocker($deployment_uuid, "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null"), + executeInDocker($deployment_uuid, 'chmod 600 /root/.ssh/id_rsa'), + ]); + } else { + $commands = collect([ + 'mkdir -p /root/.ssh', + "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null", + 'chmod 600 /root/.ssh/id_rsa', + ]); + } + + if ($exec_in_docker) { + $commands->push(executeInDocker($deployment_uuid, $base_comamnd)); + } else { + $commands->push($base_comamnd); + } + + return [ + 'commands' => $commands->implode(' && '), + 'branch' => $branch, + 'fullRepoUrl' => $fullRepoUrl, + ]; + } + + if ($this->deploymentType() === 'other') { + $fullRepoUrl = $customRepository; + $base_command = "{$base_command} {$customRepository}"; + $base_command = $this->setGitImportSettings($deployment_uuid, $base_command, public: true); + + if ($exec_in_docker) { + $commands->push(executeInDocker($deployment_uuid, $base_command)); + } else { + $commands->push($base_command); + } + + return [ + 'commands' => $commands->implode(' && '), + 'branch' => $branch, + 'fullRepoUrl' => $fullRepoUrl, + ]; + } + } + public function generateGitImportCommands(string $deployment_uuid, int $pull_request_id = 0, ?string $git_type = null, bool $exec_in_docker = true, bool $only_checkout = false, ?string $custom_base_dir = null, ?string $commit = null) { $branch = $this->git_branch; @@ -966,6 +1081,12 @@ class Application extends BaseModel // if ($composeFile !== $prComposeFile) { // $fileList->push(".$prComposeFile"); // } + + $gitRemoteStatus = $this->getGitRemoteStatus(deployment_uuid: $uuid); + if (! $gitRemoteStatus['is_accessible']) { + throw new \RuntimeException("Failed to read Git source:\n\n{$gitRemoteStatus['error']}"); + } + $commands = collect([ "rm -rf /tmp/{$uuid}", "mkdir -p /tmp/{$uuid}", From e5da464980de312267a7a05b5e6b3f81a8ef6fb7 Mon Sep 17 00:00:00 2001 From: Matheus Pratta Date: Sun, 16 Jun 2024 02:23:29 -0300 Subject: [PATCH 0005/1011] fix: convert HTTP to SSH source when using deploy key on GitHub --- app/Models/Application.php | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/app/Models/Application.php b/app/Models/Application.php index 6e55f6626..3fb7da903 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -662,6 +662,37 @@ class Application extends BaseModel public function customRepository() { + $repository = $this->git_repository; + + // Let's try and parse the string to detect if it's a valid SSH string or not + $sshMatches = []; + preg_match('/((.*?)\:\/\/)?(.*@.*:.*)/', $this->git_repository, $sshMatches); + + if ($this->deploymentType() === 'deploy_key' && empty($sshMatches) && $this->source) { + // If this happens, the user may have provided an HTTP URL when they needed an SSH one + // Let's try and fix that for known Git providers + $providerInfo = [ + 'host' => null, + 'user' => 'git', + 'port' => 22, + 'repository' => $this->git_repository, + ]; + + switch ($this->source->getMorphClass()) { + case \App\Models\GithubApp::class: + $providerInfo['host'] = Url::fromString($this->source->html_url)->getHost(); + $providerInfo['port'] = $this->source->custom_port; + $providerInfo['user'] = $this->source->custom_user; + break; + } + + if (! empty($providerInfo['host'])) { + $repository = ($providerInfo['port'] === 22) + ? "{$providerInfo['user']}@{$providerInfo['host']}:{$providerInfo['repository']}" + : "ssh://{$providerInfo['user']}@{$providerInfo['host']}:{$providerInfo['port']}/{$providerInfo['repository']}"; + } + } + preg_match('/(?<=:)\d+(?=\/)/', $this->git_repository, $matches); $port = 22; if (count($matches) === 1) { @@ -669,8 +700,6 @@ class Application extends BaseModel $gitHost = str($this->git_repository)->before(':'); $gitRepo = str($this->git_repository)->after('/'); $repository = "$gitHost:$gitRepo"; - } else { - $repository = $this->git_repository; } return [ From 79a169f53e3bc5164292e17bc159737293207812 Mon Sep 17 00:00:00 2001 From: Telokis <6382729+Telokis@users.noreply.github.com> Date: Sun, 11 Aug 2024 15:18:11 +0200 Subject: [PATCH 0006/1011] Add initial docker-compose.yaml for Pterodactyl --- public/svgs/pterodactyl.png | Bin 0 -> 32004 bytes templates/compose/pterodactyl.yaml | 157 +++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 public/svgs/pterodactyl.png create mode 100644 templates/compose/pterodactyl.yaml diff --git a/public/svgs/pterodactyl.png b/public/svgs/pterodactyl.png new file mode 100644 index 0000000000000000000000000000000000000000..a5addb87c5cf70b426a5a13a563a677088cad3a3 GIT binary patch literal 32004 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

MZBCd6fS^X@TN}n= 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 Ke1)t<@c#oi$r%~| literal 0 HcmV?d00001 diff --git a/templates/compose/pterodactyl.yaml b/templates/compose/pterodactyl.yaml new file mode 100644 index 000000000..436065a40 --- /dev/null +++ b/templates/compose/pterodactyl.yaml @@ -0,0 +1,157 @@ +# documentation: https://pterodactyl.io/ +# slogan: Pterodactyl is a free, open-source game server management panel +# tags: game, game server, management, panel, minecraft +# logo: svgs/pterodactyl.png +# port: 80 + +services: + mariadb: + image: mariadb:10.5 + restart: unless-stopped + command: --default-authentication-plugin=mysql_native_password + healthcheck: + test: + ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized || exit 1"] + start_period: 10s + interval: 10s + timeout: 1s + retries: 3 + environment: + - SERVICE_PASSWORD_MYSQL + - MYSQL_ROOT_PASSWORD=$SERVICE_PASSWORD_MYSQLROOT + - MYSQL_DATABASE=panel + - MYSQL_USER=pterodactyl + - MYSQL_PASSWORD=$SERVICE_PASSWORD_MYSQL + volumes: + - pterodactyl-db:/var/lib/mysql + + redis: + image: redis:alpine + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "redis-cli ping || exit 1"] + interval: 10s + timeout: 1s + retries: 3 + + pterodactyl: + image: ghcr.io/pterodactyl/panel:latest + restart: unless-stopped + volumes: + - "panel-var:/app/var/" + - "panel-nginx:/etc/nginx/http.d/" + - "panel-certs:/etc/letsencrypt/" + - "panel-logs:/app/storage/logs" + healthcheck: + test: ["CMD-SHELL", "curl -sf http://localhost:80 || exit 1"] + interval: 10s + timeout: 1s + retries: 3 + environment: + - SERVICE_FQDN_PTERODACTYL + + - APP_ENV=production + - APP_ENVIRONMENT_ONLY=false + - APP_URL=${PTERODACTYL_PUBLIC_FQDN:-$SERVICE_FQDN_PTERODACTYL} + - APP_TIMEZONE=${TIMEZONE:-UTC} + - APP_SERVICE_AUTHOR=$APP_SERVICE_AUTHOR + - LOG_LEVEL=${LOG_LEVEL:-debug} + + - CACHE_DRIVER=redis + - SESSION_DRIVER=redis + - QUEUE_DRIVER=redis + - REDIS_HOST=redis + + - DB_HOST=mariadb + - DB_PORT=3306 + - DB_PASSWORD=$SERVICE_PASSWORD_MYSQL + + - MAIL_FROM=$MAIL_FROM + - MAIL_DRIVER=$MAIL_DRIVER + - MAIL_HOST=$MAIL_HOST + - MAIL_PORT=$MAIL_PORT + - MAIL_USERNAME=$MAIL_USERNAME + - MAIL_PASSWORD=$MAIL_PASSWORD + - MAIL_ENCRYPTION=$MAIL_ENCRYPTION + + wings: + image: ghcr.io/pterodactyl/wings:latest + restart: unless-stopped + environment: + - TZ=${TIMEZONE:-UTC} + - WINGS_USERNAME=pterodactyl + healthcheck: + test: ["CMD", "curl", "-sf http://localhost:8080"] + interval: 10s + timeout: 1s + retries: 3 + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + - "/var/lib/docker/containers/:/var/lib/docker/containers/" + - "wings-lib:/var/lib/pterodactyl/" + - "wings-logs:/var/log/pterodactyl/" + + - type: bind + source: ./etc/config.yml + target: /etc/pterodactyl/config.yml + content: | + docker: + network: + interface: 172.28.0.1 + dns: + - 1.1.1.1 + - 1.0.0.1 + name: pterodactyl_nw + ispn: false + driver: "" + network_mode: pterodactyl_nw + is_internal: false + enable_icc: true + network_mtu: 1500 + interfaces: + v4: + subnet: 172.28.0.0/16 + gateway: 172.28.0.1 + v6: + subnet: fdba:17c8:6c94::/64 + gateway: fdba:17c8:6c94::1011 + +volumes: + panel-var: + panel-nginx: + panel-certs: + panel-logs: + wings-lib: + wings-logs: + pterodactyl-db: +# Instructions: +# - Wait for the Pterodactyl service to be healthy (can take a few minutes) +# - Use the command `php artisan p:user:make --no-interaction --admin=1 --email= --username= --name-first= --name-last= --password=` in the Pterodactyl container to create an admin user. +# - Login to the panel using the created user +# - Go to the Admin panel (Cog icon at the top) +# - Go to "Locations" on the left +# - Create a new location +# - Go to "Nodes" on the left +# - Create a new node +# - Specify a temporary FQDN like "localhost" +# - /!\ Check "Use HTTP Connection" /!\ +# - Go to the "Configuration" tab of your newly created node +# - Copy the configuration file +# - In Coolify go to the "Storage" menu for your resource. +# - Find the big text area associated with `config.yml` for Wings +# - Paste the configuration at the top of this file, above `docker:` +# - Edit the line `remote: ''` to `remote: 'http://pterodactyl'` +# - Save the file +# - On the Pterodactyl panel for the node, go to the "Settings" tab +# - Change the "Fully Qualified Domain Name" from `localhost` to `wings` +# - Go to the "About" tab and confirm that the "Information" section shows the "Daemon Version" properly. + +# +----------+--------------------------------------+ +# | Field | Value | +# +----------+--------------------------------------+ +# | UUID | 6b3083ca-274b-4a77-b88f-6fbf5e4f286f | +# | Email | telokis@example.com | +# | Username | telokis | +# | Name | Telo Kis | +# | Admin | Yes | +# +----------+--------------------------------------+ From de6be8c840f7737a6f51e8cd5f620f0e6c47fecc Mon Sep 17 00:00:00 2001 From: Telokis <6382729+Telokis@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:06:24 +0200 Subject: [PATCH 0007/1011] Fix a lot of small mistakes --- templates/compose/pterodactyl.yaml | 45 +++--------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/templates/compose/pterodactyl.yaml b/templates/compose/pterodactyl.yaml index 436065a40..19315b4ce 100644 --- a/templates/compose/pterodactyl.yaml +++ b/templates/compose/pterodactyl.yaml @@ -41,7 +41,6 @@ services: - "panel-var:/app/var/" - "panel-nginx:/etc/nginx/http.d/" - "panel-certs:/etc/letsencrypt/" - - "panel-logs:/app/storage/logs" healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:80 || exit 1"] interval: 10s @@ -54,7 +53,7 @@ services: - APP_ENVIRONMENT_ONLY=false - APP_URL=${PTERODACTYL_PUBLIC_FQDN:-$SERVICE_FQDN_PTERODACTYL} - APP_TIMEZONE=${TIMEZONE:-UTC} - - APP_SERVICE_AUTHOR=$APP_SERVICE_AUTHOR + - APP_SERVICE_AUTHOR=${APP_SERVICE_AUTHOR:-author@example.com} - LOG_LEVEL=${LOG_LEVEL:-debug} - CACHE_DRIVER=redis @@ -78,17 +77,14 @@ services: image: ghcr.io/pterodactyl/wings:latest restart: unless-stopped environment: + - SERVICE_FQDN_WINGS_8080 - TZ=${TIMEZONE:-UTC} - WINGS_USERNAME=pterodactyl - healthcheck: - test: ["CMD", "curl", "-sf http://localhost:8080"] - interval: 10s - timeout: 1s - retries: 3 volumes: - "/var/run/docker.sock:/var/run/docker.sock" - "/var/lib/docker/containers/:/var/lib/docker/containers/" - - "wings-lib:/var/lib/pterodactyl/" + - "/var/lib/pterodactyl/:/var/lib/pterodactyl/" # See https://discord.com/channels/122900397965705216/493443725012500490/1272195151309045902 + - "/tmp/pterodactyl/:/tmp/pterodactyl/" # See https://discord.com/channels/122900397965705216/493443725012500490/1272195151309045902 - "wings-logs:/var/log/pterodactyl/" - type: bind @@ -120,38 +116,5 @@ volumes: panel-var: panel-nginx: panel-certs: - panel-logs: - wings-lib: wings-logs: pterodactyl-db: -# Instructions: -# - Wait for the Pterodactyl service to be healthy (can take a few minutes) -# - Use the command `php artisan p:user:make --no-interaction --admin=1 --email= --username= --name-first= --name-last= --password=` in the Pterodactyl container to create an admin user. -# - Login to the panel using the created user -# - Go to the Admin panel (Cog icon at the top) -# - Go to "Locations" on the left -# - Create a new location -# - Go to "Nodes" on the left -# - Create a new node -# - Specify a temporary FQDN like "localhost" -# - /!\ Check "Use HTTP Connection" /!\ -# - Go to the "Configuration" tab of your newly created node -# - Copy the configuration file -# - In Coolify go to the "Storage" menu for your resource. -# - Find the big text area associated with `config.yml` for Wings -# - Paste the configuration at the top of this file, above `docker:` -# - Edit the line `remote: ''` to `remote: 'http://pterodactyl'` -# - Save the file -# - On the Pterodactyl panel for the node, go to the "Settings" tab -# - Change the "Fully Qualified Domain Name" from `localhost` to `wings` -# - Go to the "About" tab and confirm that the "Information" section shows the "Daemon Version" properly. - -# +----------+--------------------------------------+ -# | Field | Value | -# +----------+--------------------------------------+ -# | UUID | 6b3083ca-274b-4a77-b88f-6fbf5e4f286f | -# | Email | telokis@example.com | -# | Username | telokis | -# | Name | Telo Kis | -# | Admin | Yes | -# +----------+--------------------------------------+ From e77e807cdd830b71e0d6885b417c0ab14ef7de0f Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:54:16 +0200 Subject: [PATCH 0008/1011] Add UI --- .../project/database/redis/general.blade.php | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index ceb12a802..35ee90583 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -9,48 +9,41 @@

- + +
+
+ +

Network

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

Proxy

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

Advanced

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

Network

@@ -46,4 +51,4 @@
- + \ No newline at end of file From 3d7a467abf936f50167cf06445c4b61d008c2ae3 Mon Sep 17 00:00:00 2001 From: ayntk-ai <122374094+ayntk-ai@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:00:18 +0200 Subject: [PATCH 0014/1011] WIP WIP --- app/Actions/Database/StartRedis.php | 56 +++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index b3f240942..6d1548357 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -20,10 +20,42 @@ class StartRedis public function handle(StandaloneRedis $database) { $this->database = $database; + //$this->configuration_dir = database_configuration_dir().'/'.$this->database->uuid; + + //$this->add_custom_redis(); + + // $startCommand = "redis-server"; + // $additionalArgs = []; + + // if (!is_null($this->database->redis_conf) && !empty($this->database->redis_conf)) { + // ray("Using custom Redis configuration"); + // $additionalArgs[] = "{$this->configuration_dir}/redis.conf"; + + // // Check if the custom config contains a requirepass directive + // $configContent = file_get_contents("{$this->configuration_dir}/redis.conf"); + // if (strpos($configContent, 'requirepass') === false) { + // $additionalArgs[] = "--requirepass {$this->database->redis_password}"; + // ray("No requirepass in custom config, adding it as an argument"); + // } else { + // ray("requirepass found in custom config"); + // } + // } else { + // $additionalArgs[] = "--requirepass {$this->database->redis_password}"; + // $additionalArgs[] = "--appendonly yes"; + // ray("No custom config, using default arguments"); + // } + + // if (!empty($additionalArgs)) { + // $startCommand .= " " . implode(" ", $additionalArgs); + // } + + // ray("Final start command: " . $startCommand); $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; + $container_name = $this->database->uuid; + $this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->commands = [ @@ -31,12 +63,14 @@ class StartRedis "mkdir -p $this->configuration_dir", ]; + $persistent_storages = $this->generate_local_persistent_volumes(); $persistent_file_volumes = $this->database->fileStorages()->get(); $volume_names = $this->generate_local_persistent_volumes_only_volume_names(); $environment_variables = $this->generate_environment_variables(); $this->add_custom_redis(); + $docker_compose = [ 'services' => [ $container_name => [ @@ -113,6 +147,7 @@ class StartRedis 'read_only' => true, ]; $docker_compose['services'][$container_name]['command'] = "redis-server /usr/local/etc/redis/redis.conf --requirepass {$this->database->redis_password} --appendonly yes"; + } $docker_compose = Yaml::dump($docker_compose, 10); $docker_compose_base64 = base64_encode($docker_compose); @@ -178,13 +213,20 @@ class StartRedis $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); } - return $environment_variables->all(); - } + ray('Initial environment variables:', $environment_variables->toArray()); - private function get_redis_version() - { - $image_parts = explode(':', $this->database->image); - return $image_parts[1] ?? '0.0'; + // Overwrite with UI-set environment variables + $ui_variables = $this->database->environment_variables()->get();//this is working + ray('UI-set environment variables:', $ui_variables->toArray()); + + foreach ($ui_variables as $ui_variable) { //the overwrite is not working it is set wrong + $environment_variables = $environment_variables->reject(fn ($env) => str($env)->startsWith("{$ui_variable->key}=")); + $environment_variables->push("{$ui_variable->key}={$ui_variable->real_value}"); + } + + ray('Final environment variables:', $environment_variables->toArray()); + + return $environment_variables->all(); } private function add_custom_redis() @@ -194,7 +236,7 @@ class StartRedis } $filename = 'redis.conf'; Storage::disk('local')->put("tmp/redis.conf_{$this->database->uuid}", $this->database->redis_conf); - $path = Storage::path("tmp/redis.conf_{$this->database->uuid}"); + $path = Storage::path("tmp/redis.conf_{$this->database->uuid}"); instant_scp($path, "{$this->configuration_dir}/{$filename}", $this->database->destination->server); Storage::disk('local')->delete("tmp/redis.conf_{$this->database->uuid}"); } From cddd4b59f90dbeee57039e15cbdd1aa0fea57be0 Mon Sep 17 00:00:00 2001 From: ALsJourney <63744576+ALsJourney@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:16:40 +0200 Subject: [PATCH 0015/1011] 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 0016/1011] Added a HowTo Markdown on how to run tests --- tests/How_To_Use_Dusk.md | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/How_To_Use_Dusk.md diff --git a/tests/How_To_Use_Dusk.md b/tests/How_To_Use_Dusk.md new file mode 100644 index 000000000..fc10bff8c --- /dev/null +++ b/tests/How_To_Use_Dusk.md @@ -0,0 +1,53 @@ +# How to use Laravel Dusk in local development + +## Pre-requisites + +- Google Chrome installed on your machine (for the Chrome driver) +- everything else is already set up in the project + + +## Running Dusk in local development + +In order to use Laravel Dusk in local development, you need to run these commands: + +```bash +docker exec -it coolify php artisan dusk:chrome-driver --detect +``` + +The chrome driver will be installed under `./vendor/laravel/dusk/bin/chromedriver-linux`. + +Then you need to run the chrome-driver by hand. You can find the driver in the following path: +```bash +docker exec -it coolify ./vendor/laravel/dusk/bin/chromedriver-linux --port=9515 +``` + +### Running the tests on Apple Silicon + +If you are using an Apple Silicon machine, you need to install the Chrome driver locally on your machine with the following command: + +```bash +php artisan dusk:chrome-driver --detect +# then run it with the following command +./vendor/laravel/dusk/bin/chromedriver-mac-arm --port=9515 130 ↵ +``` + +### Running the tests + +Finally, you can run the tests with the following command: +```bash +docker exec -it coolify php artisan dusk +``` + +That's it. You should see the tests running in the terminal. +For proof, you can check the screenshot in the `tests/Browser/screenshots` folder. + +``` + + PASS Tests\Browser\LoginTest + ✓ login 3.63s + + Tests: 1 passed (1 assertions) + Duration: 3.79s + + +``` \ No newline at end of file From 1ae145bf13de253107537b3b0018e9b433b95418 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 26 Sep 2024 19:49:33 +0200 Subject: [PATCH 0017/1011] Revert "typo in redis seeder" This reverts commit 68060ef37dbe94c675925ad01b09ed05fbaab5ac. --- database/seeders/StandaloneRedisSeeder.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/database/seeders/StandaloneRedisSeeder.php b/database/seeders/StandaloneRedisSeeder.php index 7c64b17a2..e7bf3373e 100644 --- a/database/seeders/StandaloneRedisSeeder.php +++ b/database/seeders/StandaloneRedisSeeder.php @@ -11,9 +11,8 @@ class StandaloneRedisSeeder extends Seeder public function run(): void { StandaloneRedis::create([ - 'name' => 'Local Redis', - 'description' => 'Local Redis for testing', - 'redis_username' => 'redis', + 'name' => 'Local PostgreSQL', + 'description' => 'Local PostgreSQL for testing', 'redis_password' => 'redis', 'environment_id' => 1, 'destination_id' => 0, From e5b798964dce9489d0391b7337f850789801e658 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 26 Sep 2024 20:01:35 +0200 Subject: [PATCH 0018/1011] Update StartRedis.php --- app/Actions/Database/StartRedis.php | 74 ++++------------------------- 1 file changed, 9 insertions(+), 65 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 6d1548357..eeddab924 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -20,42 +20,10 @@ class StartRedis public function handle(StandaloneRedis $database) { $this->database = $database; - //$this->configuration_dir = database_configuration_dir().'/'.$this->database->uuid; - - //$this->add_custom_redis(); - - // $startCommand = "redis-server"; - // $additionalArgs = []; - - // if (!is_null($this->database->redis_conf) && !empty($this->database->redis_conf)) { - // ray("Using custom Redis configuration"); - // $additionalArgs[] = "{$this->configuration_dir}/redis.conf"; - - // // Check if the custom config contains a requirepass directive - // $configContent = file_get_contents("{$this->configuration_dir}/redis.conf"); - // if (strpos($configContent, 'requirepass') === false) { - // $additionalArgs[] = "--requirepass {$this->database->redis_password}"; - // ray("No requirepass in custom config, adding it as an argument"); - // } else { - // ray("requirepass found in custom config"); - // } - // } else { - // $additionalArgs[] = "--requirepass {$this->database->redis_password}"; - // $additionalArgs[] = "--appendonly yes"; - // ray("No custom config, using default arguments"); - // } - - // if (!empty($additionalArgs)) { - // $startCommand .= " " . implode(" ", $additionalArgs); - // } - - // ray("Final start command: " . $startCommand); $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; - $container_name = $this->database->uuid; - $this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->commands = [ @@ -63,14 +31,12 @@ class StartRedis "mkdir -p $this->configuration_dir", ]; - $persistent_storages = $this->generate_local_persistent_volumes(); $persistent_file_volumes = $this->database->fileStorages()->get(); $volume_names = $this->generate_local_persistent_volumes_only_volume_names(); $environment_variables = $this->generate_environment_variables(); $this->add_custom_redis(); - $docker_compose = [ 'services' => [ $container_name => [ @@ -116,14 +82,7 @@ class StartRedis data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); } if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { - $docker_compose['services'][$container_name]['logging'] = [ - 'driver' => 'fluentd', - 'options' => [ - 'fluentd-address' => 'tcp://127.0.0.1:24224', - 'fluentd-async' => 'true', - 'fluentd-sub-second-precision' => 'true', - ], - ]; + $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration(); } if (count($this->database->ports_mappings_array) > 0) { $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array; @@ -147,8 +106,12 @@ class StartRedis 'read_only' => true, ]; $docker_compose['services'][$container_name]['command'] = "redis-server /usr/local/etc/redis/redis.conf --requirepass {$this->database->redis_password} --appendonly yes"; - } + + // Add custom docker run options + $docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options); + $docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network); + $docker_compose = Yaml::dump($docker_compose, 10); $docker_compose_base64 = base64_encode($docker_compose); $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; @@ -201,30 +164,11 @@ class StartRedis $environment_variables->push("$env->key=$env->real_value"); } - $redis_version = $this->get_redis_version(); - - if (version_compare($redis_version, '6.0', '>=')) { - if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_USERNAME'))->isEmpty()) { - $environment_variables->push("REDIS_USERNAME={$this->database->redis_username}"); - } - } - if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) { $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); } - ray('Initial environment variables:', $environment_variables->toArray()); - - // Overwrite with UI-set environment variables - $ui_variables = $this->database->environment_variables()->get();//this is working - ray('UI-set environment variables:', $ui_variables->toArray()); - - foreach ($ui_variables as $ui_variable) { //the overwrite is not working it is set wrong - $environment_variables = $environment_variables->reject(fn ($env) => str($env)->startsWith("{$ui_variable->key}=")); - $environment_variables->push("{$ui_variable->key}={$ui_variable->real_value}"); - } - - ray('Final environment variables:', $environment_variables->toArray()); + add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables); return $environment_variables->all(); } @@ -236,8 +180,8 @@ class StartRedis } $filename = 'redis.conf'; Storage::disk('local')->put("tmp/redis.conf_{$this->database->uuid}", $this->database->redis_conf); - $path = Storage::path("tmp/redis.conf_{$this->database->uuid}"); + $path = Storage::path("tmp/redis.conf_{$this->database->uuid}"); instant_scp($path, "{$this->configuration_dir}/{$filename}", $this->database->destination->server); Storage::disk('local')->delete("tmp/redis.conf_{$this->database->uuid}"); } -} \ No newline at end of file +} From a2bca3d5b82913638831301ab25699a52259d21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Mon, 30 Sep 2024 00:43:35 +0200 Subject: [PATCH 0019/1011] added embedded Discord messages logic --- app/Dto/Notification/DiscordMessage.php | 70 +++++++++++++++++++ app/Jobs/SendMessageToDiscordJob.php | 8 +-- app/Notifications/Channels/DiscordChannel.php | 2 +- app/Notifications/Test.php | 13 ++-- 4 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 app/Dto/Notification/DiscordMessage.php diff --git a/app/Dto/Notification/DiscordMessage.php b/app/Dto/Notification/DiscordMessage.php new file mode 100644 index 000000000..88feda7e3 --- /dev/null +++ b/app/Dto/Notification/DiscordMessage.php @@ -0,0 +1,70 @@ +fields[] = [ + 'name' => $name, + 'value' => $value, + ]; + + return $this; + } + + public function toPayload(): array + { + $payload = [ + 'embeds' => [ + [ + 'title' => $this->title, + 'description' => $this->description, + 'color' => $this->color, + 'fields' => $this->addTimestampToFields($this->fields), + ], + ], + ]; + + if ($this->isCritical) { + $payload['content'] = '@here'; + } + + return $payload; + } + + private function addTimestampToFields(array $fields): array + { + $fields[] = [ + 'name' => 'Time', + 'value' => 'timestamp.':R>', + ]; + + return $fields; + } +} diff --git a/app/Jobs/SendMessageToDiscordJob.php b/app/Jobs/SendMessageToDiscordJob.php index f38cf823c..8b238a36d 100644 --- a/app/Jobs/SendMessageToDiscordJob.php +++ b/app/Jobs/SendMessageToDiscordJob.php @@ -2,6 +2,7 @@ namespace App\Jobs; +use App\Dto\Notification\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; @@ -29,7 +30,7 @@ class SendMessageToDiscordJob implements ShouldBeEncrypted, ShouldQueue public int $maxExceptions = 5; public function __construct( - public string $text, + public DiscordMessage $message, public string $webhookUrl ) {} @@ -38,9 +39,6 @@ class SendMessageToDiscordJob implements ShouldBeEncrypted, ShouldQueue */ public function handle(): void { - $payload = [ - 'content' => $this->text, - ]; - Http::post($this->webhookUrl, $payload); + Http::post($this->webhookUrl, $this->message->toPayload()); } } diff --git a/app/Notifications/Channels/DiscordChannel.php b/app/Notifications/Channels/DiscordChannel.php index f1706f138..3a33d8902 100644 --- a/app/Notifications/Channels/DiscordChannel.php +++ b/app/Notifications/Channels/DiscordChannel.php @@ -12,7 +12,7 @@ class DiscordChannel */ public function send(SendsDiscord $notifiable, Notification $notification): void { - $message = $notification->toDiscord($notifiable); + $message = $notification->toDiscord(); $webhookUrl = $notifiable->routeNotificationForDiscord(); if (! $webhookUrl) { return; diff --git a/app/Notifications/Test.php b/app/Notifications/Test.php index 3b46a9a24..f3bb1e3f6 100644 --- a/app/Notifications/Test.php +++ b/app/Notifications/Test.php @@ -2,6 +2,7 @@ namespace App\Notifications; +use App\Dto\Notification\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -29,11 +30,15 @@ class Test extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = 'Coolify: This is a test Discord notification from Coolify.'; - $message .= "\n\n"; - $message .= '[Go to your dashboard]('.base_url().')'; + $message = new DiscordMessage( + title: 'Coolify: This is a test Discord notification from Coolify.', + description: 'This is a test Discord notification from Coolify.', + color: DiscordMessage::successColor(), + ); + + $message->addField('Link', '[Go to your dashboard]('.base_url().')'); return $message; } From 9e2f0fb894dead9bf6da22398cbb4525f942ed35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Mon, 30 Sep 2024 10:06:50 +0200 Subject: [PATCH 0020/1011] updated namespace for DiscordMessage --- app/Jobs/SendMessageToDiscordJob.php | 2 +- app/{Dto/Notification => Notifications/Dto}/DiscordMessage.php | 2 +- app/Notifications/Test.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename app/{Dto/Notification => Notifications/Dto}/DiscordMessage.php (97%) diff --git a/app/Jobs/SendMessageToDiscordJob.php b/app/Jobs/SendMessageToDiscordJob.php index 8b238a36d..5b406f50f 100644 --- a/app/Jobs/SendMessageToDiscordJob.php +++ b/app/Jobs/SendMessageToDiscordJob.php @@ -2,7 +2,7 @@ namespace App\Jobs; -use App\Dto\Notification\DiscordMessage; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; diff --git a/app/Dto/Notification/DiscordMessage.php b/app/Notifications/Dto/DiscordMessage.php similarity index 97% rename from app/Dto/Notification/DiscordMessage.php rename to app/Notifications/Dto/DiscordMessage.php index 88feda7e3..39c4be718 100644 --- a/app/Dto/Notification/DiscordMessage.php +++ b/app/Notifications/Dto/DiscordMessage.php @@ -1,6 +1,6 @@ Date: Tue, 1 Oct 2024 21:38:12 +0200 Subject: [PATCH 0021/1011] updated DiscordMessages for Server notifications --- app/Notifications/Server/DockerCleanup.php | 11 +++++++---- app/Notifications/Server/ForceDisabled.php | 11 +++++++++-- app/Notifications/Server/ForceEnabled.php | 11 +++++++---- app/Notifications/Server/HighDiskUsage.php | 13 +++++++++++-- app/Notifications/Server/Revived.php | 11 +++++++---- app/Notifications/Server/Unreachable.php | 11 +++++++++-- 6 files changed, 50 insertions(+), 18 deletions(-) diff --git a/app/Notifications/Server/DockerCleanup.php b/app/Notifications/Server/DockerCleanup.php index 682ed7a1a..68d35b15e 100644 --- a/app/Notifications/Server/DockerCleanup.php +++ b/app/Notifications/Server/DockerCleanup.php @@ -5,6 +5,7 @@ namespace App\Notifications\Server; use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; @@ -49,11 +50,13 @@ class DockerCleanup extends Notification implements ShouldQueue // return $mail; // } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server '{$this->server->name}' cleanup job done!\n\n{$this->message}"; - - return $message; + return new DiscordMessage( + title: "Coolify: Server '{$this->server->name}' cleanup job done!", + description: $this->message, + color: DiscordMessage::successColor(), + ); } public function toTelegram(): array diff --git a/app/Notifications/Server/ForceDisabled.php b/app/Notifications/Server/ForceDisabled.php index 6377f2f15..a02228dc3 100644 --- a/app/Notifications/Server/ForceDisabled.php +++ b/app/Notifications/Server/ForceDisabled.php @@ -6,6 +6,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -50,9 +51,15 @@ class ForceDisabled extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server ({$this->server->name}) disabled because it is not paid!\n All automations and integrations are stopped.\nPlease update your subscription to enable the server again [here](https://app.coolify.io/subscriptions)."; + $message = new DiscordMessage( + title: "Coolify: Server ({$this->server->name}) disabled because it is not paid!", + description: 'All automations and integrations are stopped.', + color: DiscordMessage::errorColor(), + ); + + $message->addField('Link', 'Please update your subscription to enable the server again [here](https://app.coolify.io/subscriptions).'); return $message; } diff --git a/app/Notifications/Server/ForceEnabled.php b/app/Notifications/Server/ForceEnabled.php index 83594d643..c5c3e42b3 100644 --- a/app/Notifications/Server/ForceEnabled.php +++ b/app/Notifications/Server/ForceEnabled.php @@ -6,6 +6,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -50,11 +51,13 @@ class ForceEnabled extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server ({$this->server->name}) enabled again!"; - - return $message; + return new DiscordMessage( + title: "Coolify: Server '{$this->server->name}' enabled again!", + description: 'All automations and integrations are started.', + color: DiscordMessage::successColor(), + ); } public function toTelegram(): array diff --git a/app/Notifications/Server/HighDiskUsage.php b/app/Notifications/Server/HighDiskUsage.php index 34cb22091..c91b8c266 100644 --- a/app/Notifications/Server/HighDiskUsage.php +++ b/app/Notifications/Server/HighDiskUsage.php @@ -6,6 +6,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -52,9 +53,17 @@ class HighDiskUsage extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->docker_cleanup_threshold}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup."; + $message = new DiscordMessage( + title: "Coolify: Server '{$this->server->name}' high disk usage detected!", + description: 'Please cleanup your disk to prevent data-loss.', + color: DiscordMessage::errorColor(), + ); + + $message->addField('Disk usage', "{$this->disk_usage}%"); + $message->addField('Threshold', "{$this->docker_cleanup_threshold}%"); + $message->addField('Link', 'Here are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.'); return $message; } diff --git a/app/Notifications/Server/Revived.php b/app/Notifications/Server/Revived.php index 3f2b3b696..c3a3f389a 100644 --- a/app/Notifications/Server/Revived.php +++ b/app/Notifications/Server/Revived.php @@ -8,6 +8,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -72,11 +73,13 @@ class Revived extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Server '{$this->server->name}' revived. All automations & integrations are turned on again!"; - - return $message; + return new DiscordMessage( + title: "Coolify: Server '{$this->server->name}' revived.", + description: 'All automations & integrations are turned on again!', + color: DiscordMessage::successColor(), + ); } public function toTelegram(): array diff --git a/app/Notifications/Server/Unreachable.php b/app/Notifications/Server/Unreachable.php index 2fb83559a..7e56123e4 100644 --- a/app/Notifications/Server/Unreachable.php +++ b/app/Notifications/Server/Unreachable.php @@ -6,6 +6,7 @@ use App\Models\Server; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -63,9 +64,15 @@ class Unreachable extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server and turn on all automations & integrations."; + $message = new DiscordMessage( + title: "Coolify: Your server '{$this->server->name}' is unreachable.", + description: 'All automations & integrations are turned off! Please check your server!', + color: DiscordMessage::errorColor(), + ); + + $message->addField('IMPORTANT', 'We automatically try to revive your server and turn on all automations & integrations.'); return $message; } From cb5dc13bf1260594c80b913bc44de449f6bdd9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Tue, 1 Oct 2024 21:42:13 +0200 Subject: [PATCH 0022/1011] updated DiscordMessages for Internal&ScheduledTask notifications --- app/Notifications/Dto/DiscordMessage.php | 5 +++++ app/Notifications/Internal/GeneralNotification.php | 9 +++++++-- app/Notifications/ScheduledTask/TaskFailed.php | 13 +++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/Notifications/Dto/DiscordMessage.php b/app/Notifications/Dto/DiscordMessage.php index 39c4be718..0d0028f56 100644 --- a/app/Notifications/Dto/DiscordMessage.php +++ b/app/Notifications/Dto/DiscordMessage.php @@ -28,6 +28,11 @@ class DiscordMessage return hexdec('ff705f'); } + public static function infoColor(): int + { + return hexdec('4f545c'); + } + public function addField(string $name, string $value): self { $this->fields[] = [ diff --git a/app/Notifications/Internal/GeneralNotification.php b/app/Notifications/Internal/GeneralNotification.php index 1d4d648c8..48e7d8340 100644 --- a/app/Notifications/Internal/GeneralNotification.php +++ b/app/Notifications/Internal/GeneralNotification.php @@ -4,6 +4,7 @@ namespace App\Notifications\Internal; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; @@ -32,9 +33,13 @@ class GeneralNotification extends Notification implements ShouldQueue return $channels; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return $this->message; + return new DiscordMessage( + title: 'Coolify: General Notification', + description: $this->message, + color: DiscordMessage::infoColor(), + ); } public function toTelegram(): array diff --git a/app/Notifications/ScheduledTask/TaskFailed.php b/app/Notifications/ScheduledTask/TaskFailed.php index 479cc1aa1..aac665fb6 100644 --- a/app/Notifications/ScheduledTask/TaskFailed.php +++ b/app/Notifications/ScheduledTask/TaskFailed.php @@ -3,6 +3,7 @@ namespace App\Notifications\ScheduledTask; use App\Models\ScheduledTask; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -46,9 +47,17 @@ class TaskFailed extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return "Coolify: Scheduled task ({$this->task->name}, [link]({$this->url})) failed with output: {$this->output}"; + $message = new DiscordMessage( + title: "Coolify: Scheduled task ({$this->task->name}) failed.", + description: "Output: {$this->output}", + color: DiscordMessage::errorColor(), + ); + + $message->addField('Link', '[Open task in Coolify]('.$this->url.')'); + + return $message; } public function toTelegram(): array From 53a6e97ca37069347132a65c591d71aac6198bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Tue, 1 Oct 2024 21:46:56 +0200 Subject: [PATCH 0023/1011] updated DiscordMessages for Database notifications --- app/Notifications/Database/BackupFailed.php | 15 +++++++++++++-- app/Notifications/Database/BackupSuccess.php | 13 +++++++++++-- app/Notifications/Database/DailyBackup.php | 9 +++++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/Notifications/Database/BackupFailed.php b/app/Notifications/Database/BackupFailed.php index 77024c05b..ef6128c5f 100644 --- a/app/Notifications/Database/BackupFailed.php +++ b/app/Notifications/Database/BackupFailed.php @@ -3,6 +3,7 @@ namespace App\Notifications\Database; use App\Models\ScheduledDatabaseBackup; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -45,9 +46,19 @@ class BackupFailed extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return "Coolify: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was FAILED.\n\nReason:\n{$this->output}"; + $message = new DiscordMessage( + title: "Coolify: Database backup for {$this->name} (db:{$this->database_name}) has FAILED.", + description: 'Please check the output below for more information.', + color: DiscordMessage::errorColor(), + isCritical: true, + ); + + $message->addField('Frequency', $this->frequency); + $message->addField('Output', $this->output); + + return $message; } public function toTelegram(): array diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php index f8dc6eb56..fa9eb616c 100644 --- a/app/Notifications/Database/BackupSuccess.php +++ b/app/Notifications/Database/BackupSuccess.php @@ -3,6 +3,7 @@ namespace App\Notifications\Database; use App\Models\ScheduledDatabaseBackup; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -44,9 +45,17 @@ class BackupSuccess extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return "Coolify: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was successful."; + $message = new DiscordMessage( + title: "Coolify: Database backup for {$this->name} (db:{$this->database_name}) was successful.", + description: 'Please check the output below for more information.', + color: DiscordMessage::successColor(), + ); + + $message->addField('Frequency', $this->frequency); + + return $message; } public function toTelegram(): array diff --git a/app/Notifications/Database/DailyBackup.php b/app/Notifications/Database/DailyBackup.php index a51ac6283..b53a56903 100644 --- a/app/Notifications/Database/DailyBackup.php +++ b/app/Notifications/Database/DailyBackup.php @@ -4,6 +4,7 @@ namespace App\Notifications\Database; use App\Notifications\Channels\DiscordChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Channels\MailChannel; @@ -34,9 +35,13 @@ class DailyBackup extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - return 'Coolify: Daily backup statuses'; + return new DiscordMessage( + title: 'Coolify: Daily backup statuses', + description: 'Nothing to report.', + color: DiscordMessage::infoColor(), + ); // todo: is this necessary notification? what is the purpose of this notification? } public function toTelegram(): array From aac491da251edb953f112a9ea53b2420be3398e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Tue, 1 Oct 2024 21:48:14 +0200 Subject: [PATCH 0024/1011] updated DiscordMessages for Container notifications --- app/Notifications/Container/ContainerRestarted.php | 9 +++++++-- app/Notifications/Container/ContainerStopped.php | 11 +++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/Notifications/Container/ContainerRestarted.php b/app/Notifications/Container/ContainerRestarted.php index 23f6de264..49c2cecf0 100644 --- a/app/Notifications/Container/ContainerRestarted.php +++ b/app/Notifications/Container/ContainerRestarted.php @@ -3,6 +3,7 @@ namespace App\Notifications\Container; use App\Models\Server; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -34,9 +35,13 @@ class ContainerRestarted extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}"; + $message = new DiscordMessage( + title: "Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}", + description: 'Please check the output below for more information.', + color: DiscordMessage::infoColor(), + ); return $message; } diff --git a/app/Notifications/Container/ContainerStopped.php b/app/Notifications/Container/ContainerStopped.php index bcf5e67a5..d8ed2316b 100644 --- a/app/Notifications/Container/ContainerStopped.php +++ b/app/Notifications/Container/ContainerStopped.php @@ -3,6 +3,7 @@ namespace App\Notifications\Container; use App\Models\Server; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -34,11 +35,13 @@ class ContainerStopped extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = "Coolify: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}"; - - return $message; + return new DiscordMessage( + title: "Coolify: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}", + description: 'Please check the output below for more information.', + color: DiscordMessage::errorColor(), + ); } public function toTelegram(): array From 3b4759f349912b2d5c6cf5434fb0f3b7b28cd1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nov=C3=A1k?= Date: Tue, 1 Oct 2024 22:07:24 +0200 Subject: [PATCH 0025/1011] updated DiscordMessages for Application notifications --- .../Application/DeploymentFailed.php | 23 +++++++++++---- .../Application/DeploymentSuccess.php | 29 ++++++++++++------- .../Application/StatusChanged.php | 13 ++++++--- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/app/Notifications/Application/DeploymentFailed.php b/app/Notifications/Application/DeploymentFailed.php index 1809da368..b255cc667 100644 --- a/app/Notifications/Application/DeploymentFailed.php +++ b/app/Notifications/Application/DeploymentFailed.php @@ -4,6 +4,7 @@ namespace App\Notifications\Application; use App\Models\Application; use App\Models\ApplicationPreview; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -72,14 +73,26 @@ class DeploymentFailed extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { if ($this->preview) { - $message = 'Coolify: Pull request #'.$this->preview->pull_request_id.' of '.$this->application_name.' ('.$this->preview->fqdn.') deployment failed: '; - $message .= '[View Deployment Logs]('.$this->deployment_url.')'; + $message = new DiscordMessage( + title: 'Coolify: Deployment failed of pull request #'.$this->preview->pull_request_id.' of '.$this->application_name, + description: 'Check in the link below', + color: DiscordMessage::errorColor(), + isCritical: true, + ); + + $message->addField('Deployment Logs', '[Here]('.$this->deployment_url.')'); } else { - $message = 'Coolify: Deployment failed of '.$this->application_name.' ('.$this->fqdn.'): '; - $message .= '[View Deployment Logs]('.$this->deployment_url.')'; + $message = new DiscordMessage( + title: 'Coolify: Deployment failed of '.$this->application_name, + description: 'Check in the link below', + color: DiscordMessage::errorColor(), + isCritical: true, + ); + + $message->addField('Deployment Logs', '[Here]('.$this->deployment_url.')'); } return $message; diff --git a/app/Notifications/Application/DeploymentSuccess.php b/app/Notifications/Application/DeploymentSuccess.php index 5085065c2..96ec2ce82 100644 --- a/app/Notifications/Application/DeploymentSuccess.php +++ b/app/Notifications/Application/DeploymentSuccess.php @@ -4,6 +4,7 @@ namespace App\Notifications\Application; use App\Models\Application; use App\Models\ApplicationPreview; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -78,24 +79,32 @@ class DeploymentSuccess extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { if ($this->preview) { - $message = 'Coolify: New PR'.$this->preview->pull_request_id.' version successfully deployed of '.$this->application_name.' + $message = new DiscordMessage( + title: "Coolify: New PR{$this->preview->pull_request_id} version successfully deployed of {$this->application_name}", + description: 'Check in the links below.', + color: DiscordMessage::successColor(), + ); -'; if ($this->preview->fqdn) { - $message .= '[Open Application]('.$this->preview->fqdn.') | '; + $message->addField('Open Application', '[Here]('.$this->preview->fqdn.')'); } - $message .= '[Deployment logs]('.$this->deployment_url.')'; - } else { - $message = 'Coolify: New version successfully deployed of '.$this->application_name.' -'; + $message->addField('Deployment logs', '[Here]('.$this->deployment_url.')'); + } else { + $message = new DiscordMessage( + title: "Coolify: New version successfully deployed of {$this->application_name}", + description: 'Check in the links below.', + color: DiscordMessage::successColor(), + ); + if ($this->fqdn) { - $message .= '[Open Application]('.$this->fqdn.') | '; + $message->addField('Open Application', '[Here]('.$this->fqdn.')'); } - $message .= '[Deployment logs]('.$this->deployment_url.')'; + + $message->addField('Deployment logs', '[Here]('.$this->deployment_url.')'); } return $message; diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index 53ed8a589..abc93a3a4 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -3,6 +3,7 @@ namespace App\Notifications\Application; use App\Models\Application; +use App\Notifications\Dto\DiscordMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -55,12 +56,16 @@ class StatusChanged extends Notification implements ShouldQueue return $mail; } - public function toDiscord(): string + public function toDiscord(): DiscordMessage { - $message = 'Coolify: '.$this->resource_name.' has been stopped. + $message = new DiscordMessage( + title: "Coolify: {$this->resource_name} has been stopped", + description: 'Check the application in Coolify', + color: DiscordMessage::errorColor(), + isCritical: true, + ); -'; - $message .= '[Open Application in Coolify]('.$this->resource_url.')'; + $message->addField('Link', '[Open Application in Coolify]('.$this->resource_url.')'); return $message; } From 67b17e871fe75e04a872da0f06c79ecb6df0aa39 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Thu, 3 Oct 2024 13:26:27 -0400 Subject: [PATCH 0026/1011] 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 8e50a98e1b55c31778fb02eb20415e6d11b273a0 Mon Sep 17 00:00:00 2001 From: Daniel Alves Date: Thu, 3 Oct 2024 16:10:22 -0300 Subject: [PATCH 0027/1011] feat: add coder service tamplate and logo --- public/svgs/coder.svg | 8 ++++++ templates/compose/coder.yaml | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 public/svgs/coder.svg create mode 100644 templates/compose/coder.yaml diff --git a/public/svgs/coder.svg b/public/svgs/coder.svg new file mode 100644 index 000000000..45b7f795c --- /dev/null +++ b/public/svgs/coder.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/templates/compose/coder.yaml b/templates/compose/coder.yaml new file mode 100644 index 000000000..9d9696f5c --- /dev/null +++ b/templates/compose/coder.yaml @@ -0,0 +1,50 @@ +# documentation: https://coder.com/docs +# slogan: Coder is an open-source platform for creating and managing cloud development environments on your infrastructure, with the tools and IDEs your developers already love. +# tags: coder,development,environment,self-hosted,postgres +# logo: svgs/coder.svg +# port: 7080 + +version: "3.9" +services: + coder: + image: "ghcr.io/coder/coder:${CODER_VERSION:-latest}" + environment: + - "SERVICE_FQDN_CODER=${SERVICE_FQDN_CODER}" + - "CODER_PG_CONNECTION_URL=postgresql://${POSTGRES_USER:-username}:${POSTGRES_PASSWORD:-password}@database/${POSTGRES_DB:-coder}?sslmode=disable" + - "CODER_HTTP_ADDRESS=0.0.0.0:7080" + - "CODER_ACCESS_URL=${SERVICE_FQDN_CODER}" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + ports: + - "7080:7080" + depends_on: + database: + condition: service_healthy + healthcheck: + test: + - CMD + - wget + - "-q" + - "--spider" + - "http://localhost:7080" + interval: 5s + timeout: 20s + retries: 10 + database: + image: "postgres:16.4-alpine" + restart: unless-stopped + environment: + POSTGRES_USER: "${POSTGRES_USER:-username}" + POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-password}" + POSTGRES_DB: "${POSTGRES_DB:-coder}" + volumes: + - "coder_data:/var/lib/postgresql/data" + healthcheck: + test: + - CMD-SHELL + - "pg_isready -U ${POSTGRES_USER:-username} -d ${POSTGRES_DB:-coder}" + interval: 5s + timeout: 5s + retries: 5 +volumes: + coder_data: null From b4593ec1d225ffe15a471687d35df2fbac678dd3 Mon Sep 17 00:00:00 2001 From: "Alexander G." Date: Fri, 4 Oct 2024 12:42:42 +0300 Subject: [PATCH 0028/1011] Update trigger.yaml --- templates/compose/trigger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/trigger.yaml b/templates/compose/trigger.yaml index 6181a6925..2e8e9f9a7 100644 --- a/templates/compose/trigger.yaml +++ b/templates/compose/trigger.yaml @@ -6,7 +6,7 @@ services: trigger: - image: ghcr.io/triggerdotdev/trigger.dev:latest + image: ghcr.io/triggerdotdev/trigger.dev:main environment: - SERVICE_FQDN_TRIGGER_3000 - LOGIN_ORIGIN=$SERVICE_FQDN_TRIGGER From ab8b36266bed9182eaa867eaf41ddc51a3e90056 Mon Sep 17 00:00:00 2001 From: "Alexander G." Date: Fri, 4 Oct 2024 12:44:19 +0300 Subject: [PATCH 0029/1011] Update trigger-with-external-database.yaml --- templates/compose/trigger-with-external-database.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/trigger-with-external-database.yaml b/templates/compose/trigger-with-external-database.yaml index dcd3e2b97..00702452b 100644 --- a/templates/compose/trigger-with-external-database.yaml +++ b/templates/compose/trigger-with-external-database.yaml @@ -6,7 +6,7 @@ services: trigger: - image: ghcr.io/triggerdotdev/trigger.dev:latest + image: ghcr.io/triggerdotdev/trigger.dev:main environment: - SERVICE_FQDN_TRIGGER_3000 - LOGIN_ORIGIN=$SERVICE_FQDN_TRIGGER From b84cecfd3f757d792017892c793f4bee017a22af Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Sat, 5 Oct 2024 10:21:14 +0300 Subject: [PATCH 0030/1011] Added missing services. --- templates/compose/trigger.yaml | 44 ++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/templates/compose/trigger.yaml b/templates/compose/trigger.yaml index 2e8e9f9a7..1064ef789 100644 --- a/templates/compose/trigger.yaml +++ b/templates/compose/trigger.yaml @@ -11,15 +11,23 @@ services: - SERVICE_FQDN_TRIGGER_3000 - LOGIN_ORIGIN=$SERVICE_FQDN_TRIGGER - APP_ORIGIN=$SERVICE_FQDN_TRIGGER + - ELECTRIC_ORIGIN=http://electric:3000 - MAGIC_LINK_SECRET=$SERVICE_PASSWORD_64_MAGIC - ENCRYPTION_KEY=$SERVICE_PASSWORD_64_ENCRYPTION - SESSION_SECRET=$SERVICE_PASSWORD_64_SESSION + - PROVIDER_SECRET=$SERVICE_PASSWORD_64_PROVIDER + - COORDINATOR_SECRET=$SERVICE_PASSWORD_64_COORDINATOR - POSTGRES_USER=$SERVICE_USER_POSTGRES - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - POSTGRES_DB=${POSTGRES_DB:-trigger} - POSTGRES_HOST=postgres - DATABASE_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB - DIRECT_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_TLS_DISABLED=true + - V3_ENABLED=${V3_ENABLED:-true} + - REMIX_APP_PORT=${REMIX_APP_PORT:-3000} - RUNTIME_PLATFORM=docker-compose - NODE_ENV=production - AUTH_GITHUB_CLIENT_ID=${AUTH_GITHUB_CLIENT_ID} @@ -30,10 +38,43 @@ services: depends_on: postgresql: condition: service_healthy + redis: + condition: service_healthy + electric: + condition: service_healthy healthcheck: - test: ["NONE"] + test: + - CMD-SHELL + - pwd + electric: + image: electricsql/electric + restart: always + environment: + DATABASE_URL: postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + depends_on: + postgresql: + condition: service_healthy + healthcheck: + test: + - CMD-SHELL + - pwd + redis: + image: "redis:7" + environment: + - ALLOW_EMPTY_PASSWORD=yes + restart: always + healthcheck: + test: + - CMD-SHELL + - "redis-cli -h localhost -p 6379 ping" + interval: 5s + timeout: 5s + retries: 3 + volumes: + - redis-data:/data postgresql: image: postgres:16-alpine + restart: always volumes: - postgresql-data:/var/lib/postgresql/data environment: @@ -45,4 +86,3 @@ services: interval: 5s timeout: 20s retries: 10 - From 83bcf981c255d63548ea7269bdd3c86af4a431c7 Mon Sep 17 00:00:00 2001 From: Luan Estradioto Date: Wed, 9 Oct 2024 00:14:27 -0300 Subject: [PATCH 0031/1011] fix autocompletes --- .../views/components/modal-confirmation.blade.php | 12 ++++++++---- .../views/livewire/notifications/telegram.blade.php | 7 ++++--- resources/views/livewire/settings-email.blade.php | 3 ++- resources/views/livewire/settings-oauth.blade.php | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/resources/views/components/modal-confirmation.blade.php b/resources/views/components/modal-confirmation.blade.php index fde75ab24..adcae3eca 100644 --- a/resources/views/components/modal-confirmation.blade.php +++ b/resources/views/components/modal-confirmation.blade.php @@ -268,13 +268,17 @@

Please enter your password to confirm this destructive action.

- -
- + + +

@error('password') diff --git a/resources/views/livewire/notifications/telegram.blade.php b/resources/views/livewire/notifications/telegram.blade.php index 3f57ff471..0b9d5a874 100644 --- a/resources/views/livewire/notifications/telegram.blade.php +++ b/resources/views/livewire/notifications/telegram.blade.php @@ -20,11 +20,12 @@
- + id="team.telegram_chat_id" label="Chat ID" />
@if (data_get($team, 'telegram_enabled'))

Subscribe to events

diff --git a/resources/views/livewire/settings-email.blade.php b/resources/views/livewire/settings-email.blade.php index 37d395cd8..0e99c9586 100644 --- a/resources/views/livewire/settings-email.blade.php +++ b/resources/views/livewire/settings-email.blade.php @@ -36,7 +36,8 @@
- +
diff --git a/resources/views/livewire/settings-oauth.blade.php b/resources/views/livewire/settings-oauth.blade.php index 9a94d3c2b..eefd10c7c 100644 --- a/resources/views/livewire/settings-oauth.blade.php +++ b/resources/views/livewire/settings-oauth.blade.php @@ -25,7 +25,7 @@ + type="password" label="Client Secret" autocomplete="new-password" /> @if ($oauth_setting->provider == 'azure') From e6c249ffea070441cb8ea4c6e0adbd2cf2980602 Mon Sep 17 00:00:00 2001 From: Luan Estradioto Date: Wed, 9 Oct 2024 01:20:13 -0300 Subject: [PATCH 0032/1011] add to resend too --- resources/views/livewire/settings-email.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/settings-email.blade.php b/resources/views/livewire/settings-email.blade.php index 0e99c9586..c36e98808 100644 --- a/resources/views/livewire/settings-email.blade.php +++ b/resources/views/livewire/settings-email.blade.php @@ -58,7 +58,7 @@
+ label="Host" autocomplete="new-password" />
From b1e91252f3ccb640c1d2cd29edc23454775e70db Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Wed, 9 Oct 2024 12:54:19 +0300 Subject: [PATCH 0033/1011] Updated trigger service --- templates/compose/trigger.yaml | 122 ++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 32 deletions(-) diff --git a/templates/compose/trigger.yaml b/templates/compose/trigger.yaml index 1064ef789..e33459535 100644 --- a/templates/compose/trigger.yaml +++ b/templates/compose/trigger.yaml @@ -4,37 +4,56 @@ # logo: svgs/trigger.png # port: 3000 +x-common-env: &common-env + PORT: 3030 + REMIX_APP_PORT: 3000 + NODE_ENV: production + RUNTIME_PLATFORM: docker-compose + V3_ENABLED: true + INTERNAL_OTEL_TRACE_DISABLED: 1 + INTERNAL_OTEL_TRACE_LOGGING_ENABLED: 0 + POSTGRES_USER: $SERVICE_USER_POSTGRES + POSTGRES_PASSWORD: $SERVICE_PASSWORD_POSTGRES + POSTGRES_DB: ${POSTGRES_DB:-trigger} + MAGIC_LINK_SECRET: $SERVICE_PASSWORD_64_MAGIC + SESSION_SECRET: $SERVICE_PASSWORD_64_SESSION + ENCRYPTION_KEY: $SERVICE_PASSWORD_64_ENCRYPTION + PROVIDER_SECRET: $SERVICE_PASSWORD_64_PROVIDER + COORDINATOR_SECRET: $SERVICE_PASSWORD_64_COORDINATOR + DATABASE_HOST: postgresql + DATABASE_URL: postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + DIRECT_URL: postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_TLS_DISABLED: true + COORDINATOR_HOST: 127.0.0.1 + COORDINATOR_PORT: 9020 + WHITELISTED_EMAILS: "" + ADMIN_EMAILS: "" + DEFAULT_ORG_EXECUTION_CONCURRENCY_LIMIT: 300 + DEFAULT_ENV_EXECUTION_CONCURRENCY_LIMIT: 100 + DEPLOY_REGISTRY_HOST: docker.io + DEPLOY_REGISTRY_NAMESPACE: trigger + REGISTRY_HOST: ${DEPLOY_REGISTRY_HOST} + REGISTRY_NAMESPACE: ${DEPLOY_REGISTRY_NAMESPACE} + AUTH_GITHUB_CLIENT_ID: ${AUTH_GITHUB_CLIENT_ID} + AUTH_GITHUB_CLIENT_SECRET: ${AUTH_GITHUB_CLIENT_SECRET} + RESEND_API_KEY: ${RESEND_API_KEY} + FROM_EMAIL: ${FROM_EMAIL} + REPLY_TO_EMAIL: ${REPLY_TO_EMAIL} + LOGIN_ORIGIN: $SERVICE_FQDN_TRIGGER_3000 + APP_ORIGIN: $SERVICE_FQDN_TRIGGER_3000 + DEV_OTEL_EXPORTER_OTLP_ENDPOINT: $SERVICE_FQDN_TRIGGER_3000/otel + OTEL_EXPORTER_OTLP_ENDPOINT: "http://trigger:3040/otel" + ELECTRIC_ORIGIN: http://electric:3000 + services: trigger: - image: ghcr.io/triggerdotdev/trigger.dev:main + image: ghcr.io/triggerdotdev/trigger.dev:v3 + restart: always environment: - - SERVICE_FQDN_TRIGGER_3000 - - LOGIN_ORIGIN=$SERVICE_FQDN_TRIGGER - - APP_ORIGIN=$SERVICE_FQDN_TRIGGER - - ELECTRIC_ORIGIN=http://electric:3000 - - MAGIC_LINK_SECRET=$SERVICE_PASSWORD_64_MAGIC - - ENCRYPTION_KEY=$SERVICE_PASSWORD_64_ENCRYPTION - - SESSION_SECRET=$SERVICE_PASSWORD_64_SESSION - - PROVIDER_SECRET=$SERVICE_PASSWORD_64_PROVIDER - - COORDINATOR_SECRET=$SERVICE_PASSWORD_64_COORDINATOR - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_DB=${POSTGRES_DB:-trigger} - - POSTGRES_HOST=postgres - - DATABASE_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB - - DIRECT_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB - - REDIS_HOST=redis - - REDIS_PORT=6379 - - REDIS_TLS_DISABLED=true - - V3_ENABLED=${V3_ENABLED:-true} - - REMIX_APP_PORT=${REMIX_APP_PORT:-3000} - - RUNTIME_PLATFORM=docker-compose - - NODE_ENV=production - - AUTH_GITHUB_CLIENT_ID=${AUTH_GITHUB_CLIENT_ID} - - AUTH_GITHUB_CLIENT_SECRET=${AUTH_GITHUB_CLIENT_SECRET} - - RESEND_API_KEY=${RESEND_API_KEY} - - FROM_EMAIL=${FROM_EMAIL} - - REPLY_TO_EMAIL=${REPLY_TO_EMAIL} + SERVICE_FQDN_TRIGGER_3000: "" + <<: *common-env depends_on: postgresql: condition: service_healthy @@ -50,7 +69,7 @@ services: image: electricsql/electric restart: always environment: - DATABASE_URL: postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/$POSTGRES_DB + <<: *common-env depends_on: postgresql: condition: service_healthy @@ -78,11 +97,50 @@ services: volumes: - postgresql-data:/var/lib/postgresql/data environment: - - POSTGRES_USER=$SERVICE_USER_POSTGRES - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_DB=${POSTGRES_DB:-trigger} + <<: *common-env + command: + - -c + - wal_level=logical healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 20s retries: 10 + docker-provider: + image: ghcr.io/triggerdotdev/provider/docker:v3 + restart: always + volumes: + - /var/run/docker.sock:/var/run/docker.sock + user: root + depends_on: + trigger: + condition: service_healthy + environment: + <<: *common-env + PLATFORM_HOST: trigger + PLATFORM_WS_PORT: 3030 + SECURE_CONNECTION: "false" + PLATFORM_SECRET: $PROVIDER_SECRET + coordinator: + image: ghcr.io/triggerdotdev/coordinator:v3 + restart: always + volumes: + - /var/run/docker.sock:/var/run/docker.sock + user: root + depends_on: + trigger: + condition: service_healthy + environment: + <<: *common-env + PLATFORM_HOST: trigger + PLATFORM_WS_PORT: 3030 + SECURE_CONNECTION: "false" + PLATFORM_SECRET: $COORDINATOR_SECRET + healthcheck: + test: + - CMD-SHELL + - pwd + +volumes: + postgresql-data: + redis-data: From 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 0034/1011] 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 0035/1011] 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 0036/1011] 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 0037/1011] 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 0038/1011] 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 b997b7393b40f300ea1064cc84d304aeb8ae9911 Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 11 Oct 2024 02:44:52 +1100 Subject: [PATCH 0039/1011] feat: allow disabling default redirect, set status to 503 --- app/Listeners/ProxyStartedNotification.php | 2 +- app/Livewire/Server/Proxy.php | 16 +- app/Models/Server.php | 139 +++++++++--------- .../views/livewire/server/proxy.blade.php | 9 +- .../proxy/dynamic-configurations.blade.php | 2 +- 5 files changed, 91 insertions(+), 77 deletions(-) diff --git a/app/Listeners/ProxyStartedNotification.php b/app/Listeners/ProxyStartedNotification.php index d0541b162..9045b1e5c 100644 --- a/app/Listeners/ProxyStartedNotification.php +++ b/app/Listeners/ProxyStartedNotification.php @@ -14,7 +14,7 @@ class ProxyStartedNotification public function handle(ProxyStarted $event): void { $this->server = data_get($event, 'data'); - $this->server->setupDefault404Redirect(); + $this->server->setupDefaultRedirect(); $this->server->setupDynamicProxyConfiguration(); $this->server->proxy->force_stop = false; $this->server->save(); diff --git a/app/Livewire/Server/Proxy.php b/app/Livewire/Server/Proxy.php index 55d0c4966..fbdba53c1 100644 --- a/app/Livewire/Server/Proxy.php +++ b/app/Livewire/Server/Proxy.php @@ -16,6 +16,7 @@ class Proxy extends Component public $proxy_settings = null; + public bool $redirect_enabled = true; public ?string $redirect_url = null; protected $listeners = ['proxyStatusUpdated', 'saveConfiguration' => 'submit']; @@ -27,6 +28,7 @@ class Proxy extends Component public function mount() { $this->selectedProxy = $this->server->proxyType(); + $this->redirect_enabled = data_get($this->server, 'proxy.redirect_enabled', true); $this->redirect_url = data_get($this->server, 'proxy.redirect_url'); } @@ -65,13 +67,25 @@ class Proxy extends Component } } + public function instantSaveRedirect() + { + try { + $this->server->proxy->redirect_enabled = $this->redirect_enabled; + $this->server->save(); + $this->server->setupDefaultRedirect(); + $this->dispatch('success', 'Proxy configuration saved.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function submit() { try { SaveConfiguration::run($this->server, $this->proxy_settings); $this->server->proxy->redirect_url = $this->redirect_url; $this->server->save(); - $this->server->setupDefault404Redirect(); + $this->server->setupDefaultRedirect(); $this->dispatch('success', 'Proxy configuration saved.'); } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Models/Server.php b/app/Models/Server.php index 8864deef1..0a92caa60 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -94,6 +94,14 @@ class Server extends BaseModel ]); } } + if (!isset($server->proxy->redirect_enabled)) { + $server->proxy->redirect_enabled = true; + } + }); + static::retrieved(function ($server) { + if (!isset($server->proxy->redirect_enabled)) { + $server->proxy->redirect_enabled = true; + } }); static::deleting(function ($server) { $server->destinations()->each(function ($destination) { @@ -164,70 +172,72 @@ class Server extends BaseModel return $this->proxyType() && $this->proxyType() !== 'NONE' && $this->isFunctional() && ! $this->isSwarmWorker() && ! $this->settings->is_build_server; } - public function setupDefault404Redirect() + public function setupDefaultRedirect() { + $banner = + "# This file is generated by Coolify, do not edit it manually.\n" . + "# Disable the default redirect to customize (only if you know what are you doing).\n\n"; $dynamic_conf_path = $this->proxyPath().'/dynamic'; $proxy_type = $this->proxyType(); + $redirect_enabled = $this->proxy->redirect_enabled ?? true; $redirect_url = $this->proxy->redirect_url; + if ($proxy_type === ProxyTypes::TRAEFIK->value) { - $default_redirect_file = "$dynamic_conf_path/default_redirect_404.yaml"; + $default_redirect_file = "$dynamic_conf_path/default_redirect_503.yaml"; } elseif ($proxy_type === ProxyTypes::CADDY->value) { - $default_redirect_file = "$dynamic_conf_path/default_redirect_404.caddy"; + $default_redirect_file = "$dynamic_conf_path/default_redirect_503.caddy"; } - if (empty($redirect_url)) { + + instant_remote_process([ + "mkdir -p $dynamic_conf_path", + "rm -f $dynamic_conf_path/default_redirect_404.yaml", + "rm -f $dynamic_conf_path/default_redirect_404.caddy", + ], $this); + + if (!$redirect_enabled) { + instant_remote_process(["rm -f $default_redirect_file"], $this); + } else { if ($proxy_type === ProxyTypes::CADDY->value) { - $conf = ':80, :443 { -respond 404 + if (empty($redirect_url)) { + $conf = ':80, :443 { + respond 503 }'; - $conf = - "# 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([ - "mkdir -p $dynamic_conf_path", - "echo '$base64' | base64 -d | tee $default_redirect_file > /dev/null", - ], $this); - $this->reloadCaddy(); - - return; - } - instant_remote_process([ - "mkdir -p $dynamic_conf_path", - "rm -f $default_redirect_file", - ], $this); - - return; - } - if ($proxy_type === ProxyTypes::TRAEFIK->value) { - $dynamic_conf = [ - 'http' => [ - 'routers' => [ - 'catchall' => [ - 'entryPoints' => [ - 0 => 'http', - 1 => 'https', - ], - 'service' => 'noop', - 'rule' => 'HostRegexp(`{catchall:.*}`)', - 'priority' => 1, - 'middlewares' => [ - 0 => 'redirect-regexp@file', + } else { + $conf = ":80, :443 { + redir $redirect_url +}"; + } + } elseif ($proxy_type === ProxyTypes::TRAEFIK->value) { + $dynamic_conf = [ + 'http' => [ + 'routers' => [ + 'catchall' => [ + 'entryPoints' => [ + 0 => 'http', + 1 => 'https', + ], + 'service' => 'noop', + 'rule' => 'HostRegexp(`{catchall:.*}`)', + 'priority' => 1, ], ], - ], - 'services' => [ - 'noop' => [ - 'loadBalancer' => [ - 'servers' => [ - 0 => [ - 'url' => '', - ], + 'services' => [ + 'noop' => [ + 'loadBalancer' => [ + 'servers' => [], ], ], ], ], - 'middlewares' => [ + ]; + if (!empty($redirect_url)) { + $dynamic_conf['http']['routers']['catchall']['middlewares'] = [ + 0 => 'redirect-regexp@file', + ]; + $dynamic_conf['http']['services']['noop']['loadBalancer']['servers'][0] = [ + 'url' => '', + ]; + $dynamic_conf['http']['middlewares'] = [ 'redirect-regexp' => [ 'redirectRegex' => [ 'regex' => '(.*)', @@ -235,32 +245,17 @@ respond 404 'permanent' => false, ], ], - ], - ], - ]; - $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". - $conf; - - $base64 = base64_encode($conf); - } elseif ($proxy_type === ProxyTypes::CADDY->value) { - $conf = ":80, :443 { - 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". - $conf; + ]; + } + $conf = Yaml::dump($dynamic_conf, 12, 2); + } + $conf = $banner . $conf; $base64 = base64_encode($conf); + instant_remote_process([ + "echo '$base64' | base64 -d | tee $default_redirect_file > /dev/null", + ], $this); } - instant_remote_process([ - "mkdir -p $dynamic_conf_path", - "echo '$base64' | base64 -d | tee $default_redirect_file > /dev/null", - ], $this); - if ($proxy_type === 'CADDY') { $this->reloadCaddy(); } diff --git a/resources/views/livewire/server/proxy.blade.php b/resources/views/livewire/server/proxy.blade.php index 25c3f7acd..5748a5876 100644 --- a/resources/views/livewire/server/proxy.blade.php +++ b/resources/views/livewire/server/proxy.blade.php @@ -28,6 +28,13 @@ id="server.settings.generate_exact_labels" label="Generate labels only for {{ str($server->proxyType())->title() }}" instantSave />
+
Default request handler
+
+ + @if ($redirect_enabled) + + @endif +
@if ($server->proxyType() === ProxyTypes::TRAEFIK->value)

Traefik

@elseif ($server->proxyType() === 'CADDY') @@ -40,8 +47,6 @@ configurations. @endif -
diff --git a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php index a8192cdb1..dd1fa59f0 100644 --- a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php +++ b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php @@ -29,7 +29,7 @@ @if (str_replace('|', '.', $fileName) === 'coolify.yaml' || str_replace('|', '.', $fileName) === 'Caddyfile' || str_replace('|', '.', $fileName) === 'coolify.caddy' || - str_replace('|', '.', $fileName) === 'default_redirect_404.caddy') + str_replace('|', '.', $fileName) === 'default_redirect_503.caddy')

File: {{ str_replace('|', '.', $fileName) }}

From 2f3503d8b8509ddc9904a2fc3ffc12c3cd98e7b4 Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 11 Oct 2024 03:24:46 +1100 Subject: [PATCH 0040/1011] fix: don't allow editing traefik config --- .../views/livewire/server/proxy/dynamic-configurations.blade.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php index dd1fa59f0..5499ea95b 100644 --- a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php +++ b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php @@ -29,6 +29,7 @@ @if (str_replace('|', '.', $fileName) === 'coolify.yaml' || str_replace('|', '.', $fileName) === 'Caddyfile' || str_replace('|', '.', $fileName) === 'coolify.caddy' || + str_replace('|', '.', $fileName) === 'default_redirect_503.yaml' || str_replace('|', '.', $fileName) === 'default_redirect_503.caddy')

File: {{ str_replace('|', '.', $fileName) }}

From 5e11f159e0a78a72d3706aeebb6d6e3337223ff2 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Thu, 10 Oct 2024 18:32:24 +0200 Subject: [PATCH 0041/1011] Remove some useless variable assignments. --- app/Livewire/Boarding/Index.php | 2 -- app/Livewire/Server/Form.php | 7 ------- app/Models/Application.php | 4 ++-- bootstrap/helpers/docker.php | 12 ++++++------ 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php index 52d4674ee..b7dd8656d 100644 --- a/app/Livewire/Boarding/Index.php +++ b/app/Livewire/Boarding/Index.php @@ -73,8 +73,6 @@ class Index extends Component } $this->privateKeyName = generate_random_name(); $this->remoteServerName = generate_random_name(); - $this->remoteServerPort = $this->remoteServerPort; - $this->remoteServerUser = $this->remoteServerUser; if (isDev()) { $this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index c4f25c79d..30c96eaee 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -95,8 +95,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; } @@ -236,11 +234,6 @@ 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; - } $currentTimezone = $this->server->settings->getOriginal('server_timezone'); $newTimezone = $this->server->settings->server_timezone; if ($currentTimezone !== $newTimezone || $currentTimezone === '') { diff --git a/app/Models/Application.php b/app/Models/Application.php index 07aeb4c5b..b20f65201 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -1459,9 +1459,9 @@ class Application extends BaseModel return $config; } - public function setConfig($config) { - $config = $config; + public function setConfig($config) + { $validator = Validator::make(['config' => $config], [ 'config' => 'required|json', ]); diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 397bce029..5b45f666f 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -279,7 +279,6 @@ function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains, $labels->push("caddy_ingress_network={$network}"); } foreach ($domains as $loop => $domain) { - $loop = $loop; $url = Url::fromString($domain); $host = $url->getHost(); $path = $url->getPath(); @@ -335,10 +334,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 +388,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 +402,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 +417,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 3b13446e6536625d85086824c4ce16dfe118d2d9 Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Thu, 10 Oct 2024 19:18:35 +0100 Subject: [PATCH 0042/1011] 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 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

p!*Z_;7&1;8)3J~i4?v1 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 /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 0043/1011] 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 0044/1011] 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 0045/1011] 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 0046/1011] 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 0047/1011] 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 0048/1011] 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 0049/1011] 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 0050/1011] 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 0051/1011] 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 0052/1011] 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 0053/1011] 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 0054/1011] 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 0055/1011] 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 0056/1011] 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 0057/1011] 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 0058/1011] 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 0059/1011] 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 0060/1011] 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 0061/1011] 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 0062/1011] 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 0063/1011] 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 0064/1011] 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 0065/1011] 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 0066/1011] 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 0067/1011] 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 0068/1011] 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 0069/1011] 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 0070/1011] 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 0071/1011] 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 0072/1011] 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 0073/1011] 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 0074/1011] 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 0075/1011] 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 0076/1011] 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 0077/1011] 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 0078/1011] 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 0079/1011] 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 0080/1011] 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 0081/1011] 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 0082/1011] 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 0083/1011] 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 0084/1011] 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 0085/1011] 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 e971094508c865faffc19dd543173d621e56797c Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:32:24 +0200 Subject: [PATCH 0086/1011] new much larger default docker address pool --- other/nightly/install.sh | 10 ++++++++-- scripts/install.sh | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/other/nightly/install.sh b/other/nightly/install.sh index 04faf50ea..c4bcb761b 100755 --- a/other/nightly/install.sh +++ b/other/nightly/install.sh @@ -287,7 +287,10 @@ test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json /etc/docker/daemon "log-opts": { "max-size": "10m", "max-file": "3" - } + }, + "default-address-pools": [ + {"base":"10.0.0.0/8","size":24} + ] } EOL cat >/etc/docker/daemon.json.coolify </etc/docker/daemon.json.coolify </etc/docker/daemon.json.coolify </etc/docker/daemon.json.coolify < Date: Mon, 14 Oct 2024 21:05:33 +0200 Subject: [PATCH 0087/1011] 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 21:35:20 +0200 Subject: [PATCH 0088/1011] fix: make sure caddy is not removed by cleanup --- bootstrap/helpers/proxy.php | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 309ccee4a..33d19d9cc 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -244,6 +244,7 @@ function generate_default_proxy_configuration(Server $server) ], 'labels' => [ 'coolify.managed=true', + 'coolify.proxy=true', ], 'volumes' => [ '/var/run/docker.sock:/var/run/docker.sock:ro', From 8635f92ed48652feb6ee539121ac09614b6be5ba Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:35:38 +0200 Subject: [PATCH 0089/1011] Remove duplicated proxy check --- app/Actions/Docker/GetContainersStatus.php | 26 ----------- app/Jobs/ServerCheckJob.php | 52 +++++++++++----------- 2 files changed, 26 insertions(+), 52 deletions(-) diff --git a/app/Actions/Docker/GetContainersStatus.php b/app/Actions/Docker/GetContainersStatus.php index ed563eaae..d1603d7b4 100644 --- a/app/Actions/Docker/GetContainersStatus.php +++ b/app/Actions/Docker/GetContainersStatus.php @@ -651,31 +651,5 @@ class GetContainersStatus // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url)); } - if (! $this->server->proxySet() || $this->server->proxy->force_stop) { - return; - } - $foundProxyContainer = $this->containers->filter(function ($value, $key) { - if ($this->server->isSwarm()) { - return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik'; - } else { - return data_get($value, 'Name') === '/coolify-proxy'; - } - })->first(); - if (! $foundProxyContainer) { - try { - $shouldStart = CheckProxy::run($this->server); - if ($shouldStart) { - StartProxy::run($this->server, false); - $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server)); - } - } catch (\Throwable $e) { - ray($e); - } - } else { - $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); - $this->server->save(); - $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); - instant_remote_process($connectProxyToDockerNetworks, $this->server, false); - } } } diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php index 39d4aa0c0..3ff695cc1 100644 --- a/app/Jobs/ServerCheckJob.php +++ b/app/Jobs/ServerCheckJob.php @@ -72,6 +72,32 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue if ($this->server->isLogDrainEnabled()) { $this->checkLogDrainContainer(); } + if ($this->server->proxySet() && ! $this->server->proxy->force_stop) { + $this->server->proxyType(); + $foundProxyContainer = $this->containers->filter(function ($value, $key) { + if ($this->server->isSwarm()) { + return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik'; + } else { + return data_get($value, 'Name') === '/coolify-proxy'; + } + })->first(); + if (! $foundProxyContainer) { + try { + $shouldStart = CheckProxy::run($this->server); + if ($shouldStart) { + StartProxy::run($this->server, false); + $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server)); + } + } catch (\Throwable $e) { + ray($e); + } + } else { + $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); + $this->server->save(); + $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); + instant_remote_process($connectProxyToDockerNetworks, $this->server, false); + } + } } } catch (\Throwable $e) { @@ -387,31 +413,5 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue } // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url)); } - - // Check if proxy is running - $this->server->proxyType(); - $foundProxyContainer = $this->containers->filter(function ($value, $key) { - if ($this->server->isSwarm()) { - return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik'; - } else { - return data_get($value, 'Name') === '/coolify-proxy'; - } - })->first(); - if (! $foundProxyContainer) { - try { - $shouldStart = CheckProxy::run($this->server); - if ($shouldStart) { - StartProxy::run($this->server, false); - $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server)); - } - } catch (\Throwable $e) { - ray($e); - } - } else { - $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); - $this->server->save(); - $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); - instant_remote_process($connectProxyToDockerNetworks, $this->server, false); - } } } From 740419806eb44bd3c92d688fe7088e8350797544 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Oct 2024 22:35:18 +0200 Subject: [PATCH 0090/1011] 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 0091/1011] 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 0092/1011] 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 0093/1011] 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 0094/1011] 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 0095/1011] 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 0096/1011] 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 0097/1011] 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 0098/1011] 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 902cde59057ead5d7dda36f0096d041a8cc2019f Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:19:04 +0200 Subject: [PATCH 0099/1011] improve custom redis.conf --- app/Actions/Database/StartRedis.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index eeddab924..186ad0432 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -37,6 +37,8 @@ class StartRedis $environment_variables = $this->generate_environment_variables(); $this->add_custom_redis(); + $startCommand = $this->buildStartCommand(); + $docker_compose = [ 'services' => [ $container_name => [ @@ -105,7 +107,6 @@ class StartRedis 'target' => '/usr/local/etc/redis/redis.conf', 'read_only' => true, ]; - $docker_compose['services'][$container_name]['command'] = "redis-server /usr/local/etc/redis/redis.conf --requirepass {$this->database->redis_password} --appendonly yes"; } // Add custom docker run options @@ -173,6 +174,27 @@ class StartRedis return $environment_variables->all(); } + private function buildStartCommand(): string + { + $hasRedisConf = ! is_null($this->database->redis_conf) && ! empty($this->database->redis_conf); + $redisConfPath = '/usr/local/etc/redis/redis.conf'; + + if ($hasRedisConf) { + $confContent = $this->database->redis_conf; + $hasRequirePass = str_contains($confContent, 'requirepass'); + + if ($hasRequirePass) { + $command = "redis-server $redisConfPath"; + } else { + $command = "redis-server $redisConfPath --requirepass {$this->database->redis_password}"; + } + } else { + $command = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; + } + + return $command; + } + private function add_custom_redis() { if (is_null($this->database->redis_conf) || empty($this->database->redis_conf)) { From c6e2c7e5e3f9531699d48f19986c476d2b198998 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:35:20 +0200 Subject: [PATCH 0100/1011] fix start command --- app/Actions/Database/StartRedis.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 186ad0432..3e3c5b3b9 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -21,8 +21,6 @@ class StartRedis { $this->database = $database; - $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; - $container_name = $this->database->uuid; $this->configuration_dir = database_configuration_dir().'/'.$container_name; From 79caa3c26bcf0224cdfb3de30170d3fde884c66f Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:02:37 +0200 Subject: [PATCH 0101/1011] fix: allow setting standalone redis variables via ENVs (team variables...) --- app/Actions/Database/StartRedis.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 3e3c5b3b9..45a031e70 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -159,12 +159,29 @@ class StartRedis private function generate_environment_variables() { $environment_variables = collect(); + $redis_password = null; + $redis_username = null; + foreach ($this->database->runtime_environment_variables as $env) { $environment_variables->push("$env->key=$env->real_value"); + + if ($env->key === 'REDIS_PASSWORD') { + $redis_password = $env->real_value; + } elseif ($env->key === 'REDIS_USERNAME') { + $redis_username = $env->real_value; + } } - if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) { + if (is_null($redis_password)) { $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); + } else { + $this->database->update(['redis_password' => $redis_password]); + } + + if (is_null($redis_username)) { + $environment_variables->push("REDIS_USERNAME={$this->database->redis_username}"); + } else { + $this->database->update(['redis_username' => $redis_username]); } add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables); From 2702fbc284f8aaa265603cd5a17ce35903be3257 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Oct 2024 17:03:50 +0200 Subject: [PATCH 0102/1011] 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 5274ae1f0b578ab4b27bc4646c1ac2cb86805c93 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:23:33 +0200 Subject: [PATCH 0103/1011] fix: check for username separately form password --- app/Actions/Database/StartRedis.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 45a031e70..56be36202 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -167,7 +167,9 @@ class StartRedis if ($env->key === 'REDIS_PASSWORD') { $redis_password = $env->real_value; - } elseif ($env->key === 'REDIS_USERNAME') { + } + + if ($env->key === 'REDIS_USERNAME') { $redis_username = $env->real_value; } } From edad4fcd5c0b8bdc89e4e590b8336956967df635 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:38:11 +0200 Subject: [PATCH 0104/1011] update helper text --- .../livewire/project/database/redis/general.blade.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index c76229d28..c5ab13d94 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -16,9 +16,11 @@ $redis_version = explode(':', $database->image)[1] ?? '0.0'; @endphp @if (version_compare($redis_version, '6.0', '>=')) - + @endif - +
-
\ No newline at end of file +
From b9c9c1041a911824f5630b8cad87476205587558 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:20:26 +0200 Subject: [PATCH 0105/1011] feat: add is shared to env variables --- app/Models/EnvironmentVariable.php | 10 +++++++++ ...add_is_shared_to_environment_variables.php | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php diff --git a/app/Models/EnvironmentVariable.php b/app/Models/EnvironmentVariable.php index 531c8fa40..f77d73db8 100644 --- a/app/Models/EnvironmentVariable.php +++ b/app/Models/EnvironmentVariable.php @@ -74,6 +74,9 @@ class EnvironmentVariable extends Model 'version' => config('version'), ]); }); + static::saving(function (EnvironmentVariable $environmentVariable) { + $environmentVariable->updateIsShared(); + }); } public function service() @@ -217,4 +220,11 @@ class EnvironmentVariable extends Model set: fn (string $value) => str($value)->trim()->replace(' ', '_')->value, ); } + + protected function updateIsShared(): void + { + $type = str($this->value)->after('{{')->before('.')->value; + $isShared = str($this->value)->startsWith('{{'.$type) && str($this->value)->endsWith('}}'); + $this->is_shared = $isShared; + } } diff --git a/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php b/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php new file mode 100644 index 000000000..eb878e2f6 --- /dev/null +++ b/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php @@ -0,0 +1,22 @@ +boolean('is_shared')->default(false); + }); + } + + public function down() + { + Schema::table('environment_variables', function (Blueprint $table) { + $table->dropColumn('is_shared'); + }); + } +} From 6f97d589aee48b673ca6d362526cbe923c62e8e7 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:29:13 +0200 Subject: [PATCH 0106/1011] feat: variabel sync and support shared vars --- app/Actions/Database/StartRedis.php | 37 ++++++++----------- .../Project/Database/Redis/General.php | 30 ++++++++++++--- bootstrap/helpers/databases.php | 16 ++++++++ 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 56be36202..3705ce938 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -159,31 +159,26 @@ class StartRedis private function generate_environment_variables() { $environment_variables = collect(); - $redis_password = null; - $redis_username = null; foreach ($this->database->runtime_environment_variables as $env) { - $environment_variables->push("$env->key=$env->real_value"); + if ($env->is_shared) { + $environment_variables->push("$env->key=$env->real_value"); - if ($env->key === 'REDIS_PASSWORD') { - $redis_password = $env->real_value; + if ($env->key === 'REDIS_PASSWORD') { + $this->database->update(['redis_password' => $env->real_value]); + } + + if ($env->key === 'REDIS_USERNAME') { + $this->database->update(['redis_username' => $env->real_value]); + } + } else { + if ($env->key === 'REDIS_PASSWORD') { + $env->update(['value' => $this->database->redis_password]); + } elseif ($env->key === 'REDIS_USERNAME') { + $env->update(['value' => $this->database->redis_username]); + } + $environment_variables->push("$env->key=$env->real_value"); } - - if ($env->key === 'REDIS_USERNAME') { - $redis_username = $env->real_value; - } - } - - if (is_null($redis_password)) { - $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); - } else { - $this->database->update(['redis_password' => $redis_password]); - } - - if (is_null($redis_username)) { - $environment_variables->push("REDIS_USERNAME={$this->database->redis_username}"); - } else { - $this->database->update(['redis_username' => $redis_username]); } add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables); diff --git a/app/Livewire/Project/Database/Redis/General.php b/app/Livewire/Project/Database/Redis/General.php index b5b459acb..ab9b0756d 100644 --- a/app/Livewire/Project/Database/Redis/General.php +++ b/app/Livewire/Project/Database/Redis/General.php @@ -80,14 +80,12 @@ class General extends Component $redis_version = $this->get_redis_version(); - if (version_compare($redis_version, '6.0', '>=')) { - if ($this->database->isDirty('redis_username')) { - $this->database->redis_username = $this->database->redis_username; - } + if (version_compare($redis_version, '6.0', '>=') && $this->database->isDirty('redis_username')) { + $this->updateEnvironmentVariable('REDIS_USERNAME', $this->database->redis_username); } if ($this->database->isDirty('redis_password')) { - $this->database->redis_password = $this->database->redis_password; + $this->updateEnvironmentVariable('REDIS_PASSWORD', $this->database->redis_password); } $this->database->save(); @@ -101,6 +99,7 @@ class General extends Component private function get_redis_version() { $image_parts = explode(':', $this->database->image); + return $image_parts[1] ?? '0.0'; } @@ -144,4 +143,23 @@ class General extends Component { return view('livewire.project.database.redis.general'); } -} \ No newline at end of file + + private function updateEnvironmentVariable($key, $value) + { + $envVar = $this->database->runtime_environment_variables() + ->where('key', $key) + ->first(); + + if ($envVar) { + if (! $envVar->is_shared) { + $envVar->update(['value' => $value]); + } + } else { + $this->database->runtime_environment_variables()->create([ + 'key' => $key, + 'value' => $value, + 'is_shared' => false, + ]); + } + } +} diff --git a/bootstrap/helpers/databases.php b/bootstrap/helpers/databases.php index 950eb67b6..d77327c8f 100644 --- a/bootstrap/helpers/databases.php +++ b/bootstrap/helpers/databases.php @@ -1,5 +1,6 @@ name = generate_database_name('redis'); $database->redis_password = \Illuminate\Support\Str::password(length: 64, symbols: false); + $database->redis_username = 'default'; $database->environment_id = $environment_id; $database->destination_id = $destination->id; $database->destination_type = $destination->getMorphClass(); @@ -57,6 +59,20 @@ function create_standalone_redis($environment_id, $destination_uuid, ?array $oth } $database->save(); + EnvironmentVariable::create([ + 'key' => 'REDIS_PASSWORD', + 'value' => $database->redis_password, + 'standalone_redis_id' => $database->id, + 'is_shared' => false, + ]); + + EnvironmentVariable::create([ + 'key' => 'REDIS_USERNAME', + 'value' => $database->redis_username, + 'standalone_redis_id' => $database->id, + 'is_shared' => false, + ]); + return $database; } From 85c3270dcc4270a6c9616bb68401105493370b45 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:44:17 +0200 Subject: [PATCH 0107/1011] update helper and disable input if variable is shared --- .../Project/Database/Redis/General.php | 9 +++++++++ app/Models/StandaloneRedis.php | 12 ++++++++---- .../project/database/redis/general.blade.php | 19 +++++++++++++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/app/Livewire/Project/Database/Redis/General.php b/app/Livewire/Project/Database/Redis/General.php index ab9b0756d..20a881523 100644 --- a/app/Livewire/Project/Database/Redis/General.php +++ b/app/Livewire/Project/Database/Redis/General.php @@ -4,6 +4,7 @@ namespace App\Livewire\Project\Database\Redis; use App\Actions\Database\StartDatabaseProxy; use App\Actions\Database\StopDatabaseProxy; +use App\Models\EnvironmentVariable; use App\Models\Server; use App\Models\StandaloneRedis; use Exception; @@ -144,6 +145,14 @@ class General extends Component return view('livewire.project.database.redis.general'); } + public function isSharedVariable($name) + { + return EnvironmentVariable::where('key', $name) + ->where('standalone_redis_id', $this->database->id) + ->where('is_shared', true) + ->exists(); + } + private function updateEnvironmentVariable($key, $value) { $envVar = $this->database->runtime_environment_variables() diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index e71eacc45..188982f47 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -21,7 +21,7 @@ class StandaloneRedis extends BaseModel ]; protected $attributes = [ - 'redis_username' => 'redis', + 'redis_username' => 'default', ]; protected static function booted() @@ -220,7 +220,8 @@ class StandaloneRedis extends BaseModel return new Attribute( get: function () { $redis_version = $this->get_redis_version(); - $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ""; + $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ''; + return "redis://{$username_part}{$this->redis_password}@{$this->uuid}:6379/0"; } ); @@ -232,9 +233,11 @@ class StandaloneRedis extends BaseModel get: function () { if ($this->is_public && $this->public_port) { $redis_version = $this->get_redis_version(); - $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ""; + $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : ''; + return "redis://{$username_part}{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0"; } + return null; } ); @@ -243,6 +246,7 @@ class StandaloneRedis extends BaseModel private function get_redis_version() { $image_parts = explode(':', $this->image); + return $image_parts[1] ?? '0.0'; } @@ -309,9 +313,9 @@ class StandaloneRedis extends BaseModel return $parsedCollection->toArray(); } } + public function isBackupSolutionAvailable() { return false; } } - diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index c5ab13d94..e61c210b0 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -16,11 +16,22 @@ $redis_version = explode(':', $database->image)[1] ?? '0.0'; @endphp @if (version_compare($redis_version, '6.0', '>=')) - + @endif - + Date: Wed, 16 Oct 2024 14:04:21 +0200 Subject: [PATCH 0108/1011] fix: encrypt all existing redis passwords --- ...20026_encrypt_existing_redis_passwords.php | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 database/migrations/2024_10_16_120026_encrypt_existing_redis_passwords.php diff --git a/database/migrations/2024_10_16_120026_encrypt_existing_redis_passwords.php b/database/migrations/2024_10_16_120026_encrypt_existing_redis_passwords.php new file mode 100644 index 000000000..3b4f11986 --- /dev/null +++ b/database/migrations/2024_10_16_120026_encrypt_existing_redis_passwords.php @@ -0,0 +1,27 @@ +chunkById(100, function ($redisInstances) { + foreach ($redisInstances as $redis) { + DB::table('standalone_redis') + ->where('id', $redis->id) + ->update(['redis_password' => Crypt::encryptString($redis->redis_password)]); + } + }); + } catch (\Exception $e) { + echo 'Encrypting Redis passwords failed.'; + echo $e->getMessage(); + } + } +} From 08da5aaf04ffef8b567106a437400157fd884009 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:59:42 +0200 Subject: [PATCH 0109/1011] fix and improve OTP --- .../views/livewire/profile/index.blade.php | 70 ++++++++++++++++--- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/resources/views/livewire/profile/index.blade.php b/resources/views/livewire/profile/index.blade.php index 0648016b7..94bc73089 100644 --- a/resources/views/livewire/profile/index.blade.php +++ b/resources/views/livewire/profile/index.blade.php @@ -33,20 +33,70 @@ Please finish configuring two factor authentication below. Read the QR code or enter the secret key manually. -
+
@csrf - + Validate 2FA -
-
{!! request()->user()->twoFactorQrCodeSvg() !!}
-
- - Show secret key to manually - enter +
+
+ {!! request()->user()->twoFactorQrCodeSvg() !!} +
+
+
+
+ + +
+
+ + +
+
+ + Secret Key and OTP URL +
From 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 0110/1011] 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 0111/1011] 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 0112/1011] 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 0113/1011] 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 0114/1011] 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 0115/1011] 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 0116/1011] 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 0117/1011] 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 0118/1011] 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 2cb424ed7b29f11d9ebefcd78dd491c86e639f40 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:07:35 +0200 Subject: [PATCH 0119/1011] setting to disable tow step confirmation --- app/Livewire/Settings/Index.php | 9 +- ...on_settings_to_instance_settings_table.php | 22 +++ .../views/livewire/settings/index.blade.php | 175 +++++++++--------- 3 files changed, 114 insertions(+), 92 deletions(-) create mode 100644 database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php index 754f0929b..7d3fe62a7 100644 --- a/app/Livewire/Settings/Index.php +++ b/app/Livewire/Settings/Index.php @@ -25,6 +25,10 @@ class Index extends Component public string $update_check_frequency; + public $timezones; + + public bool $disable_two_step_confirmation; + protected string $dynamic_config_path = '/data/coolify/proxy/dynamic'; protected Server $server; @@ -55,8 +59,6 @@ class Index extends Component 'update_check_frequency' => 'Update Check Frequency', ]; - public $timezones; - public function mount() { if (isInstanceAdmin()) { @@ -69,6 +71,7 @@ class Index extends Component $this->auto_update_frequency = $this->settings->auto_update_frequency; $this->update_check_frequency = $this->settings->update_check_frequency; $this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray(); + $this->disable_two_step_confirmation = $this->settings->disable_two_step_confirmation; } else { return redirect()->route('dashboard'); } @@ -83,6 +86,7 @@ class Index extends Component $this->settings->is_api_enabled = $this->is_api_enabled; $this->settings->auto_update_frequency = $this->auto_update_frequency; $this->settings->update_check_frequency = $this->update_check_frequency; + $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation; $this->settings->save(); $this->dispatch('success', 'Settings updated!'); } @@ -148,6 +152,7 @@ class Index extends Component $this->settings->is_api_enabled = $this->is_api_enabled; $this->settings->auto_update_frequency = $this->auto_update_frequency; $this->settings->update_check_frequency = $this->update_check_frequency; + $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation; $this->settings->save(); $this->server->setupDynamicProxyConfiguration(); if (! $error_show) { diff --git a/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php b/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php new file mode 100644 index 000000000..7040daf44 --- /dev/null +++ b/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php @@ -0,0 +1,22 @@ +boolean('disable_two_step_confirmation')->default(false); + }); + } + + public function down() + { + Schema::table('instance_settings', function (Blueprint $table) { + $table->dropColumn('disable_two_step_confirmation'); + }); + } +}; diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php index f9293e7d7..db2a06995 100644 --- a/resources/views/livewire/settings/index.blade.php +++ b/resources/views/livewire/settings/index.blade.php @@ -1,26 +1,24 @@
Settings | Coolify - - -
-
-

Configuration

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

Configuration

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

Instance Settings

-
-
- - -
+

Instance Settings

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

DNS Validation

+
+ +
+
-

DNS Validation

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

API

-
- -
- +
+

API

+
+ +
+ -

Advanced

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

Advanced

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

Warning!

+

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

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

Confirm Actions

-

{{ $confirmationLabel }}

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

Confirm Actions

+

{{ $confirmationLabel }}

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

Warning!

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

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

Warning!

-

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

+

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

@if($disable_two_step_confirmation) @@ -119,10 +119,10 @@ buttonTitle="Disable Two Step Confirmation" isErrorButton submitAction="toggleTwoStepConfirmation" - :actions="['Tow Step confimation will be disabled globally.', 'Disabling two-step confirmation reduces security (as anyone can easily delete anything).', 'The risk of accidental actions will increase.']" + :actions="['Tow Step confimation will be disabled globally.', 'Disabling two step confirmation reduces security (as anyone can easily delete anything).', 'The risk of accidental actions will increase.']" confirmationText="DISABLE TWO STEP CONFIRMATION" confirmationLabel="Please type the confirmation text to disable two step confirmation." - shortConfirmationLabel="Type Confirmation Text" + shortConfirmationLabel="Confirmation text" step3ButtonText="Disable Two Step Confirmation" /> @endif From 8b114f555874130ecd0e7b1850e7bce7574ed7d3 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:05:58 +0200 Subject: [PATCH 0124/1011] fix button text kind of --- resources/views/components/modal-confirmation.blade.php | 2 +- resources/views/livewire/server/delete.blade.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/components/modal-confirmation.blade.php b/resources/views/components/modal-confirmation.blade.php index a0175c1a1..4dc4e83e7 100644 --- a/resources/views/components/modal-confirmation.blade.php +++ b/resources/views/components/modal-confirmation.blade.php @@ -331,7 +331,7 @@ } " > - + diff --git a/resources/views/livewire/server/delete.blade.php b/resources/views/livewire/server/delete.blade.php index 360e1e0c6..86053c0d4 100644 --- a/resources/views/livewire/server/delete.blade.php +++ b/resources/views/livewire/server/delete.blade.php @@ -16,7 +16,7 @@ + shortConfirmationLabel="Server Name" step3ButtonText="Permanently Delete" /> @endif @endif
From c087f22056ba5fa21c3d1b9e179f8024db4462aa Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:49:45 +0200 Subject: [PATCH 0125/1011] 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 0126/1011] 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 0127/1011] 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 0128/1011] 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 0129/1011] 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 0130/1011] 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 0131/1011] 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 0132/1011] 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 0133/1011] 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 0134/1011] 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 0135/1011] 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 0136/1011] 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 0137/1011] 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 0138/1011] 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 0139/1011] 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 0140/1011] 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 0141/1011] 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 0142/1011] 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 0143/1011] 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 0144/1011] 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 0145/1011] 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 0146/1011] 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 1d2e9b69461bafb9a79264981265cabafd2954c9 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:29:33 +0200 Subject: [PATCH 0147/1011] fix is required on shared variables --- app/Livewire/Project/Shared/EnvironmentVariable/Show.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php index 0538a6bdb..53c4374df 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php @@ -112,14 +112,20 @@ class Show extends Component $this->validate(); } - if ($this->env->is_required && str($this->env->real_value)->isEmpty()) { + if (! $this->isSharedVariable && $this->env->is_required && str($this->env->real_value)->isEmpty()) { $oldValue = $this->env->getOriginal('value'); $this->env->value = $oldValue; $this->dispatch('error', 'Required environment variable cannot be empty.'); return; } + $this->serialize(); + + if ($this->isSharedVariable) { + unset($this->env->is_required); + } + $this->env->save(); $this->dispatch('success', 'Environment variable updated.'); $this->dispatch('envsUpdated'); From 5a38b21d95edcf70a7a7e80aa95a01ed17826e97 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:48:41 +0200 Subject: [PATCH 0148/1011] fix project deletion and refactor some code --- app/Http/Controllers/Api/ProjectController.php | 2 +- app/Livewire/Project/DeleteProject.php | 11 ++++++----- app/Models/Project.php | 13 +++++++++++-- resources/views/livewire/project/edit.blade.php | 2 +- resources/views/livewire/project/show.blade.php | 2 +- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index f1958de2c..066d74e76 100644 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -423,7 +423,7 @@ class ProjectController extends Controller if (! $project) { return response()->json(['message' => 'Project not found.'], 404); } - if ($project->resource_count() > 0) { + if (! $project->isEmpty()) { return response()->json(['message' => 'Project has resources, so it cannot be deleted.'], 400); } diff --git a/app/Livewire/Project/DeleteProject.php b/app/Livewire/Project/DeleteProject.php index 360fad10a..f320a19b0 100644 --- a/app/Livewire/Project/DeleteProject.php +++ b/app/Livewire/Project/DeleteProject.php @@ -27,11 +27,12 @@ class DeleteProject extends Component 'project_id' => 'required|int', ]); $project = Project::findOrFail($this->project_id); - if ($project->applications->count() > 0) { - return $this->dispatch('error', 'Project has resources defined, please delete them first.'); - } - $project->delete(); + if ($project->isEmpty()) { + $project->delete(); - return redirect()->route('project.index'); + return redirect()->route('project.index'); + } + + return $this->dispatch('error', "Project {$project->name} has resources defined, please delete them first."); } } diff --git a/app/Models/Project.php b/app/Models/Project.php index 5a9dd964a..16ce403eb 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -123,9 +123,18 @@ class Project extends BaseModel return $this->hasManyThrough(StandaloneMariadb::class, Environment::class); } - public function resource_count() + public function isEmpty() { - return $this->applications()->count() + $this->postgresqls()->count() + $this->redis()->count() + $this->mongodbs()->count() + $this->mysqls()->count() + $this->mariadbs()->count() + $this->keydbs()->count() + $this->dragonflies()->count() + $this->clickhouses()->count() + $this->services()->count(); + return $this->applications()->count() == 0 && + $this->redis()->count() == 0 && + $this->postgresqls()->count() == 0 && + $this->mysqls()->count() == 0 && + $this->keydbs()->count() == 0 && + $this->dragonflies()->count() == 0 && + $this->clickhouses()->count() == 0 && + $this->mariadbs()->count() == 0 && + $this->mongodbs()->count() == 0 && + $this->services()->count() == 0; } public function databases() diff --git a/resources/views/livewire/project/edit.blade.php b/resources/views/livewire/project/edit.blade.php index ec9304da9..de837eb65 100644 --- a/resources/views/livewire/project/edit.blade.php +++ b/resources/views/livewire/project/edit.blade.php @@ -7,7 +7,7 @@

Project: {{ data_get($project, 'name') }}

Save - +
Edit project details here.
diff --git a/resources/views/livewire/project/show.blade.php b/resources/views/livewire/project/show.blade.php index f4f5299f9..014a34faf 100644 --- a/resources/views/livewire/project/show.blade.php +++ b/resources/views/livewire/project/show.blade.php @@ -7,7 +7,7 @@ - +
{{ $project->name }}.
From e52139f4368b0e15ec275733094b4d4fb39e94a2 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:49:17 +0200 Subject: [PATCH 0149/1011] chore better error message when deleting an environment --- app/Livewire/Project/DeleteEnvironment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Livewire/Project/DeleteEnvironment.php b/app/Livewire/Project/DeleteEnvironment.php index e01741770..9c1c358b8 100644 --- a/app/Livewire/Project/DeleteEnvironment.php +++ b/app/Livewire/Project/DeleteEnvironment.php @@ -33,6 +33,6 @@ class DeleteEnvironment extends Component return redirect()->route('project.show', ['project_uuid' => $this->parameters['project_uuid']]); } - return $this->dispatch('error', 'Environment has defined resources, please delete them first.'); + return $this->dispatch('error', "Environment {$environment->name} has defined resources, please delete them first."); } } From ba91ca4e84e487d8372b8fb43dffb6e57f094d13 Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Fri, 18 Oct 2024 14:50:11 +0100 Subject: [PATCH 0150/1011] 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 0151/1011] 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 0152/1011] 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 0153/1011] Update service-templates.json --- templates/service-templates.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/templates/service-templates.json b/templates/service-templates.json index be67f694a..644864ade 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -1612,6 +1612,19 @@ "minversion": "0.0.0", "port": "8080" }, + "mosquitto": { + "documentation": "https://mosquitto.org/documentation/?utm_source=coolify.io", + "slogan": "Mosquitto is lightweight and suitable for use on all devices, from low-power single-board computers to full servers.", + "compose": "c2VydmljZXM6CiAgbW9zcXVpdHRvOgogICAgaW1hZ2U6IGVjbGlwc2UtbW9zcXVpdHRvCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fTU9TUVVJVFRPXzE4ODMKICAgICAgLSAnTVFUVF9VU0VSTkFNRT0ke1NFUlZJQ0VfVVNFUl9NT1NRVUlUVE99JwogICAgICAtICdNUVRUX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NT1NRVUlUVE99JwogICAgICAtICdSRVFVSVJFX0NFUlRJRklDQVRFPSR7UkVRVUlSRV9DRVJUSUZJQ0FURTotZmFsc2V9JwogICAgICAtICdBTExPV19BTk9OWU1PVVM9JHtBTExPV19BTk9OWU1PVVM6LXRydWV9JwogICAgdm9sdW1lczoKICAgICAgLSAnbW9zcXVpdHRvLWNvbmZpZzovbW9zcXVpdHRvL2NvbmZpZycKICAgICAgLSAnbW9zcXVpdHRvLWNlcnRzOi9jZXJ0cycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnZXhpdCAwJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgICBlbnRyeXBvaW50OiAic2ggLWMgXCIgaWYgWyAnJFJFUVVJUkVfQ0VSVElGSUNBVEUnID0gJ3RydWUnIF07IHRoZW4gZWNobyAnbGlzdGVuZXIgODg4MycgPiAvbW9zcXVpdHRvL2NvbmZpZy9tb3NxdWl0dG8uY29uZiAmJiBlY2hvICdjYWZpbGUgL2NlcnRzL2NhLmNydCcgPj4gL21vc3F1aXR0by9jb25maWcvbW9zcXVpdHRvLmNvbmYgJiYgZWNobyAnY2VydGZpbGUgL2NlcnRzL3NlcnZlci5jcnQnID4+IC9tb3NxdWl0dG8vY29uZmlnL21vc3F1aXR0by5jb25mICYmIGVjaG8gJ2tleWZpbGUgIC9jZXJ0cy9zZXJ2ZXIua2V5JyA+PiAvbW9zcXVpdHRvL2NvbmZpZy9tb3NxdWl0dG8uY29uZjsgZWxzZSBlY2hvICdsaXN0ZW5lciAxODgzJyA+IC9tb3NxdWl0dG8vY29uZmlnL21vc3F1aXR0by5jb25mOyBmaSAmJiBlY2hvICdyZXF1aXJlX2NlcnRpZmljYXRlICckUkVRVUlSRV9DRVJUSUZJQ0FURSA+PiAvbW9zcXVpdHRvL2NvbmZpZy9tb3NxdWl0dG8uY29uZiAmJiBlY2hvICdhbGxvd19hbm9ueW1vdXMgJyRBTExPV19BTk9OWU1PVVMgPj4gL21vc3F1aXR0by9jb25maWcvbW9zcXVpdHRvLmNvbmYgJiYgaWYgWyAtbiAnJFNFUlZJQ0VfVVNFUl9NT1NRVUlUVE8nXSAmJiBbIC1uICckU0VSVklDRV9QQVNTV09SRF9NT1NRVUlUVE8nIF07IHRoZW4gZWNobyAncGFzc3dvcmRfZmlsZSAvbW9zcXVpdHRvL2NvbmZpZy9wYXNzd29yZHMnID4+IC9tb3NxdWl0dG8vY29uZmlnL21vc3F1aXR0by5jb25mICYmIHRvdWNoIC9tb3NxdWl0dG8vY29uZmlnL3Bhc3N3b3JkcyAmJiBjaG1vZCAwNzAwIC9tb3NxdWl0dG8vY29uZmlnL3Bhc3N3b3JkcyAmJiBjaG93biByb290OnJvb3QgL21vc3F1aXR0by9jb25maWcvcGFzc3dvcmRzICYmIG1vc3F1aXR0b19wYXNzd2QgLWIgLWMgL21vc3F1aXR0by9jb25maWcvcGFzc3dvcmRzICRTRVJWSUNFX1VTRVJfTU9TUVVJVFRPICRTRVJWSUNFX1BBU1NXT1JEX01PU1FVSVRUTyAmJiBjaG93biBtb3NxdWl0dG86bW9zcXVpdHRvIC9tb3NxdWl0dG8vY29uZmlnL3Bhc3N3b3JkczsgZmkgJiYgZXhlYyBtb3NxdWl0dG8gLWMgL21vc3F1aXR0by9jb25maWcvbW9zcXVpdHRvLmNvbmYgXCIiCiAgICBsYWJlbHM6CiAgICAgIC0gdHJhZWZpay50Y3Aucm91dGVycy5tcXR0LmVudHJ5cG9pbnRzPW1xdHQKICAgICAgLSB0cmFlZmlrLnRjcC5yb3V0ZXJzLm1xdHRzLmVudHJ5cG9pbnRzPW1xdHRzCg==", + "tags": [ + "mosquitto", + "mqtt", + "open-source" + ], + "logo": "svgs/mosquitto.svg", + "minversion": "0.0.0", + "port": "1883" + }, "n8n-with-postgresql": { "documentation": "https://n8n.io?utm_source=coolify.io", "slogan": "n8n is an extendable workflow automation tool.", From fb4e658628a5d9a114526549ef9825c6943c0822 Mon Sep 17 00:00:00 2001 From: Diogo Carvalho Date: Fri, 18 Oct 2024 21:58:15 +0100 Subject: [PATCH 0154/1011] Fix entrypoint --- templates/compose/mosquitto.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/mosquitto.yaml b/templates/compose/mosquitto.yaml index 1ec6f0cdc..475d7cf39 100644 --- a/templates/compose/mosquitto.yaml +++ b/templates/compose/mosquitto.yaml @@ -32,7 +32,7 @@ services: 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 && + echo ''allow_anonymous ''$ALLOW_ANONYMOUS >> /mosquitto/config/mosquitto.conf; if [ -n ''$SERVICE_USER_MOSQUITTO''] && [ -n ''$SERVICE_PASSWORD_MOSQUITTO'' ]; then echo ''password_file /mosquitto/config/passwords'' >> /mosquitto/config/mosquitto.conf && touch /mosquitto/config/passwords && From 5d8a3d0eec19a9d793a558f793db6f39e981dd64 Mon Sep 17 00:00:00 2001 From: Frank Hufnagel Date: Sat, 19 Oct 2024 12:57:29 +0200 Subject: [PATCH 0155/1011] update openapi spec for healthcheck --- app/Http/Controllers/Api/OtherController.php | 2 +- openapi.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/OtherController.php b/app/Http/Controllers/Api/OtherController.php index 2414b7a42..062cc04e7 100644 --- a/app/Http/Controllers/Api/OtherController.php +++ b/app/Http/Controllers/Api/OtherController.php @@ -160,7 +160,7 @@ class OtherController extends Controller #[OA\Get( summary: 'Healthcheck', description: 'Healthcheck endpoint.', - path: '/healthcheck', + path: '/health', operationId: 'healthcheck', responses: [ new OA\Response( diff --git a/openapi.yaml b/openapi.yaml index 91d5c1443..1110bfd72 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3093,7 +3093,7 @@ paths: security: - bearerAuth: [] - /healthcheck: + /health: get: summary: Healthcheck description: 'Healthcheck endpoint.' From ce4b6db041ffb976db4943cff5051d593376310e Mon Sep 17 00:00:00 2001 From: JakeKydd Date: Sun, 20 Oct 2024 01:17:26 +0200 Subject: [PATCH 0156/1011] add: wireguard-easy template --- public/svgs/wireguard.svg | 7 +++++++ templates/compose/wireguard-easy.yaml | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 public/svgs/wireguard.svg create mode 100644 templates/compose/wireguard-easy.yaml diff --git a/public/svgs/wireguard.svg b/public/svgs/wireguard.svg new file mode 100644 index 000000000..81823b3eb --- /dev/null +++ b/public/svgs/wireguard.svg @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/templates/compose/wireguard-easy.yaml b/templates/compose/wireguard-easy.yaml new file mode 100644 index 000000000..56d3c89ce --- /dev/null +++ b/templates/compose/wireguard-easy.yaml @@ -0,0 +1,27 @@ +# documentation: https://github.com/wg-easy/wg-easy +# slogan: The easiest way to run WireGuard VPN + Web-based Admin UI. +# tags: wireguard,vpn,web,admin +# logo: svgs/wireguard.svg +# port: 8000 +services: + wg-easy: + image: ghcr.io/wg-easy/wg-easy + container_name: wg-easy + environment: + - LANG=en + - WG_HOST=$SERVICE_FQDN_WIREGUARDEASY + - PASSWORD_HASH=$2y$10$2wrW.nOpZLjGSGaiocD8xOo6uLCa.CebkaqswyAz.hSd5PYKm2WVu + - PORT=8000 + - WG_PORT=51820 + volumes: + - ~/.wg-easy:/etc/wireguard + ports: + - "51820:51820/udp" + - "8000:8000/tcp" + cap_add: + - NET_ADMIN + - SYS_MODULE + sysctls: + - net.ipv4.conf.all.src_valid_mark=1 + - net.ipv4.ip_forward=1 + restart: unless-stopped From 1c1689d3288b973ce9a505edadc6e47245829454 Mon Sep 17 00:00:00 2001 From: "yokowasis@host2" Date: Sun, 20 Oct 2024 00:44:03 +0000 Subject: [PATCH 0157/1011] jupyterlab tempalte --- public/svgs/jupyterlab.svg | 90 +++++++++++++++++++++++++++++++ templates/compose/jupyterlab.yaml | 21 ++++++++ 2 files changed, 111 insertions(+) create mode 100644 public/svgs/jupyterlab.svg create mode 100644 templates/compose/jupyterlab.yaml diff --git a/public/svgs/jupyterlab.svg b/public/svgs/jupyterlab.svg new file mode 100644 index 000000000..ab2550874 --- /dev/null +++ b/public/svgs/jupyterlab.svg @@ -0,0 +1,90 @@ + +Group.svg +Created using Figma 0.90 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/compose/jupyterlab.yaml b/templates/compose/jupyterlab.yaml new file mode 100644 index 000000000..360067919 --- /dev/null +++ b/templates/compose/jupyterlab.yaml @@ -0,0 +1,21 @@ +# documentation: https://jupyterlab.readthedocs.io/en/latest/ +# slogan: JupyterLab Notebook with C++ (xeus-cling) and Javascript (Deno) Kernel +# tags: jupyter,notebook,python,cpp,deno,jupyterlab +# logo: svgs/jupyterlab.svg +# port: 8008 + +version: '3.8' + +services: + jupyterlab: + image: yokowasis/jupyterlab + expose: + - 8008 + environment: + - SERVICE_FQDN_JUPYTERLAB + - PORT=${PORT:-8008} + - TOKEN=${SERVICE_PASSWORD_TOKEN} + - CONDA_PACKAGES=${CONDA_PACKAGES:-pandas numpy matplotlib seaborn scikit-learn pytorch nltk openpyxl category_encoders scikit-learn tensorflow spacy} + - PIP_PACKAGES=${PIP_PACKAGES:-sastrawi} + volumes: + - jupyterlab_data:/home/mambauser/data From c3c1671b6cd07cdd3e222ca9d86f12695817e9fa Mon Sep 17 00:00:00 2001 From: "Alexander G." Date: Sun, 20 Oct 2024 14:24:13 +0300 Subject: [PATCH 0158/1011] Adding healthcheck to trigger --- templates/compose/trigger.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/compose/trigger.yaml b/templates/compose/trigger.yaml index e33459535..818f54eb4 100644 --- a/templates/compose/trigger.yaml +++ b/templates/compose/trigger.yaml @@ -62,9 +62,10 @@ services: electric: condition: service_healthy healthcheck: - test: - - CMD-SHELL - - pwd + test: "timeout 10s bash -c ':> /dev/tcp/127.0.0.1/3000' || exit 1" + interval: 10s + timeout: 5s + retries: 5 electric: image: electricsql/electric restart: always From d7852c334e007b270dbd19d2b047840c964c5c1d Mon Sep 17 00:00:00 2001 From: JakeKydd Date: Sun, 20 Oct 2024 14:22:00 +0200 Subject: [PATCH 0159/1011] fix: volume --- templates/compose/wireguard-easy.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/templates/compose/wireguard-easy.yaml b/templates/compose/wireguard-easy.yaml index 56d3c89ce..f0ada4dcf 100644 --- a/templates/compose/wireguard-easy.yaml +++ b/templates/compose/wireguard-easy.yaml @@ -6,15 +6,14 @@ services: wg-easy: image: ghcr.io/wg-easy/wg-easy - container_name: wg-easy environment: + - SERVICE_FQDN_WIREGUARDEASY_8000 - LANG=en - WG_HOST=$SERVICE_FQDN_WIREGUARDEASY - - PASSWORD_HASH=$2y$10$2wrW.nOpZLjGSGaiocD8xOo6uLCa.CebkaqswyAz.hSd5PYKm2WVu - PORT=8000 - WG_PORT=51820 volumes: - - ~/.wg-easy:/etc/wireguard + - wg-easy:/etc/wireguard ports: - "51820:51820/udp" - "8000:8000/tcp" From 55d92e6913edc33b4c41902bc84ba76ae6c05be9 Mon Sep 17 00:00:00 2001 From: Strider27 Date: Sun, 20 Oct 2024 17:52:38 +0100 Subject: [PATCH 0160/1011] Fixed bookstack.yaml - Added APP_KEY as it was not defined and container was erroring out. - Changed DB_USER and DB_PASS to the correct var's (DB_USERNAME and DB_PASSWORD) - Changed healthcheck from wget to curl, as wget kept getting redirected to the external/local ip and failing instead of loading header from localhost 127.0.0.1. Major props to Darren from the discord server for helping/doing all the work really. Just changing it here so others don't have to mess with it. --- templates/compose/bookstack.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/compose/bookstack.yaml b/templates/compose/bookstack.yaml index 0bfe4f8e9..d6a86dcd9 100644 --- a/templates/compose/bookstack.yaml +++ b/templates/compose/bookstack.yaml @@ -10,13 +10,14 @@ services: environment: - SERVICE_FQDN_BOOKSTACK_80 - APP_URL=${SERVICE_FQDN_BOOKSTACK} + - APP_KEY=${SERVICE_PASSWORD_APPKEY} - PUID=1000 - PGID=1000 - TZ=${TZ:-Europe/Berlin} - DB_HOST=mariadb - DB_PORT=3306 - - DB_USER=${SERVICE_USER_MYSQL} - - DB_PASS=${SERVICE_PASSWORD_MYSQL} + - DB_USERNAME=${SERVICE_USER_MYSQL} + - DB_PASSWORD=${SERVICE_PASSWORD_MYSQL} - DB_DATABASE=${MYSQL_DATABASE:-bookstackapp} - QUEUE_CONNECTION=${QUEUE_CONNECTION} # You will need to set up an authentication provider as described at https://www.bookstackapp.com/docs/admin/third-party-auth/. @@ -27,7 +28,7 @@ services: healthcheck: test: - CMD-SHELL - - 'wget -qO- http://127.0.0.1:80/' + - 'curl -f http://127.0.0.1:80/' interval: 5s timeout: 20s retries: 10 From 0d2584e44eedb9cfa0a18721d233c6da35135a09 Mon Sep 17 00:00:00 2001 From: Strider27 Date: Sun, 20 Oct 2024 19:21:35 +0100 Subject: [PATCH 0161/1011] Added SMTP mail support variables to bookstack.yaml More info can be seen here https://www.bookstackapp.com/docs/admin/email-webhooks/#email-configuration/ --- templates/compose/bookstack.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/templates/compose/bookstack.yaml b/templates/compose/bookstack.yaml index d6a86dcd9..dd9719471 100644 --- a/templates/compose/bookstack.yaml +++ b/templates/compose/bookstack.yaml @@ -23,6 +23,15 @@ services: # You will need to set up an authentication provider as described at https://www.bookstackapp.com/docs/admin/third-party-auth/. - GITHUB_APP_ID=${GITHUB_APP_ID} - GITHUB_APP_SECRET=${GITHUB_APP_SECRET} + # SMTP Mail variables as per https://www.bookstackapp.com/docs/admin/email-webhooks/#email-configuration/. + - MAIL_DRIVER=${MAIL_DRIVER:-smtp} + - MAIL_HOST=${MAIL_HOST} + - MAIL_PORT=${MAIL_PORT:-587} + - MAIL_ENCRYPTION=${MAIL_ENCRYPTION:-tls} + - MAIL_USERNAME=${MAIL_USERNAME} + - MAIL_PASSWORD=${MAIL_PASSWORD} + - MAIL_FROM=${MAIL_FROM} + - MAIL_FROM_NAME=${MAIL_FROM_NAME:-BookStack} volumes: - 'bookstack-data:/config' healthcheck: From 97aab8ba286355fbabf9fdb46717371cb16706f2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 20 Oct 2024 22:15:31 +0200 Subject: [PATCH 0162/1011] feat: show warning if people would like to use sslip with https --- app/Livewire/Project/Application/General.php | 7 ++++++- app/Livewire/Project/Service/EditDomain.php | 6 +++++- .../Project/Service/ServiceApplicationView.php | 9 +++++---- bootstrap/helpers/shared.php | 13 ++++++++++++- lang/en.json | 3 ++- .../livewire/project/service/database.blade.php | 1 - 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index 096e18617..9af0c8d8d 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -337,7 +337,12 @@ class General extends Component return str($domain)->trim()->lower(); }); + $this->application->fqdn = $this->application->fqdn->unique()->implode(','); + $warning = sslipDomainWarning($this->application->fqdn); + if ($warning) { + $this->dispatch('warning', __('warning.sslipdomain')); + } $this->resetDefaultLabels(); if ($this->application->isDirty('redirect')) { @@ -403,7 +408,7 @@ class General extends Component } $this->application->custom_labels = base64_encode($this->customLabels); $this->application->save(); - $showToaster && $this->dispatch('success', 'Application settings updated!'); + $showToaster && ! $warning && $this->dispatch('success', 'Application settings updated!'); } catch (\Throwable $e) { $originalFqdn = $this->application->getOriginal('fqdn'); if ($originalFqdn !== $this->application->fqdn) { diff --git a/app/Livewire/Project/Service/EditDomain.php b/app/Livewire/Project/Service/EditDomain.php index b7ef978a8..e89aeda85 100644 --- a/app/Livewire/Project/Service/EditDomain.php +++ b/app/Livewire/Project/Service/EditDomain.php @@ -33,6 +33,10 @@ class EditDomain extends Component return str($domain)->trim()->lower(); }); $this->application->fqdn = $this->application->fqdn->unique()->implode(','); + $warning = sslipDomainWarning($this->application->fqdn); + if ($warning) { + $this->dispatch('warning', __('warning.sslipdomain')); + } check_domain_usage(resource: $this->application); $this->validate(); $this->application->save(); @@ -40,7 +44,7 @@ class EditDomain extends Component if (str($this->application->fqdn)->contains(',')) { $this->dispatch('warning', 'Some services do not support multiple domains, which can lead to problems and is NOT RECOMMENDED.

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

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

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