Merge branch 'next' into include-tip-in-www-redirect-helper
This commit is contained in:
@@ -23,3 +23,5 @@ yarn-error.log
|
|||||||
.rnd
|
.rnd
|
||||||
/.ssh
|
/.ssh
|
||||||
.ignition.json
|
.ignition.json
|
||||||
|
.env.dusk.local
|
||||||
|
docker/coolify-realtime/node_modules
|
||||||
|
15
.env.dusk.ci
Normal file
15
.env.dusk.ci
Normal file
@@ -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
|
||||||
|
|
@@ -4,6 +4,7 @@ APP_ID=coolify-windows-docker-desktop
|
|||||||
APP_NAME=Coolify
|
APP_NAME=Coolify
|
||||||
APP_KEY=base64:ssTlCmrIE/q7whnKMvT6DwURikg69COzGsAwFVROm80=
|
APP_KEY=base64:ssTlCmrIE/q7whnKMvT6DwURikg69COzGsAwFVROm80=
|
||||||
|
|
||||||
|
DB_USERNAME=coolify
|
||||||
DB_PASSWORD=coolify
|
DB_PASSWORD=coolify
|
||||||
REDIS_PASSWORD=coolify
|
REDIS_PASSWORD=coolify
|
||||||
|
|
||||||
|
65
.github/workflows/browser-tests.yml
vendored
Normal file
65
.github/workflows/browser-tests.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: Dusk
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "not-existing" ]
|
||||||
|
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 --port=4444 &
|
||||||
|
- 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
|
89
.github/workflows/coolify-helper-next.yml
vendored
89
.github/workflows/coolify-helper-next.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Coolify Helper Image Development (v4)
|
name: Coolify Helper Image Development
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -8,7 +8,8 @@ on:
|
|||||||
- docker/coolify-helper/Dockerfile
|
- docker/coolify-helper/Dockerfile
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
GITHUB_REGISTRY: ghcr.io
|
||||||
|
DOCKER_REGISTRY: docker.io
|
||||||
IMAGE_NAME: "coollabsio/coolify-helper"
|
IMAGE_NAME: "coollabsio/coolify-helper"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,25 +20,36 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/coolify-helper/Dockerfile
|
file: docker/coolify-helper/Dockerfile
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
push: true
|
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: |
|
labels: |
|
||||||
coolify.managed=true
|
coolify.managed=true
|
||||||
aarch64:
|
aarch64:
|
||||||
@@ -47,27 +59,39 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/coolify-helper/Dockerfile
|
file: docker/coolify-helper/Dockerfile
|
||||||
platforms: linux/aarch64
|
platforms: linux/aarch64
|
||||||
push: true
|
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: |
|
labels: |
|
||||||
coolify.managed=true
|
coolify.managed=true
|
||||||
|
|
||||||
merge-manifest:
|
merge-manifest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
@@ -75,25 +99,42 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
needs: [ amd64, aarch64 ]
|
needs: [ amd64, aarch64 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
- uses: docker/setup-buildx-action@v3
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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: |
|
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
|
- uses: sarisia/actions-status-discord@v1
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
|
93
.github/workflows/coolify-helper.yml
vendored
93
.github/workflows/coolify-helper.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Coolify Helper Image (v4)
|
name: Coolify Helper Image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -8,7 +8,8 @@ on:
|
|||||||
- docker/coolify-helper/Dockerfile
|
- docker/coolify-helper/Dockerfile
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
GITHUB_REGISTRY: ghcr.io
|
||||||
|
DOCKER_REGISTRY: docker.io
|
||||||
IMAGE_NAME: "coollabsio/coolify-helper"
|
IMAGE_NAME: "coollabsio/coolify-helper"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,25 +20,36 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/coolify-helper/Dockerfile
|
file: docker/coolify-helper/Dockerfile
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
push: true
|
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: |
|
labels: |
|
||||||
coolify.managed=true
|
coolify.managed=true
|
||||||
aarch64:
|
aarch64:
|
||||||
@@ -47,25 +59,36 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/coolify-helper/Dockerfile
|
file: docker/coolify-helper/Dockerfile
|
||||||
platforms: linux/aarch64
|
platforms: linux/aarch64
|
||||||
push: true
|
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: |
|
labels: |
|
||||||
coolify.managed=true
|
coolify.managed=true
|
||||||
merge-manifest:
|
merge-manifest:
|
||||||
@@ -75,25 +98,43 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
needs: [ amd64, aarch64 ]
|
needs: [ amd64, aarch64 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up QEMU
|
- uses: docker/setup-buildx-action@v3
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Set up Docker Buildx
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.helper.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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: |
|
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
|
- uses: sarisia/actions-status-discord@v1
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
|
139
.github/workflows/coolify-production-build.yml
vendored
Normal file
139
.github/workflows/coolify-production-build.yml
vendored
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
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/*
|
||||||
|
|
||||||
|
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 }}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
merge-manifest:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
needs: [amd64, aarch64]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- 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 }}
|
96
.github/workflows/coolify-realtime-next.yml
vendored
96
.github/workflows/coolify-realtime-next.yml
vendored
@@ -1,17 +1,19 @@
|
|||||||
name: Coolify Realtime Development (v4)
|
name: Coolify Realtime Development
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "next" ]
|
branches: [ "next" ]
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/coolify-realtime.yml
|
- .github/workflows/coolify-realtime-next.yml
|
||||||
- docker/coolify-realtime/Dockerfile
|
- docker/coolify-realtime/Dockerfile
|
||||||
- docker/coolify-realtime/terminal-server.js
|
- docker/coolify-realtime/terminal-server.js
|
||||||
- docker/coolify-realtime/package.json
|
- docker/coolify-realtime/package.json
|
||||||
|
- docker/coolify-realtime/package-lock.json
|
||||||
- docker/coolify-realtime/soketi-entrypoint.sh
|
- docker/coolify-realtime/soketi-entrypoint.sh
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
GITHUB_REGISTRY: ghcr.io
|
||||||
|
DOCKER_REGISTRY: docker.io
|
||||||
IMAGE_NAME: "coollabsio/coolify-realtime"
|
IMAGE_NAME: "coollabsio/coolify-realtime"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -22,27 +24,39 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/coolify-realtime/Dockerfile
|
file: docker/coolify-realtime/Dockerfile
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
push: true
|
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: |
|
labels: |
|
||||||
coolify.managed=true
|
coolify.managed=true
|
||||||
|
|
||||||
aarch64:
|
aarch64:
|
||||||
runs-on: [ self-hosted, arm64 ]
|
runs-on: [ self-hosted, arm64 ]
|
||||||
permissions:
|
permissions:
|
||||||
@@ -50,27 +64,39 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/coolify-realtime/Dockerfile
|
file: docker/coolify-realtime/Dockerfile
|
||||||
platforms: linux/aarch64
|
platforms: linux/aarch64
|
||||||
push: true
|
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: |
|
labels: |
|
||||||
coolify.managed=true
|
coolify.managed=true
|
||||||
|
|
||||||
merge-manifest:
|
merge-manifest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
@@ -78,26 +104,44 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
needs: [ amd64, aarch64 ]
|
needs: [ amd64, aarch64 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up QEMU
|
- uses: docker/setup-buildx-action@v3
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Set up Docker Buildx
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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: |
|
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
|
- uses: sarisia/actions-status-discord@v1
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}
|
webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
|
||||||
|
92
.github/workflows/coolify-realtime.yml
vendored
92
.github/workflows/coolify-realtime.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Coolify Realtime (v4)
|
name: Coolify Realtime
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -8,10 +8,12 @@ on:
|
|||||||
- docker/coolify-realtime/Dockerfile
|
- docker/coolify-realtime/Dockerfile
|
||||||
- docker/coolify-realtime/terminal-server.js
|
- docker/coolify-realtime/terminal-server.js
|
||||||
- docker/coolify-realtime/package.json
|
- docker/coolify-realtime/package.json
|
||||||
|
- docker/coolify-realtime/package-lock.json
|
||||||
- docker/coolify-realtime/soketi-entrypoint.sh
|
- docker/coolify-realtime/soketi-entrypoint.sh
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
GITHUB_REGISTRY: ghcr.io
|
||||||
|
DOCKER_REGISTRY: docker.io
|
||||||
IMAGE_NAME: "coollabsio/coolify-realtime"
|
IMAGE_NAME: "coollabsio/coolify-realtime"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -22,27 +24,39 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/coolify-realtime/Dockerfile
|
file: docker/coolify-realtime/Dockerfile
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
push: true
|
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: |
|
labels: |
|
||||||
coolify.managed=true
|
coolify.managed=true
|
||||||
|
|
||||||
aarch64:
|
aarch64:
|
||||||
runs-on: [ self-hosted, arm64 ]
|
runs-on: [ self-hosted, arm64 ]
|
||||||
permissions:
|
permissions:
|
||||||
@@ -50,27 +64,39 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/coolify-realtime/Dockerfile
|
file: docker/coolify-realtime/Dockerfile
|
||||||
platforms: linux/aarch64
|
platforms: linux/aarch64
|
||||||
push: true
|
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: |
|
labels: |
|
||||||
coolify.managed=true
|
coolify.managed=true
|
||||||
|
|
||||||
merge-manifest:
|
merge-manifest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
@@ -78,25 +104,43 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
needs: [ amd64, aarch64 ]
|
needs: [ amd64, aarch64 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up QEMU
|
- uses: docker/setup-buildx-action@v3
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Set up Docker Buildx
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Get Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
|
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: |
|
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
|
- uses: sarisia/actions-status-discord@v1
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
|
125
.github/workflows/coolify-staging-build.yml
vendored
Normal file
125
.github/workflows/coolify-staging-build.yml
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
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
|
||||||
|
- docker/testing-host/Dockerfile
|
||||||
|
- templates/*
|
||||||
|
|
||||||
|
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 }}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
merge-manifest:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
needs: [amd64, aarch64]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- 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 }}
|
92
.github/workflows/coolify-testing-host.yml
vendored
92
.github/workflows/coolify-testing-host.yml
vendored
@@ -1,14 +1,15 @@
|
|||||||
name: Coolify Testing Host (v4-non-prod)
|
name: Coolify Testing Host
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "main", "next" ]
|
branches: [ "next" ]
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/coolify-testing-host.yml
|
- .github/workflows/coolify-testing-host.yml
|
||||||
- docker/testing-host/Dockerfile
|
- docker/testing-host/Dockerfile
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
GITHUB_REGISTRY: ghcr.io
|
||||||
|
DOCKER_REGISTRY: docker.io
|
||||||
IMAGE_NAME: "coollabsio/coolify-testing-host"
|
IMAGE_NAME: "coollabsio/coolify-testing-host"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,21 +20,34 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/testing-host/Dockerfile
|
file: docker/testing-host/Dockerfile
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
tags: |
|
||||||
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||||
|
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||||
|
labels: |
|
||||||
|
coolify.managed=true
|
||||||
|
|
||||||
aarch64:
|
aarch64:
|
||||||
runs-on: [ self-hosted, arm64 ]
|
runs-on: [ self-hosted, arm64 ]
|
||||||
permissions:
|
permissions:
|
||||||
@@ -41,21 +55,34 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
|
||||||
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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:
|
with:
|
||||||
no-cache: true
|
|
||||||
context: .
|
context: .
|
||||||
file: docker/testing-host/Dockerfile
|
file: docker/testing-host/Dockerfile
|
||||||
platforms: linux/aarch64
|
platforms: linux/aarch64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64
|
tags: |
|
||||||
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64
|
||||||
|
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64
|
||||||
|
labels: |
|
||||||
|
coolify.managed=true
|
||||||
|
|
||||||
merge-manifest:
|
merge-manifest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
@@ -63,21 +90,36 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
needs: [ amd64, aarch64 ]
|
needs: [ amd64, aarch64 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up QEMU
|
- uses: docker/setup-buildx-action@v3
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Set up Docker Buildx
|
- name: Login to ${{ env.GITHUB_REGISTRY }}
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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: |
|
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
|
- uses: sarisia/actions-status-discord@v1
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
|
79
.github/workflows/development-build.yml
vendored
79
.github/workflows/development-build.yml
vendored
@@ -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 }}
|
|
89
.github/workflows/production-build.yml
vendored
89
.github/workflows/production-build.yml
vendored
@@ -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 }}
|
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -33,3 +33,5 @@ _ide_helper_models.php
|
|||||||
/.ssh
|
/.ssh
|
||||||
scripts/load-test/*
|
scripts/load-test/*
|
||||||
.ignition.json
|
.ignition.json
|
||||||
|
.env.dusk.local
|
||||||
|
docker/coolify-realtime/node_modules
|
||||||
|
@@ -11,7 +11,6 @@ class GenerateConfig
|
|||||||
|
|
||||||
public function handle(Application $application, bool $is_json = false)
|
public function handle(Application $application, bool $is_json = false)
|
||||||
{
|
{
|
||||||
ray()->clearAll();
|
|
||||||
return $application->generateConfig(is_json: $is_json);
|
return $application->generateConfig(is_json: $is_json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@ class StopApplication
|
|||||||
if (! $server->isFunctional()) {
|
if (! $server->isFunctional()) {
|
||||||
return 'Server is not functional';
|
return 'Server is not functional';
|
||||||
}
|
}
|
||||||
ray('Stopping application: '.$application->name);
|
|
||||||
|
|
||||||
if ($server->isSwarm()) {
|
if ($server->isSwarm()) {
|
||||||
instant_remote_process(["docker stack rm {$application->uuid}"], $server);
|
instant_remote_process(["docker stack rm {$application->uuid}"], $server);
|
||||||
@@ -36,8 +35,6 @@ class StopApplication
|
|||||||
CleanupDocker::dispatch($server, true);
|
CleanupDocker::dispatch($server, true);
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,8 +32,6 @@ class StopApplicationOneServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,7 +48,6 @@ class PrepareCoolifyTask
|
|||||||
call_event_data: $this->remoteProcessArgs->call_event_data,
|
call_event_data: $this->remoteProcessArgs->call_event_data,
|
||||||
);
|
);
|
||||||
if ($this->remoteProcessArgs->type === ActivityTypes::COMMAND->value) {
|
if ($this->remoteProcessArgs->type === ActivityTypes::COMMAND->value) {
|
||||||
ray('Dispatching a high priority job');
|
|
||||||
dispatch($job)->onQueue('high');
|
dispatch($job)->onQueue('high');
|
||||||
} else {
|
} else {
|
||||||
dispatch($job);
|
dispatch($job);
|
||||||
|
@@ -9,6 +9,7 @@ use App\Jobs\ApplicationDeploymentJob;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Process\ProcessResult;
|
use Illuminate\Process\ProcessResult;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Process;
|
use Illuminate\Support\Facades\Process;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
|
|
||||||
@@ -39,7 +40,6 @@ class RunRemoteProcess
|
|||||||
*/
|
*/
|
||||||
public function __construct(Activity $activity, bool $hide_from_output = false, bool $ignore_errors = false, $call_event_on_finish = null, $call_event_data = null)
|
public function __construct(Activity $activity, bool $hide_from_output = false, bool $ignore_errors = false, $call_event_on_finish = null, $call_event_data = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value && $activity->getExtraProperty('type') !== ActivityTypes::COMMAND->value) {
|
if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value && $activity->getExtraProperty('type') !== ActivityTypes::COMMAND->value) {
|
||||||
throw new \RuntimeException('Incompatible Activity to run a remote command.');
|
throw new \RuntimeException('Incompatible Activity to run a remote command.');
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ class RunRemoteProcess
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e);
|
Log::error('Error calling event: '.$e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -51,6 +51,8 @@ class StartClickhouse
|
|||||||
],
|
],
|
||||||
'labels' => [
|
'labels' => [
|
||||||
'coolify.managed' => 'true',
|
'coolify.managed' => 'true',
|
||||||
|
'coolify.type' => 'database',
|
||||||
|
'coolify.databaseId' => $this->database->id,
|
||||||
],
|
],
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => "clickhouse-client --password {$this->database->clickhouse_admin_password} --query 'SELECT 1'",
|
'test' => "clickhouse-client --password {$this->database->clickhouse_admin_password} --query 'SELECT 1'",
|
||||||
@@ -97,8 +99,8 @@ class StartClickhouse
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($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 = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
@@ -23,33 +23,33 @@ class StartDatabase
|
|||||||
return 'Server is not functional';
|
return 'Server is not functional';
|
||||||
}
|
}
|
||||||
switch ($database->getMorphClass()) {
|
switch ($database->getMorphClass()) {
|
||||||
case 'App\Models\StandalonePostgresql':
|
case \App\Models\StandalonePostgresql::class:
|
||||||
$activity = StartPostgresql::run($database);
|
$activity = StartPostgresql::run($database);
|
||||||
break;
|
break;
|
||||||
case 'App\Models\StandaloneRedis':
|
case \App\Models\StandaloneRedis::class:
|
||||||
$activity = StartRedis::run($database);
|
$activity = StartRedis::run($database);
|
||||||
break;
|
break;
|
||||||
case 'App\Models\StandaloneMongodb':
|
case \App\Models\StandaloneMongodb::class:
|
||||||
$activity = StartMongodb::run($database);
|
$activity = StartMongodb::run($database);
|
||||||
break;
|
break;
|
||||||
case 'App\Models\StandaloneMysql':
|
case \App\Models\StandaloneMysql::class:
|
||||||
$activity = StartMysql::run($database);
|
$activity = StartMysql::run($database);
|
||||||
break;
|
break;
|
||||||
case 'App\Models\StandaloneMariadb':
|
case \App\Models\StandaloneMariadb::class:
|
||||||
$activity = StartMariadb::run($database);
|
$activity = StartMariadb::run($database);
|
||||||
break;
|
break;
|
||||||
case 'App\Models\StandaloneKeydb':
|
case \App\Models\StandaloneKeydb::class:
|
||||||
$activity = StartKeydb::run($database);
|
$activity = StartKeydb::run($database);
|
||||||
break;
|
break;
|
||||||
case 'App\Models\StandaloneDragonfly':
|
case \App\Models\StandaloneDragonfly::class:
|
||||||
$activity = StartDragonfly::run($database);
|
$activity = StartDragonfly::run($database);
|
||||||
break;
|
break;
|
||||||
case 'App\Models\StandaloneClickhouse':
|
case \App\Models\StandaloneClickhouse::class:
|
||||||
$activity = StartClickhouse::run($database);
|
$activity = StartClickhouse::run($database);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ($database->is_public && $database->public_port) {
|
if ($database->is_public && $database->public_port) {
|
||||||
StartDatabaseProxy::dispatch($database);
|
StartDatabaseProxy::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $activity;
|
return $activity;
|
||||||
|
@@ -26,7 +26,7 @@ class StartDatabaseProxy
|
|||||||
$server = data_get($database, 'destination.server');
|
$server = data_get($database, 'destination.server');
|
||||||
$containerName = data_get($database, 'uuid');
|
$containerName = data_get($database, 'uuid');
|
||||||
$proxyContainerName = "{$database->uuid}-proxy";
|
$proxyContainerName = "{$database->uuid}-proxy";
|
||||||
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
|
||||||
$databaseType = $database->databaseType();
|
$databaseType = $database->databaseType();
|
||||||
// $connectPredefined = data_get($database, 'service.connect_to_docker_network');
|
// $connectPredefined = data_get($database, 'service.connect_to_docker_network');
|
||||||
$network = $database->service->uuid;
|
$network = $database->service->uuid;
|
||||||
@@ -34,54 +34,54 @@ class StartDatabaseProxy
|
|||||||
$proxyContainerName = "{$database->service->uuid}-proxy";
|
$proxyContainerName = "{$database->service->uuid}-proxy";
|
||||||
switch ($databaseType) {
|
switch ($databaseType) {
|
||||||
case 'standalone-mariadb':
|
case 'standalone-mariadb':
|
||||||
$type = 'App\Models\StandaloneMariadb';
|
$type = \App\Models\StandaloneMariadb::class;
|
||||||
$containerName = "mariadb-{$database->service->uuid}";
|
$containerName = "mariadb-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-mongodb':
|
case 'standalone-mongodb':
|
||||||
$type = 'App\Models\StandaloneMongodb';
|
$type = \App\Models\StandaloneMongodb::class;
|
||||||
$containerName = "mongodb-{$database->service->uuid}";
|
$containerName = "mongodb-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-mysql':
|
case 'standalone-mysql':
|
||||||
$type = 'App\Models\StandaloneMysql';
|
$type = \App\Models\StandaloneMysql::class;
|
||||||
$containerName = "mysql-{$database->service->uuid}";
|
$containerName = "mysql-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-postgresql':
|
case 'standalone-postgresql':
|
||||||
$type = 'App\Models\StandalonePostgresql';
|
$type = \App\Models\StandalonePostgresql::class;
|
||||||
$containerName = "postgresql-{$database->service->uuid}";
|
$containerName = "postgresql-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-redis':
|
case 'standalone-redis':
|
||||||
$type = 'App\Models\StandaloneRedis';
|
$type = \App\Models\StandaloneRedis::class;
|
||||||
$containerName = "redis-{$database->service->uuid}";
|
$containerName = "redis-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-keydb':
|
case 'standalone-keydb':
|
||||||
$type = 'App\Models\StandaloneKeydb';
|
$type = \App\Models\StandaloneKeydb::class;
|
||||||
$containerName = "keydb-{$database->service->uuid}";
|
$containerName = "keydb-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-dragonfly':
|
case 'standalone-dragonfly':
|
||||||
$type = 'App\Models\StandaloneDragonfly';
|
$type = \App\Models\StandaloneDragonfly::class;
|
||||||
$containerName = "dragonfly-{$database->service->uuid}";
|
$containerName = "dragonfly-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-clickhouse':
|
case 'standalone-clickhouse':
|
||||||
$type = 'App\Models\StandaloneClickhouse';
|
$type = \App\Models\StandaloneClickhouse::class;
|
||||||
$containerName = "clickhouse-{$database->service->uuid}";
|
$containerName = "clickhouse-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($type === 'App\Models\StandaloneRedis') {
|
if ($type === \App\Models\StandaloneRedis::class) {
|
||||||
$internalPort = 6379;
|
$internalPort = 6379;
|
||||||
} elseif ($type === 'App\Models\StandalonePostgresql') {
|
} elseif ($type === \App\Models\StandalonePostgresql::class) {
|
||||||
$internalPort = 5432;
|
$internalPort = 5432;
|
||||||
} elseif ($type === 'App\Models\StandaloneMongodb') {
|
} elseif ($type === \App\Models\StandaloneMongodb::class) {
|
||||||
$internalPort = 27017;
|
$internalPort = 27017;
|
||||||
} elseif ($type === 'App\Models\StandaloneMysql') {
|
} elseif ($type === \App\Models\StandaloneMysql::class) {
|
||||||
$internalPort = 3306;
|
$internalPort = 3306;
|
||||||
} elseif ($type === 'App\Models\StandaloneMariadb') {
|
} elseif ($type === \App\Models\StandaloneMariadb::class) {
|
||||||
$internalPort = 3306;
|
$internalPort = 3306;
|
||||||
} elseif ($type === 'App\Models\StandaloneKeydb') {
|
} elseif ($type === \App\Models\StandaloneKeydb::class) {
|
||||||
$internalPort = 6379;
|
$internalPort = 6379;
|
||||||
} elseif ($type === 'App\Models\StandaloneDragonfly') {
|
} elseif ($type === \App\Models\StandaloneDragonfly::class) {
|
||||||
$internalPort = 6379;
|
$internalPort = 6379;
|
||||||
} elseif ($type === 'App\Models\StandaloneClickhouse') {
|
} elseif ($type === \App\Models\StandaloneClickhouse::class) {
|
||||||
$internalPort = 9000;
|
$internalPort = 9000;
|
||||||
}
|
}
|
||||||
$configuration_dir = database_proxy_dir($database->uuid);
|
$configuration_dir = database_proxy_dir($database->uuid);
|
||||||
|
@@ -48,6 +48,8 @@ class StartDragonfly
|
|||||||
],
|
],
|
||||||
'labels' => [
|
'labels' => [
|
||||||
'coolify.managed' => 'true',
|
'coolify.managed' => 'true',
|
||||||
|
'coolify.type' => 'database',
|
||||||
|
'coolify.databaseId' => $this->database->id,
|
||||||
],
|
],
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => "redis-cli -a {$this->database->dragonfly_password} ping",
|
'test' => "redis-cli -a {$this->database->dragonfly_password} ping",
|
||||||
@@ -94,8 +96,8 @@ class StartDragonfly
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($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 = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
@@ -50,6 +50,8 @@ class StartKeydb
|
|||||||
],
|
],
|
||||||
'labels' => [
|
'labels' => [
|
||||||
'coolify.managed' => 'true',
|
'coolify.managed' => 'true',
|
||||||
|
'coolify.type' => 'database',
|
||||||
|
'coolify.databaseId' => $this->database->id,
|
||||||
],
|
],
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => "keydb-cli --pass {$this->database->keydb_password} ping",
|
'test' => "keydb-cli --pass {$this->database->keydb_password} ping",
|
||||||
@@ -105,8 +107,8 @@ class StartKeydb
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($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 = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||||
|
@@ -45,6 +45,8 @@ class StartMariadb
|
|||||||
],
|
],
|
||||||
'labels' => [
|
'labels' => [
|
||||||
'coolify.managed' => 'true',
|
'coolify.managed' => 'true',
|
||||||
|
'coolify.type' => 'database',
|
||||||
|
'coolify.databaseId' => $this->database->id,
|
||||||
],
|
],
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized'],
|
'test' => ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized'],
|
||||||
@@ -99,8 +101,8 @@ class StartMariadb
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($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 = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
@@ -25,6 +25,10 @@ class StartMongodb
|
|||||||
$container_name = $this->database->uuid;
|
$container_name = $this->database->uuid;
|
||||||
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||||
|
|
||||||
|
if (isDev()) {
|
||||||
|
$this->configuration_dir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/databases/'.$container_name;
|
||||||
|
}
|
||||||
|
|
||||||
$this->commands = [
|
$this->commands = [
|
||||||
"echo 'Starting {$database->name}.'",
|
"echo 'Starting {$database->name}.'",
|
||||||
"mkdir -p $this->configuration_dir",
|
"mkdir -p $this->configuration_dir",
|
||||||
@@ -49,6 +53,8 @@ class StartMongodb
|
|||||||
],
|
],
|
||||||
'labels' => [
|
'labels' => [
|
||||||
'coolify.managed' => 'true',
|
'coolify.managed' => 'true',
|
||||||
|
'coolify.type' => 'database',
|
||||||
|
'coolify.databaseId' => $this->database->id,
|
||||||
],
|
],
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => [
|
'test' => [
|
||||||
@@ -115,8 +121,8 @@ class StartMongodb
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($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 = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
@@ -45,6 +45,8 @@ class StartMysql
|
|||||||
],
|
],
|
||||||
'labels' => [
|
'labels' => [
|
||||||
'coolify.managed' => 'true',
|
'coolify.managed' => 'true',
|
||||||
|
'coolify.type' => 'database',
|
||||||
|
'coolify.databaseId' => $this->database->id,
|
||||||
],
|
],
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => ['CMD', 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', "-p{$this->database->mysql_root_password}"],
|
'test' => ['CMD', 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', "-p{$this->database->mysql_root_password}"],
|
||||||
@@ -99,8 +101,8 @@ class StartMysql
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($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 = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
@@ -49,6 +49,8 @@ class StartPostgresql
|
|||||||
],
|
],
|
||||||
'labels' => [
|
'labels' => [
|
||||||
'coolify.managed' => 'true',
|
'coolify.managed' => 'true',
|
||||||
|
'coolify.type' => 'database',
|
||||||
|
'coolify.databaseId' => $this->database->id,
|
||||||
],
|
],
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => [
|
'test' => [
|
||||||
@@ -120,8 +122,8 @@ class StartPostgresql
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($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 = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
@@ -21,8 +21,6 @@ class StartRedis
|
|||||||
{
|
{
|
||||||
$this->database = $database;
|
$this->database = $database;
|
||||||
|
|
||||||
$startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes";
|
|
||||||
|
|
||||||
$container_name = $this->database->uuid;
|
$container_name = $this->database->uuid;
|
||||||
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||||
|
|
||||||
@@ -37,6 +35,8 @@ class StartRedis
|
|||||||
$environment_variables = $this->generate_environment_variables();
|
$environment_variables = $this->generate_environment_variables();
|
||||||
$this->add_custom_redis();
|
$this->add_custom_redis();
|
||||||
|
|
||||||
|
$startCommand = $this->buildStartCommand();
|
||||||
|
|
||||||
$docker_compose = [
|
$docker_compose = [
|
||||||
'services' => [
|
'services' => [
|
||||||
$container_name => [
|
$container_name => [
|
||||||
@@ -50,6 +50,8 @@ class StartRedis
|
|||||||
],
|
],
|
||||||
'labels' => [
|
'labels' => [
|
||||||
'coolify.managed' => 'true',
|
'coolify.managed' => 'true',
|
||||||
|
'coolify.type' => 'database',
|
||||||
|
'coolify.databaseId' => $this->database->id,
|
||||||
],
|
],
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => [
|
'test' => [
|
||||||
@@ -105,12 +107,11 @@ class StartRedis
|
|||||||
'target' => '/usr/local/etc/redis/redis.conf',
|
'target' => '/usr/local/etc/redis/redis.conf',
|
||||||
'read_only' => true,
|
'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
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($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 = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
@@ -160,12 +161,26 @@ class StartRedis
|
|||||||
private function generate_environment_variables()
|
private function generate_environment_variables()
|
||||||
{
|
{
|
||||||
$environment_variables = collect();
|
$environment_variables = collect();
|
||||||
foreach ($this->database->runtime_environment_variables as $env) {
|
|
||||||
$environment_variables->push("$env->key=$env->real_value");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
|
foreach ($this->database->runtime_environment_variables as $env) {
|
||||||
$environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}");
|
if ($env->is_shared) {
|
||||||
|
$environment_variables->push("$env->key=$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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
|
add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
|
||||||
@@ -173,6 +188,27 @@ class StartRedis
|
|||||||
return $environment_variables->all();
|
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()
|
private function add_custom_redis()
|
||||||
{
|
{
|
||||||
if (is_null($this->database->redis_conf) || empty($this->database->redis_conf)) {
|
if (is_null($this->database->redis_conf) || empty($this->database->redis_conf)) {
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Actions\Database;
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
use App\Events\DatabaseStatusChanged;
|
use App\Events\DatabaseProxyStopped;
|
||||||
use App\Models\ServiceDatabase;
|
use App\Models\ServiceDatabase;
|
||||||
use App\Models\StandaloneClickhouse;
|
use App\Models\StandaloneClickhouse;
|
||||||
use App\Models\StandaloneDragonfly;
|
use App\Models\StandaloneDragonfly;
|
||||||
@@ -22,12 +22,16 @@ class StopDatabaseProxy
|
|||||||
{
|
{
|
||||||
$server = data_get($database, 'destination.server');
|
$server = data_get($database, 'destination.server');
|
||||||
$uuid = $database->uuid;
|
$uuid = $database->uuid;
|
||||||
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
|
||||||
$uuid = $database->service->uuid;
|
$uuid = $database->service->uuid;
|
||||||
$server = data_get($database, 'service.server');
|
$server = data_get($database, 'service.server');
|
||||||
}
|
}
|
||||||
instant_remote_process(["docker rm -f {$uuid}-proxy"], $server);
|
instant_remote_process(["docker rm -f {$uuid}-proxy"], $server);
|
||||||
|
|
||||||
|
$database->is_public = false;
|
||||||
$database->save();
|
$database->save();
|
||||||
DatabaseStatusChanged::dispatch();
|
|
||||||
|
DatabaseProxyStopped::dispatch();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,14 +3,11 @@
|
|||||||
namespace App\Actions\Docker;
|
namespace App\Actions\Docker;
|
||||||
|
|
||||||
use App\Actions\Database\StartDatabaseProxy;
|
use App\Actions\Database\StartDatabaseProxy;
|
||||||
use App\Actions\Proxy\CheckProxy;
|
|
||||||
use App\Actions\Proxy\StartProxy;
|
|
||||||
use App\Actions\Shared\ComplexStatusCheck;
|
use App\Actions\Shared\ComplexStatusCheck;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\ServiceDatabase;
|
use App\Models\ServiceDatabase;
|
||||||
use App\Notifications\Container\ContainerRestarted;
|
use App\Notifications\Container\ContainerRestarted;
|
||||||
use App\Notifications\Container\ContainerStopped;
|
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
@@ -33,7 +30,7 @@ class GetContainersStatus
|
|||||||
$this->containerReplicates = $containerReplicates;
|
$this->containerReplicates = $containerReplicates;
|
||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
if (! $this->server->isFunctional()) {
|
if (! $this->server->isFunctional()) {
|
||||||
return 'Server is not ready.';
|
return 'Server is not functional.';
|
||||||
}
|
}
|
||||||
$this->applications = $this->server->applications();
|
$this->applications = $this->server->applications();
|
||||||
$skip_these_applications = collect([]);
|
$skip_these_applications = collect([]);
|
||||||
@@ -49,323 +46,8 @@ class GetContainersStatus
|
|||||||
$this->applications = $this->applications->filter(function ($value, $key) use ($skip_these_applications) {
|
$this->applications = $this->applications->filter(function ($value, $key) use ($skip_these_applications) {
|
||||||
return ! $skip_these_applications->pluck('id')->contains($value->id);
|
return ! $skip_these_applications->pluck('id')->contains($value->id);
|
||||||
});
|
});
|
||||||
$this->old_way();
|
|
||||||
// if ($this->server->isSwarm()) {
|
|
||||||
// $this->old_way();
|
|
||||||
// } else {
|
|
||||||
// if (!$this->server->is_metrics_enabled) {
|
|
||||||
// $this->old_way();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// $sentinel_found = instant_remote_process(["docker inspect coolify-sentinel"], $this->server, false);
|
|
||||||
// $sentinel_found = json_decode($sentinel_found, true);
|
|
||||||
// $status = data_get($sentinel_found, '0.State.Status', 'exited');
|
|
||||||
// if ($status === 'running') {
|
|
||||||
// ray('Checking with Sentinel');
|
|
||||||
// $this->sentinel();
|
|
||||||
// } else {
|
|
||||||
// ray('Checking the Old way');
|
|
||||||
// $this->old_way();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// private function sentinel()
|
|
||||||
// {
|
|
||||||
// try {
|
|
||||||
// $this->containers = $this->server->getContainersWithSentinel();
|
|
||||||
// if ($this->containers->count() === 0) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// $databases = $this->server->databases();
|
|
||||||
// $services = $this->server->services()->get();
|
|
||||||
// $previews = $this->server->previews();
|
|
||||||
// $foundApplications = [];
|
|
||||||
// $foundApplicationPreviews = [];
|
|
||||||
// $foundDatabases = [];
|
|
||||||
// $foundServices = [];
|
|
||||||
|
|
||||||
// foreach ($this->containers as $container) {
|
|
||||||
// $labels = Arr::undot(data_get($container, 'labels'));
|
|
||||||
// $containerStatus = data_get($container, 'state');
|
|
||||||
// $containerHealth = data_get($container, 'health_status', 'unhealthy');
|
|
||||||
// $containerStatus = "$containerStatus ($containerHealth)";
|
|
||||||
// $applicationId = data_get($labels, 'coolify.applicationId');
|
|
||||||
// if ($applicationId) {
|
|
||||||
// $pullRequestId = data_get($labels, 'coolify.pullRequestId');
|
|
||||||
// if ($pullRequestId) {
|
|
||||||
// if (str($applicationId)->contains('-')) {
|
|
||||||
// $applicationId = str($applicationId)->before('-');
|
|
||||||
// }
|
|
||||||
// $preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
|
||||||
// if ($preview) {
|
|
||||||
// $foundApplicationPreviews[] = $preview->id;
|
|
||||||
// $statusFromDb = $preview->status;
|
|
||||||
// if ($statusFromDb !== $containerStatus) {
|
|
||||||
// $preview->update(['status' => $containerStatus]);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// //Notify user that this container should not be there.
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// $application = $this->applications->where('id', $applicationId)->first();
|
|
||||||
// if ($application) {
|
|
||||||
// $foundApplications[] = $application->id;
|
|
||||||
// $statusFromDb = $application->status;
|
|
||||||
// if ($statusFromDb !== $containerStatus) {
|
|
||||||
// $application->update(['status' => $containerStatus]);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// //Notify user that this container should not be there.
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// $uuid = data_get($labels, 'com.docker.compose.service');
|
|
||||||
// $type = data_get($labels, 'coolify.type');
|
|
||||||
// if ($uuid) {
|
|
||||||
// if ($type === 'service') {
|
|
||||||
// $database_id = data_get($labels, 'coolify.service.subId');
|
|
||||||
// if ($database_id) {
|
|
||||||
// $service_db = ServiceDatabase::where('id', $database_id)->first();
|
|
||||||
// if ($service_db) {
|
|
||||||
// $uuid = $service_db->service->uuid;
|
|
||||||
// $isPublic = data_get($service_db, 'is_public');
|
|
||||||
// if ($isPublic) {
|
|
||||||
// $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
|
||||||
// if ($this->server->isSwarm()) {
|
|
||||||
// // TODO: fix this with sentinel
|
|
||||||
// return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
|
||||||
// } else {
|
|
||||||
// return data_get($value, 'name') === "$uuid-proxy";
|
|
||||||
// }
|
|
||||||
// })->first();
|
|
||||||
// if (! $foundTcpProxy) {
|
|
||||||
// StartDatabaseProxy::run($service_db);
|
|
||||||
// // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// $database = $databases->where('uuid', $uuid)->first();
|
|
||||||
// if ($database) {
|
|
||||||
// $isPublic = data_get($database, 'is_public');
|
|
||||||
// $foundDatabases[] = $database->id;
|
|
||||||
// $statusFromDb = $database->status;
|
|
||||||
// if ($statusFromDb !== $containerStatus) {
|
|
||||||
// $database->update(['status' => $containerStatus]);
|
|
||||||
// }
|
|
||||||
// if ($isPublic) {
|
|
||||||
// $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
|
||||||
// if ($this->server->isSwarm()) {
|
|
||||||
// // TODO: fix this with sentinel
|
|
||||||
// return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
|
||||||
// } else {
|
|
||||||
// return data_get($value, 'name') === "$uuid-proxy";
|
|
||||||
// }
|
|
||||||
// })->first();
|
|
||||||
// if (! $foundTcpProxy) {
|
|
||||||
// StartDatabaseProxy::run($database);
|
|
||||||
// $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // Notify user that this container should not be there.
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (data_get($container, 'name') === 'coolify-db') {
|
|
||||||
// $foundDatabases[] = 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// $serviceLabelId = data_get($labels, 'coolify.serviceId');
|
|
||||||
// if ($serviceLabelId) {
|
|
||||||
// $subType = data_get($labels, 'coolify.service.subType');
|
|
||||||
// $subId = data_get($labels, 'coolify.service.subId');
|
|
||||||
// $service = $services->where('id', $serviceLabelId)->first();
|
|
||||||
// if (! $service) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// if ($subType === 'application') {
|
|
||||||
// $service = $service->applications()->where('id', $subId)->first();
|
|
||||||
// } else {
|
|
||||||
// $service = $service->databases()->where('id', $subId)->first();
|
|
||||||
// }
|
|
||||||
// if ($service) {
|
|
||||||
// $foundServices[] = "$service->id-$service->name";
|
|
||||||
// $statusFromDb = $service->status;
|
|
||||||
// if ($statusFromDb !== $containerStatus) {
|
|
||||||
// // ray('Updating status: ' . $containerStatus);
|
|
||||||
// $service->update(['status' => $containerStatus]);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// $exitedServices = collect([]);
|
|
||||||
// foreach ($services as $service) {
|
|
||||||
// $apps = $service->applications()->get();
|
|
||||||
// $dbs = $service->databases()->get();
|
|
||||||
// foreach ($apps as $app) {
|
|
||||||
// if (in_array("$app->id-$app->name", $foundServices)) {
|
|
||||||
// continue;
|
|
||||||
// } else {
|
|
||||||
// $exitedServices->push($app);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// foreach ($dbs as $db) {
|
|
||||||
// if (in_array("$db->id-$db->name", $foundServices)) {
|
|
||||||
// continue;
|
|
||||||
// } else {
|
|
||||||
// $exitedServices->push($db);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// $exitedServices = $exitedServices->unique('id');
|
|
||||||
// foreach ($exitedServices as $exitedService) {
|
|
||||||
// if (str($exitedService->status)->startsWith('exited')) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// $name = data_get($exitedService, 'name');
|
|
||||||
// $fqdn = data_get($exitedService, 'fqdn');
|
|
||||||
// if ($name) {
|
|
||||||
// if ($fqdn) {
|
|
||||||
// $containerName = "$name, available at $fqdn";
|
|
||||||
// } else {
|
|
||||||
// $containerName = $name;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// if ($fqdn) {
|
|
||||||
// $containerName = $fqdn;
|
|
||||||
// } else {
|
|
||||||
// $containerName = null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// $projectUuid = data_get($service, 'environment.project.uuid');
|
|
||||||
// $serviceUuid = data_get($service, 'uuid');
|
|
||||||
// $environmentName = data_get($service, 'environment.name');
|
|
||||||
|
|
||||||
// if ($projectUuid && $serviceUuid && $environmentName) {
|
|
||||||
// $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/service/'.$serviceUuid;
|
|
||||||
// } else {
|
|
||||||
// $url = null;
|
|
||||||
// }
|
|
||||||
// // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
|
||||||
// $exitedService->update(['status' => 'exited']);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $notRunningApplications = $this->applications->pluck('id')->diff($foundApplications);
|
|
||||||
// foreach ($notRunningApplications as $applicationId) {
|
|
||||||
// $application = $this->applications->where('id', $applicationId)->first();
|
|
||||||
// if (str($application->status)->startsWith('exited')) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// $application->update(['status' => 'exited']);
|
|
||||||
|
|
||||||
// $name = data_get($application, 'name');
|
|
||||||
// $fqdn = data_get($application, 'fqdn');
|
|
||||||
|
|
||||||
// $containerName = $name ? "$name ($fqdn)" : $fqdn;
|
|
||||||
|
|
||||||
// $projectUuid = data_get($application, 'environment.project.uuid');
|
|
||||||
// $applicationUuid = data_get($application, 'uuid');
|
|
||||||
// $environment = data_get($application, 'environment.name');
|
|
||||||
|
|
||||||
// if ($projectUuid && $applicationUuid && $environment) {
|
|
||||||
// $url = base_url().'/project/'.$projectUuid.'/'.$environment.'/application/'.$applicationUuid;
|
|
||||||
// } else {
|
|
||||||
// $url = null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
|
||||||
// }
|
|
||||||
// $notRunningApplicationPreviews = $previews->pluck('id')->diff($foundApplicationPreviews);
|
|
||||||
// foreach ($notRunningApplicationPreviews as $previewId) {
|
|
||||||
// $preview = $previews->where('id', $previewId)->first();
|
|
||||||
// if (str($preview->status)->startsWith('exited')) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// $preview->update(['status' => 'exited']);
|
|
||||||
|
|
||||||
// $name = data_get($preview, 'name');
|
|
||||||
// $fqdn = data_get($preview, 'fqdn');
|
|
||||||
|
|
||||||
// $containerName = $name ? "$name ($fqdn)" : $fqdn;
|
|
||||||
|
|
||||||
// $projectUuid = data_get($preview, 'application.environment.project.uuid');
|
|
||||||
// $environmentName = data_get($preview, 'application.environment.name');
|
|
||||||
// $applicationUuid = data_get($preview, 'application.uuid');
|
|
||||||
|
|
||||||
// if ($projectUuid && $applicationUuid && $environmentName) {
|
|
||||||
// $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/application/'.$applicationUuid;
|
|
||||||
// } else {
|
|
||||||
// $url = null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
|
||||||
// }
|
|
||||||
// $notRunningDatabases = $databases->pluck('id')->diff($foundDatabases);
|
|
||||||
// foreach ($notRunningDatabases as $database) {
|
|
||||||
// $database = $databases->where('id', $database)->first();
|
|
||||||
// if (str($database->status)->startsWith('exited')) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// $database->update(['status' => 'exited']);
|
|
||||||
|
|
||||||
// $name = data_get($database, 'name');
|
|
||||||
// $fqdn = data_get($database, 'fqdn');
|
|
||||||
|
|
||||||
// $containerName = $name;
|
|
||||||
|
|
||||||
// $projectUuid = data_get($database, 'environment.project.uuid');
|
|
||||||
// $environmentName = data_get($database, 'environment.name');
|
|
||||||
// $databaseUuid = data_get($database, 'uuid');
|
|
||||||
|
|
||||||
// if ($projectUuid && $databaseUuid && $environmentName) {
|
|
||||||
// $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid;
|
|
||||||
// } else {
|
|
||||||
// $url = null;
|
|
||||||
// }
|
|
||||||
// // $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()) {
|
|
||||||
// // TODO: fix this with sentinel
|
|
||||||
// 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');
|
|
||||||
// $this->server->save();
|
|
||||||
// $connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
|
|
||||||
// instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
|
|
||||||
// }
|
|
||||||
// } catch (\Exception $e) {
|
|
||||||
// // send_internal_notification("ContainerStatusJob failed on ({$this->server->id}) with: " . $e->getMessage());
|
|
||||||
// ray($e->getMessage());
|
|
||||||
|
|
||||||
// return handleError($e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private function old_way()
|
|
||||||
{
|
|
||||||
if ($this->containers === null) {
|
if ($this->containers === null) {
|
||||||
['containers' => $this->containers,'containerReplicates' => $this->containerReplicates] = $this->server->getContainers();
|
['containers' => $this->containers, 'containerReplicates' => $this->containerReplicates] = $this->server->getContainers();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->containers)) {
|
if (is_null($this->containers)) {
|
||||||
@@ -425,6 +107,8 @@ class GetContainersStatus
|
|||||||
$statusFromDb = $preview->status;
|
$statusFromDb = $preview->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
if ($statusFromDb !== $containerStatus) {
|
||||||
$preview->update(['status' => $containerStatus]);
|
$preview->update(['status' => $containerStatus]);
|
||||||
|
} else {
|
||||||
|
$preview->update(['last_online_at' => now()]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//Notify user that this container should not be there.
|
//Notify user that this container should not be there.
|
||||||
@@ -436,6 +120,8 @@ class GetContainersStatus
|
|||||||
$statusFromDb = $application->status;
|
$statusFromDb = $application->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
if ($statusFromDb !== $containerStatus) {
|
||||||
$application->update(['status' => $containerStatus]);
|
$application->update(['status' => $containerStatus]);
|
||||||
|
} else {
|
||||||
|
$application->update(['last_online_at' => now()]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//Notify user that this container should not be there.
|
//Notify user that this container should not be there.
|
||||||
@@ -478,7 +164,10 @@ class GetContainersStatus
|
|||||||
$statusFromDb = $database->status;
|
$statusFromDb = $database->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
if ($statusFromDb !== $containerStatus) {
|
||||||
$database->update(['status' => $containerStatus]);
|
$database->update(['status' => $containerStatus]);
|
||||||
|
} else {
|
||||||
|
$database->update(['last_online_at' => now()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($isPublic) {
|
if ($isPublic) {
|
||||||
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
@@ -489,7 +178,7 @@ class GetContainersStatus
|
|||||||
})->first();
|
})->first();
|
||||||
if (! $foundTcpProxy) {
|
if (! $foundTcpProxy) {
|
||||||
StartDatabaseProxy::run($database);
|
StartDatabaseProxy::run($database);
|
||||||
$this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
|
// $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -520,6 +209,8 @@ class GetContainersStatus
|
|||||||
if ($statusFromDb !== $containerStatus) {
|
if ($statusFromDb !== $containerStatus) {
|
||||||
// ray('Updating status: ' . $containerStatus);
|
// ray('Updating status: ' . $containerStatus);
|
||||||
$service->update(['status' => $containerStatus]);
|
$service->update(['status' => $containerStatus]);
|
||||||
|
} else {
|
||||||
|
$service->update(['last_online_at' => now()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -650,32 +341,5 @@ class GetContainersStatus
|
|||||||
}
|
}
|
||||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
// $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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,12 +6,11 @@ use App\Models\User;
|
|||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Validation\Rules\Password;
|
||||||
use Laravel\Fortify\Contracts\CreatesNewUsers;
|
use Laravel\Fortify\Contracts\CreatesNewUsers;
|
||||||
|
|
||||||
class CreateNewUser implements CreatesNewUsers
|
class CreateNewUser implements CreatesNewUsers
|
||||||
{
|
{
|
||||||
use PasswordValidationRules;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate and create a newly registered user.
|
* Validate and create a newly registered user.
|
||||||
*
|
*
|
||||||
@@ -32,7 +31,7 @@ class CreateNewUser implements CreatesNewUsers
|
|||||||
'max:255',
|
'max:255',
|
||||||
Rule::unique(User::class),
|
Rule::unique(User::class),
|
||||||
],
|
],
|
||||||
'password' => $this->passwordRules(),
|
'password' => ['required', Password::defaults(), 'confirmed'],
|
||||||
])->validate();
|
])->validate();
|
||||||
|
|
||||||
if (User::count() == 0) {
|
if (User::count() == 0) {
|
||||||
@@ -41,7 +40,7 @@ class CreateNewUser implements CreatesNewUsers
|
|||||||
$user = User::create([
|
$user = User::create([
|
||||||
'id' => 0,
|
'id' => 0,
|
||||||
'name' => $input['name'],
|
'name' => $input['name'],
|
||||||
'email' => $input['email'],
|
'email' => strtolower($input['email']),
|
||||||
'password' => Hash::make($input['password']),
|
'password' => Hash::make($input['password']),
|
||||||
]);
|
]);
|
||||||
$team = $user->teams()->first();
|
$team = $user->teams()->first();
|
||||||
@@ -53,7 +52,7 @@ class CreateNewUser implements CreatesNewUsers
|
|||||||
} else {
|
} else {
|
||||||
$user = User::create([
|
$user = User::create([
|
||||||
'name' => $input['name'],
|
'name' => $input['name'],
|
||||||
'email' => $input['email'],
|
'email' => strtolower($input['email']),
|
||||||
'password' => Hash::make($input['password']),
|
'password' => Hash::make($input['password']),
|
||||||
]);
|
]);
|
||||||
$team = $user->teams()->first();
|
$team = $user->teams()->first();
|
||||||
|
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Fortify;
|
|
||||||
|
|
||||||
use Laravel\Fortify\Rules\Password;
|
|
||||||
|
|
||||||
trait PasswordValidationRules
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the validation rules used to validate passwords.
|
|
||||||
*
|
|
||||||
* @return array<int, \Illuminate\Contracts\Validation\Rule|array|string>
|
|
||||||
*/
|
|
||||||
protected function passwordRules(): array
|
|
||||||
{
|
|
||||||
return ['required', 'string', new Password, 'confirmed'];
|
|
||||||
}
|
|
||||||
}
|
|
@@ -5,12 +5,11 @@ namespace App\Actions\Fortify;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rules\Password;
|
||||||
use Laravel\Fortify\Contracts\ResetsUserPasswords;
|
use Laravel\Fortify\Contracts\ResetsUserPasswords;
|
||||||
|
|
||||||
class ResetUserPassword implements ResetsUserPasswords
|
class ResetUserPassword implements ResetsUserPasswords
|
||||||
{
|
{
|
||||||
use PasswordValidationRules;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate and reset the user's forgotten password.
|
* Validate and reset the user's forgotten password.
|
||||||
*
|
*
|
||||||
@@ -19,7 +18,7 @@ class ResetUserPassword implements ResetsUserPasswords
|
|||||||
public function reset(User $user, array $input): void
|
public function reset(User $user, array $input): void
|
||||||
{
|
{
|
||||||
Validator::make($input, [
|
Validator::make($input, [
|
||||||
'password' => $this->passwordRules(),
|
'password' => ['required', Password::defaults(), 'confirmed'],
|
||||||
])->validate();
|
])->validate();
|
||||||
|
|
||||||
$user->forceFill([
|
$user->forceFill([
|
||||||
|
@@ -5,12 +5,11 @@ namespace App\Actions\Fortify;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rules\Password;
|
||||||
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
|
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
|
||||||
|
|
||||||
class UpdateUserPassword implements UpdatesUserPasswords
|
class UpdateUserPassword implements UpdatesUserPasswords
|
||||||
{
|
{
|
||||||
use PasswordValidationRules;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate and update the user's password.
|
* Validate and update the user's password.
|
||||||
*
|
*
|
||||||
@@ -20,7 +19,7 @@ class UpdateUserPassword implements UpdatesUserPasswords
|
|||||||
{
|
{
|
||||||
Validator::make($input, [
|
Validator::make($input, [
|
||||||
'current_password' => ['required', 'string', 'current_password:web'],
|
'current_password' => ['required', 'string', 'current_password:web'],
|
||||||
'password' => $this->passwordRules(),
|
'password' => ['required', Password::defaults(), 'confirmed'],
|
||||||
], [
|
], [
|
||||||
'current_password.current_password' => __('The provided password does not match your current password.'),
|
'current_password.current_password' => __('The provided password does not match your current password.'),
|
||||||
])->validateWithBag('updatePassword');
|
])->validateWithBag('updatePassword');
|
||||||
|
@@ -25,8 +25,6 @@ class CheckResaleLicense
|
|||||||
// }
|
// }
|
||||||
$base_url = config('coolify.license_url');
|
$base_url = config('coolify.license_url');
|
||||||
$instance_id = config('app.id');
|
$instance_id = config('app.id');
|
||||||
|
|
||||||
ray("Checking license key against $base_url/lemon/validate");
|
|
||||||
$data = Http::withHeaders([
|
$data = Http::withHeaders([
|
||||||
'Accept' => 'application/json',
|
'Accept' => 'application/json',
|
||||||
])->get("$base_url/lemon/validate", [
|
])->get("$base_url/lemon/validate", [
|
||||||
@@ -34,7 +32,6 @@ class CheckResaleLicense
|
|||||||
'instance_id' => $instance_id,
|
'instance_id' => $instance_id,
|
||||||
])->json();
|
])->json();
|
||||||
if (data_get($data, 'valid') === true && data_get($data, 'license_key.status') === 'active') {
|
if (data_get($data, 'valid') === true && data_get($data, 'license_key.status') === 'active') {
|
||||||
ray('Valid & active license key');
|
|
||||||
$settings->update([
|
$settings->update([
|
||||||
'is_resale_license_active' => true,
|
'is_resale_license_active' => true,
|
||||||
]);
|
]);
|
||||||
@@ -48,7 +45,6 @@ class CheckResaleLicense
|
|||||||
'instance_id' => $instance_id,
|
'instance_id' => $instance_id,
|
||||||
])->json();
|
])->json();
|
||||||
if (data_get($data, 'activated') === true) {
|
if (data_get($data, 'activated') === true) {
|
||||||
ray('Activated license key');
|
|
||||||
$settings->update([
|
$settings->update([
|
||||||
'is_resale_license_active' => true,
|
'is_resale_license_active' => true,
|
||||||
]);
|
]);
|
||||||
@@ -60,7 +56,6 @@ class CheckResaleLicense
|
|||||||
}
|
}
|
||||||
throw new \Exception('Cannot activate license key.');
|
throw new \Exception('Cannot activate license key.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e);
|
|
||||||
$settings->update([
|
$settings->update([
|
||||||
'resale_license' => null,
|
'resale_license' => null,
|
||||||
'is_resale_license_active' => false,
|
'is_resale_license_active' => false,
|
||||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Proxy;
|
|||||||
|
|
||||||
use App\Enums\ProxyTypes;
|
use App\Enums\ProxyTypes;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ class CheckProxy
|
|||||||
$portsToCheck = [];
|
$portsToCheck = [];
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
ray($e->getMessage());
|
Log::error('Error checking proxy: '.$e->getMessage());
|
||||||
}
|
}
|
||||||
if (count($portsToCheck) === 0) {
|
if (count($portsToCheck) === 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@@ -13,67 +13,60 @@ class StartProxy
|
|||||||
|
|
||||||
public function handle(Server $server, bool $async = true, bool $force = false): string|Activity
|
public function handle(Server $server, bool $async = true, bool $force = false): string|Activity
|
||||||
{
|
{
|
||||||
try {
|
$proxyType = $server->proxyType();
|
||||||
$proxyType = $server->proxyType();
|
if ((is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop || $server->isBuildServer()) && $force === false) {
|
||||||
if ((is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop || $server->isBuildServer()) && $force === false) {
|
return 'OK';
|
||||||
return 'OK';
|
}
|
||||||
}
|
$commands = collect([]);
|
||||||
$commands = collect([]);
|
$proxy_path = $server->proxyPath();
|
||||||
$proxy_path = $server->proxyPath();
|
$configuration = CheckConfiguration::run($server);
|
||||||
$configuration = CheckConfiguration::run($server);
|
if (! $configuration) {
|
||||||
if (! $configuration) {
|
throw new \Exception('Configuration is not synced');
|
||||||
throw new \Exception('Configuration is not synced');
|
}
|
||||||
}
|
SaveConfiguration::run($server, $configuration);
|
||||||
SaveConfiguration::run($server, $configuration);
|
$docker_compose_yml_base64 = base64_encode($configuration);
|
||||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value();
|
||||||
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value();
|
$server->save();
|
||||||
|
if ($server->isSwarm()) {
|
||||||
|
$commands = $commands->merge([
|
||||||
|
"mkdir -p $proxy_path/dynamic",
|
||||||
|
"cd $proxy_path",
|
||||||
|
"echo 'Creating required Docker Compose file.'",
|
||||||
|
"echo 'Starting coolify-proxy.'",
|
||||||
|
'docker stack deploy -c docker-compose.yml coolify-proxy',
|
||||||
|
"echo 'Successfully started coolify-proxy.'",
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$caddfile = 'import /dynamic/*.caddy';
|
||||||
|
$commands = $commands->merge([
|
||||||
|
"mkdir -p $proxy_path/dynamic",
|
||||||
|
"cd $proxy_path",
|
||||||
|
"echo '$caddfile' > $proxy_path/dynamic/Caddyfile",
|
||||||
|
"echo 'Creating required Docker Compose file.'",
|
||||||
|
"echo 'Pulling docker image.'",
|
||||||
|
'docker compose pull',
|
||||||
|
'if docker ps -a --format "{{.Names}}" | grep -q "^coolify-proxy$"; then',
|
||||||
|
" echo 'Stopping and removing existing coolify-proxy.'",
|
||||||
|
' docker rm -f coolify-proxy || true',
|
||||||
|
" echo 'Successfully stopped and removed existing coolify-proxy.'",
|
||||||
|
'fi',
|
||||||
|
"echo 'Starting coolify-proxy.'",
|
||||||
|
'docker compose up -d --remove-orphans',
|
||||||
|
"echo 'Successfully started coolify-proxy.'",
|
||||||
|
]);
|
||||||
|
$commands = $commands->merge(connectProxyToNetworks($server));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($async) {
|
||||||
|
return remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server);
|
||||||
|
} else {
|
||||||
|
instant_remote_process($commands, $server);
|
||||||
|
$server->proxy->set('status', 'running');
|
||||||
|
$server->proxy->set('type', $proxyType);
|
||||||
$server->save();
|
$server->save();
|
||||||
if ($server->isSwarm()) {
|
ProxyStarted::dispatch($server);
|
||||||
$commands = $commands->merge([
|
|
||||||
"mkdir -p $proxy_path/dynamic",
|
|
||||||
"cd $proxy_path",
|
|
||||||
"echo 'Creating required Docker Compose file.'",
|
|
||||||
"echo 'Starting coolify-proxy.'",
|
|
||||||
'docker stack deploy -c docker-compose.yml coolify-proxy',
|
|
||||||
"echo 'Successfully started coolify-proxy.'",
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
$caddfile = 'import /dynamic/*.caddy';
|
|
||||||
$commands = $commands->merge([
|
|
||||||
"mkdir -p $proxy_path/dynamic",
|
|
||||||
"cd $proxy_path",
|
|
||||||
"echo '$caddfile' > $proxy_path/dynamic/Caddyfile",
|
|
||||||
"echo 'Creating required Docker Compose file.'",
|
|
||||||
"echo 'Pulling docker image.'",
|
|
||||||
'docker compose pull',
|
|
||||||
'if docker ps -a --format "{{.Names}}" | grep -q "^coolify-proxy$"; then',
|
|
||||||
" echo 'Stopping and removing existing coolify-proxy.'",
|
|
||||||
' docker rm -f coolify-proxy || true',
|
|
||||||
" echo 'Successfully stopped and removed existing coolify-proxy.'",
|
|
||||||
'fi',
|
|
||||||
"echo 'Starting coolify-proxy.'",
|
|
||||||
'docker compose up -d --remove-orphans',
|
|
||||||
"echo 'Successfully started coolify-proxy.'",
|
|
||||||
]);
|
|
||||||
$commands = $commands->merge(connectProxyToNetworks($server));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($async) {
|
return 'OK';
|
||||||
$activity = remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server);
|
|
||||||
|
|
||||||
return $activity;
|
|
||||||
} else {
|
|
||||||
instant_remote_process($commands, $server);
|
|
||||||
$server->proxy->set('status', 'running');
|
|
||||||
$server->proxy->set('type', $proxyType);
|
|
||||||
$server->save();
|
|
||||||
ProxyStarted::dispatch($server);
|
|
||||||
|
|
||||||
return 'OK';
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
ray($e);
|
|
||||||
throw $e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,6 @@ class ConfigureCloudflared
|
|||||||
]);
|
]);
|
||||||
instant_remote_process($commands, $server);
|
instant_remote_process($commands, $server);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e);
|
|
||||||
$server->settings->is_cloudflare_tunnel = false;
|
$server->settings->is_cloudflare_tunnel = false;
|
||||||
$server->settings->save();
|
$server->settings->save();
|
||||||
throw $e;
|
throw $e;
|
||||||
@@ -51,7 +50,6 @@ class ConfigureCloudflared
|
|||||||
'rm -fr /tmp/cloudflared',
|
'rm -fr /tmp/cloudflared',
|
||||||
]);
|
]);
|
||||||
instant_remote_process($commands, $server);
|
instant_remote_process($commands, $server);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
app/Actions/Server/DeleteServer.php
Normal file
17
app/Actions/Server/DeleteServer.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class DeleteServer
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(Server $server)
|
||||||
|
{
|
||||||
|
StopSentinel::run($server);
|
||||||
|
$server->forceDelete();
|
||||||
|
}
|
||||||
|
}
|
@@ -12,12 +12,11 @@ class InstallDocker
|
|||||||
|
|
||||||
public function handle(Server $server)
|
public function handle(Server $server)
|
||||||
{
|
{
|
||||||
|
$dockerVersion = config('constants.docker_install_version');
|
||||||
$supported_os_type = $server->validateOS();
|
$supported_os_type = $server->validateOS();
|
||||||
if (! $supported_os_type) {
|
if (! $supported_os_type) {
|
||||||
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
|
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
|
||||||
}
|
}
|
||||||
ray('Installing Docker on server: '.$server->name.' ('.$server->ip.')'.' with OS type: '.$supported_os_type);
|
|
||||||
$dockerVersion = '24.0';
|
|
||||||
$config = base64_encode('{
|
$config = base64_encode('{
|
||||||
"log-driver": "json-file",
|
"log-driver": "json-file",
|
||||||
"log-opts": {
|
"log-opts": {
|
||||||
|
41
app/Actions/Server/ResourcesCheck.php
Normal file
41
app/Actions/Server/ResourcesCheck.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\ServiceApplication;
|
||||||
|
use App\Models\ServiceDatabase;
|
||||||
|
use App\Models\StandaloneClickhouse;
|
||||||
|
use App\Models\StandaloneDragonfly;
|
||||||
|
use App\Models\StandaloneKeydb;
|
||||||
|
use App\Models\StandaloneMariadb;
|
||||||
|
use App\Models\StandaloneMongodb;
|
||||||
|
use App\Models\StandaloneMysql;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\StandaloneRedis;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class ResourcesCheck
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$seconds = 60;
|
||||||
|
try {
|
||||||
|
Application::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
ServiceApplication::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
ServiceDatabase::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
StandalonePostgresql::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
StandaloneRedis::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
StandaloneMongodb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
StandaloneMysql::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
StandaloneMariadb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
StandaloneKeydb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
StandaloneDragonfly::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
StandaloneClickhouse::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
app/Actions/Server/RestartContainer.php
Normal file
16
app/Actions/Server/RestartContainer.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class RestartContainer
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(Server $server, string $containerName)
|
||||||
|
{
|
||||||
|
$server->restartContainer($containerName);
|
||||||
|
}
|
||||||
|
}
|
@@ -12,8 +12,6 @@ class RunCommand
|
|||||||
|
|
||||||
public function handle(Server $server, $command)
|
public function handle(Server $server, $command)
|
||||||
{
|
{
|
||||||
$activity = remote_process(command: [$command], server: $server, ignore_errors: true, type: ActivityTypes::COMMAND->value);
|
return remote_process(command: [$command], server: $server, ignore_errors: true, type: ActivityTypes::COMMAND->value);
|
||||||
|
|
||||||
return $activity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
269
app/Actions/Server/ServerCheck.php
Normal file
269
app/Actions/Server/ServerCheck.php
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use App\Actions\Database\StartDatabaseProxy;
|
||||||
|
use App\Actions\Proxy\CheckProxy;
|
||||||
|
use App\Actions\Proxy\StartProxy;
|
||||||
|
use App\Jobs\CheckAndStartSentinelJob;
|
||||||
|
use App\Jobs\ServerStorageCheckJob;
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\ApplicationPreview;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\Service;
|
||||||
|
use App\Models\ServiceApplication;
|
||||||
|
use App\Models\ServiceDatabase;
|
||||||
|
use App\Notifications\Container\ContainerRestarted;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class ServerCheck
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public Server $server;
|
||||||
|
|
||||||
|
public bool $isSentinel = false;
|
||||||
|
|
||||||
|
public $containers;
|
||||||
|
|
||||||
|
public $databases;
|
||||||
|
|
||||||
|
public function handle(Server $server, $data = null)
|
||||||
|
{
|
||||||
|
$this->server = $server;
|
||||||
|
try {
|
||||||
|
if ($this->server->isFunctional() === false) {
|
||||||
|
return 'Server is not functional.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $this->server->isSwarmWorker() && ! $this->server->isBuildServer()) {
|
||||||
|
|
||||||
|
if (isset($data)) {
|
||||||
|
$data = collect($data);
|
||||||
|
|
||||||
|
$this->server->sentinelHeartbeat();
|
||||||
|
|
||||||
|
$this->containers = collect(data_get($data, 'containers'));
|
||||||
|
|
||||||
|
$filesystemUsageRoot = data_get($data, 'filesystem_usage_root.used_percentage');
|
||||||
|
ServerStorageCheckJob::dispatch($this->server, $filesystemUsageRoot);
|
||||||
|
|
||||||
|
$containerReplicates = null;
|
||||||
|
$this->isSentinel = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
['containers' => $this->containers, 'containerReplicates' => $containerReplicates] = $this->server->getContainers();
|
||||||
|
// ServerStorageCheckJob::dispatch($this->server);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($this->containers)) {
|
||||||
|
return 'No containers found.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($containerReplicates)) {
|
||||||
|
foreach ($containerReplicates as $containerReplica) {
|
||||||
|
$name = data_get($containerReplica, 'Name');
|
||||||
|
$this->containers = $this->containers->map(function ($container) use ($name, $containerReplica) {
|
||||||
|
if (data_get($container, 'Spec.Name') === $name) {
|
||||||
|
$replicas = data_get($containerReplica, 'Replicas');
|
||||||
|
$running = str($replicas)->explode('/')[0];
|
||||||
|
$total = str($replicas)->explode('/')[1];
|
||||||
|
if ($running === $total) {
|
||||||
|
data_set($container, 'State.Status', 'running');
|
||||||
|
data_set($container, 'State.Health.Status', 'healthy');
|
||||||
|
} else {
|
||||||
|
data_set($container, 'State.Status', 'starting');
|
||||||
|
data_set($container, 'State.Health.Status', 'unhealthy');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $container;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->checkContainers();
|
||||||
|
|
||||||
|
if ($this->server->isSentinelEnabled() && $this->isSentinel === false) {
|
||||||
|
CheckAndStartSentinelJob::dispatch($this->server);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->server->isLogDrainEnabled()) {
|
||||||
|
$this->checkLogDrainContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->server->proxySet() && ! $this->server->proxy->force_stop) {
|
||||||
|
$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) {
|
||||||
|
}
|
||||||
|
} 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) {
|
||||||
|
return handleError($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkLogDrainContainer()
|
||||||
|
{
|
||||||
|
$foundLogDrainContainer = $this->containers->filter(function ($value, $key) {
|
||||||
|
return data_get($value, 'Name') === '/coolify-log-drain';
|
||||||
|
})->first();
|
||||||
|
if ($foundLogDrainContainer) {
|
||||||
|
$status = data_get($foundLogDrainContainer, 'State.Status');
|
||||||
|
if ($status !== 'running') {
|
||||||
|
StartLogDrain::dispatch($this->server)->onQueue('high');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
StartLogDrain::dispatch($this->server)->onQueue('high');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkContainers()
|
||||||
|
{
|
||||||
|
foreach ($this->containers as $container) {
|
||||||
|
if ($this->isSentinel) {
|
||||||
|
$labels = Arr::undot(data_get($container, 'labels'));
|
||||||
|
} else {
|
||||||
|
if ($this->server->isSwarm()) {
|
||||||
|
$labels = Arr::undot(data_get($container, 'Spec.Labels'));
|
||||||
|
} else {
|
||||||
|
$labels = Arr::undot(data_get($container, 'Config.Labels'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$managed = data_get($labels, 'coolify.managed');
|
||||||
|
if (! $managed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$uuid = data_get($labels, 'coolify.name');
|
||||||
|
if (! $uuid) {
|
||||||
|
$uuid = data_get($labels, 'com.docker.compose.service');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isSentinel) {
|
||||||
|
$containerStatus = data_get($container, 'state');
|
||||||
|
$containerHealth = data_get($container, 'health_status');
|
||||||
|
} else {
|
||||||
|
$containerStatus = data_get($container, 'State.Status');
|
||||||
|
$containerHealth = data_get($container, 'State.Health.Status', 'unhealthy');
|
||||||
|
}
|
||||||
|
$containerStatus = "$containerStatus ($containerHealth)";
|
||||||
|
|
||||||
|
$applicationId = data_get($labels, 'coolify.applicationId');
|
||||||
|
$serviceId = data_get($labels, 'coolify.serviceId');
|
||||||
|
$databaseId = data_get($labels, 'coolify.databaseId');
|
||||||
|
$pullRequestId = data_get($labels, 'coolify.pullRequestId');
|
||||||
|
|
||||||
|
if ($applicationId) {
|
||||||
|
// Application
|
||||||
|
if ($pullRequestId != 0) {
|
||||||
|
if (str($applicationId)->contains('-')) {
|
||||||
|
$applicationId = str($applicationId)->before('-');
|
||||||
|
}
|
||||||
|
$preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
||||||
|
if ($preview) {
|
||||||
|
$preview->update(['status' => $containerStatus]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$application = Application::where('id', $applicationId)->first();
|
||||||
|
if ($application) {
|
||||||
|
$application->update([
|
||||||
|
'status' => $containerStatus,
|
||||||
|
'last_online_at' => now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (isset($serviceId)) {
|
||||||
|
// Service
|
||||||
|
$subType = data_get($labels, 'coolify.service.subType');
|
||||||
|
$subId = data_get($labels, 'coolify.service.subId');
|
||||||
|
$service = Service::where('id', $serviceId)->first();
|
||||||
|
if (! $service) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($subType === 'application') {
|
||||||
|
$service = ServiceApplication::where('id', $subId)->first();
|
||||||
|
} else {
|
||||||
|
$service = ServiceDatabase::where('id', $subId)->first();
|
||||||
|
}
|
||||||
|
if ($service) {
|
||||||
|
$service->update([
|
||||||
|
'status' => $containerStatus,
|
||||||
|
'last_online_at' => now(),
|
||||||
|
]);
|
||||||
|
if ($subType === 'database') {
|
||||||
|
$isPublic = data_get($service, 'is_public');
|
||||||
|
if ($isPublic) {
|
||||||
|
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||||
|
if ($this->isSentinel) {
|
||||||
|
return data_get($value, 'name') === $uuid.'-proxy';
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ($this->server->isSwarm()) {
|
||||||
|
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||||
|
} else {
|
||||||
|
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})->first();
|
||||||
|
if (! $foundTcpProxy) {
|
||||||
|
StartDatabaseProxy::run($service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Database
|
||||||
|
if (is_null($this->databases)) {
|
||||||
|
$this->databases = $this->server->databases();
|
||||||
|
}
|
||||||
|
$database = $this->databases->where('uuid', $uuid)->first();
|
||||||
|
if ($database) {
|
||||||
|
$database->update([
|
||||||
|
'status' => $containerStatus,
|
||||||
|
'last_online_at' => now(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$isPublic = data_get($database, 'is_public');
|
||||||
|
if ($isPublic) {
|
||||||
|
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||||
|
if ($this->isSentinel) {
|
||||||
|
return data_get($value, 'name') === $uuid.'-proxy';
|
||||||
|
} else {
|
||||||
|
if ($this->server->isSwarm()) {
|
||||||
|
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})->first();
|
||||||
|
if (! $foundTcpProxy) {
|
||||||
|
StartDatabaseProxy::run($database);
|
||||||
|
// $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -5,7 +5,7 @@ namespace App\Actions\Server;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class InstallLogDrain
|
class StartLogDrain
|
||||||
{
|
{
|
||||||
use AsAction;
|
use AsAction;
|
||||||
|
|
||||||
@@ -13,12 +13,16 @@ class InstallLogDrain
|
|||||||
{
|
{
|
||||||
if ($server->settings->is_logdrain_newrelic_enabled) {
|
if ($server->settings->is_logdrain_newrelic_enabled) {
|
||||||
$type = 'newrelic';
|
$type = 'newrelic';
|
||||||
|
StopLogDrain::run($server);
|
||||||
} elseif ($server->settings->is_logdrain_highlight_enabled) {
|
} elseif ($server->settings->is_logdrain_highlight_enabled) {
|
||||||
$type = 'highlight';
|
$type = 'highlight';
|
||||||
|
StopLogDrain::run($server);
|
||||||
} elseif ($server->settings->is_logdrain_axiom_enabled) {
|
} elseif ($server->settings->is_logdrain_axiom_enabled) {
|
||||||
$type = 'axiom';
|
$type = 'axiom';
|
||||||
|
StopLogDrain::run($server);
|
||||||
} elseif ($server->settings->is_logdrain_custom_enabled) {
|
} elseif ($server->settings->is_logdrain_custom_enabled) {
|
||||||
$type = 'custom';
|
$type = 'custom';
|
||||||
|
StopLogDrain::run($server);
|
||||||
} else {
|
} else {
|
||||||
$type = 'none';
|
$type = 'none';
|
||||||
}
|
}
|
||||||
@@ -151,6 +155,8 @@ services:
|
|||||||
- ./parsers.conf:/parsers.conf
|
- ./parsers.conf:/parsers.conf
|
||||||
ports:
|
ports:
|
||||||
- 127.0.0.1:24224:24224
|
- 127.0.0.1:24224:24224
|
||||||
|
labels:
|
||||||
|
- coolify.managed=true
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
');
|
');
|
||||||
$readme = base64_encode('# New Relic Log Drain
|
$readme = base64_encode('# New Relic Log Drain
|
||||||
@@ -202,10 +208,8 @@ Files:
|
|||||||
throw new \Exception('Unknown log drain type.');
|
throw new \Exception('Unknown log drain type.');
|
||||||
}
|
}
|
||||||
$restart_command = [
|
$restart_command = [
|
||||||
"echo 'Stopping old Fluent Bit'",
|
|
||||||
"cd $config_path && docker compose down --remove-orphans || true",
|
|
||||||
"echo 'Starting Fluent Bit'",
|
"echo 'Starting Fluent Bit'",
|
||||||
"cd $config_path && docker compose up -d --remove-orphans",
|
"cd $config_path && docker compose up -d",
|
||||||
];
|
];
|
||||||
$command = array_merge($command, $add_envs_command, $restart_command);
|
$command = array_merge($command, $add_envs_command, $restart_command);
|
||||||
|
|
@@ -9,18 +9,57 @@ class StartSentinel
|
|||||||
{
|
{
|
||||||
use AsAction;
|
use AsAction;
|
||||||
|
|
||||||
public function handle(Server $server, $version = 'latest', bool $restart = false)
|
public function handle(Server $server, bool $restart = false, ?string $latestVersion = null)
|
||||||
{
|
{
|
||||||
|
if ($server->isSwarm() || $server->isBuildServer()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ($restart) {
|
if ($restart) {
|
||||||
StopSentinel::run($server);
|
StopSentinel::run($server);
|
||||||
}
|
}
|
||||||
$metrics_history = $server->settings->metrics_history_days;
|
$version = $latestVersion ?? get_latest_sentinel_version();
|
||||||
$refresh_rate = $server->settings->metrics_refresh_rate_seconds;
|
$metricsHistory = data_get($server, 'settings.sentinel_metrics_history_days');
|
||||||
$token = $server->settings->metrics_token;
|
$refreshRate = data_get($server, 'settings.sentinel_metrics_refresh_rate_seconds');
|
||||||
|
$pushInterval = data_get($server, 'settings.sentinel_push_interval_seconds');
|
||||||
|
$token = data_get($server, 'settings.sentinel_token');
|
||||||
|
$endpoint = data_get($server, 'settings.sentinel_custom_url');
|
||||||
|
$debug = data_get($server, 'settings.is_sentinel_debug_enabled');
|
||||||
|
$mountDir = '/data/coolify/sentinel';
|
||||||
|
$image = "ghcr.io/coollabsio/sentinel:$version";
|
||||||
|
if (! $endpoint) {
|
||||||
|
throw new \Exception('You should set FQDN in Instance Settings.');
|
||||||
|
}
|
||||||
|
$environments = [
|
||||||
|
'TOKEN' => $token,
|
||||||
|
'DEBUG' => $debug ? 'true' : 'false',
|
||||||
|
'PUSH_ENDPOINT' => $endpoint,
|
||||||
|
'PUSH_INTERVAL_SECONDS' => $pushInterval,
|
||||||
|
'COLLECTOR_ENABLED' => $server->isMetricsEnabled() ? 'true' : 'false',
|
||||||
|
'COLLECTOR_REFRESH_RATE_SECONDS' => $refreshRate,
|
||||||
|
'COLLECTOR_RETENTION_PERIOD_DAYS' => $metricsHistory,
|
||||||
|
];
|
||||||
|
$labels = [
|
||||||
|
'coolify.managed' => 'true',
|
||||||
|
];
|
||||||
|
if (isDev()) {
|
||||||
|
// data_set($environments, 'DEBUG', 'true');
|
||||||
|
// $image = 'sentinel';
|
||||||
|
$mountDir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/sentinel';
|
||||||
|
}
|
||||||
|
$dockerEnvironments = '-e "'.implode('" -e "', array_map(fn ($key, $value) => "$key=$value", array_keys($environments), $environments)).'"';
|
||||||
|
$dockerLabels = implode(' ', array_map(fn ($key, $value) => "$key=$value", array_keys($labels), $labels));
|
||||||
|
$dockerCommand = "docker run -d $dockerEnvironments --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v $mountDir:/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 --label $dockerLabels $image";
|
||||||
|
|
||||||
instant_remote_process([
|
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",
|
'docker rm -f coolify-sentinel || true',
|
||||||
'chown -R 9999:root /data/coolify/metrics /data/coolify/logs',
|
"mkdir -p $mountDir",
|
||||||
'chmod -R 700 /data/coolify/metrics /data/coolify/logs',
|
$dockerCommand,
|
||||||
], $server, true);
|
"chown -R 9999:root $mountDir",
|
||||||
|
"chmod -R 700 $mountDir",
|
||||||
|
], $server);
|
||||||
|
|
||||||
|
$server->settings->is_sentinel_enabled = true;
|
||||||
|
$server->settings->save();
|
||||||
|
$server->sentinelHeartbeat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@ class StopLogDrain
|
|||||||
public function handle(Server $server)
|
public function handle(Server $server)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return instant_remote_process(['docker rm -f coolify-log-drain || true'], $server);
|
return instant_remote_process(['docker rm -f coolify-log-drain'], $server, false);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
|
@@ -12,5 +12,6 @@ class StopSentinel
|
|||||||
public function handle(Server $server)
|
public function handle(Server $server)
|
||||||
{
|
{
|
||||||
instant_remote_process(['docker rm -f coolify-sentinel'], $server, false);
|
instant_remote_process(['docker rm -f coolify-sentinel'], $server, false);
|
||||||
|
$server->sentinelHeartbeat(isReset: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,32 +18,28 @@ class UpdateCoolify
|
|||||||
|
|
||||||
public function handle($manual_update = false)
|
public function handle($manual_update = false)
|
||||||
{
|
{
|
||||||
try {
|
$settings = instanceSettings();
|
||||||
$settings = instanceSettings();
|
$this->server = Server::find(0);
|
||||||
$this->server = Server::find(0);
|
if (! $this->server) {
|
||||||
if (! $this->server) {
|
return;
|
||||||
|
}
|
||||||
|
CleanupDocker::dispatch($this->server)->onQueue('high');
|
||||||
|
$this->latestVersion = get_latest_version_of_coolify();
|
||||||
|
$this->currentVersion = config('version');
|
||||||
|
if (! $manual_update) {
|
||||||
|
if (! $settings->is_auto_update_enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CleanupDocker::dispatch($this->server)->onQueue('high');
|
if ($this->latestVersion === $this->currentVersion) {
|
||||||
$this->latestVersion = get_latest_version_of_coolify();
|
return;
|
||||||
$this->currentVersion = config('version');
|
}
|
||||||
if (! $manual_update) {
|
if (version_compare($this->latestVersion, $this->currentVersion, '<')) {
|
||||||
if (! $settings->is_auto_update_enabled) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($this->latestVersion === $this->currentVersion) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (version_compare($this->latestVersion, $this->currentVersion, '<')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$this->update();
|
|
||||||
$settings->new_version_available = false;
|
|
||||||
$settings->save();
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
throw $e;
|
|
||||||
}
|
}
|
||||||
|
$this->update();
|
||||||
|
$settings->new_version_available = false;
|
||||||
|
$settings->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function update()
|
private function update()
|
||||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Service;
|
|||||||
|
|
||||||
use App\Actions\Server\CleanupDocker;
|
use App\Actions\Server\CleanupDocker;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class DeleteService
|
class DeleteService
|
||||||
@@ -39,8 +40,8 @@ class DeleteService
|
|||||||
if (! empty($commands)) {
|
if (! empty($commands)) {
|
||||||
foreach ($commands as $command) {
|
foreach ($commands as $command) {
|
||||||
$result = instant_remote_process([$command], $server, false);
|
$result = instant_remote_process([$command], $server, false);
|
||||||
if ($result !== 0) {
|
if ($result !== null && $result !== 0) {
|
||||||
ray("Failed to execute: $command");
|
Log::error('Error deleting volumes: '.$result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,6 @@ class StartService
|
|||||||
|
|
||||||
public function handle(Service $service)
|
public function handle(Service $service)
|
||||||
{
|
{
|
||||||
ray('Starting service: '.$service->name);
|
|
||||||
$service->saveComposeConfigs();
|
$service->saveComposeConfigs();
|
||||||
$commands[] = 'cd '.$service->workdir();
|
$commands[] = 'cd '.$service->workdir();
|
||||||
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
|
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
|
||||||
@@ -34,8 +33,7 @@ class StartService
|
|||||||
$commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} >/dev/null 2>&1 || true";
|
$commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} >/dev/null 2>&1 || true";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$activity = remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
|
|
||||||
|
|
||||||
return $activity;
|
return remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,8 +28,6 @@ class StopService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@ use Illuminate\Support\Facades\DB;
|
|||||||
|
|
||||||
class CleanupDatabase extends Command
|
class CleanupDatabase extends Command
|
||||||
{
|
{
|
||||||
protected $signature = 'cleanup:database {--yes}';
|
protected $signature = 'cleanup:database {--yes} {--keep-days=}';
|
||||||
|
|
||||||
protected $description = 'Cleanup database';
|
protected $description = 'Cleanup database';
|
||||||
|
|
||||||
@@ -20,9 +20,9 @@ class CleanupDatabase extends Command
|
|||||||
}
|
}
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
// Later on we can increase this to 180 days or dynamically set
|
// Later on we can increase this to 180 days or dynamically set
|
||||||
$keep_days = 60;
|
$keep_days = $this->option('keep-days') ?? 60;
|
||||||
} else {
|
} else {
|
||||||
$keep_days = 60;
|
$keep_days = $this->option('keep-days') ?? 60;
|
||||||
}
|
}
|
||||||
echo "Keep days: $keep_days\n";
|
echo "Keep days: $keep_days\n";
|
||||||
// Cleanup failed jobs table
|
// Cleanup failed jobs table
|
||||||
@@ -64,6 +64,5 @@ class CleanupDatabase extends Command
|
|||||||
if ($this->option('yes')) {
|
if ($this->option('yes')) {
|
||||||
$webhooks->delete();
|
$webhooks->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,5 @@ class CleanupRedis extends Command
|
|||||||
collect($queueOverlaps)->each(function ($key) {
|
collect($queueOverlaps)->each(function ($key) {
|
||||||
Redis::connection()->del($key);
|
Redis::connection()->del($key);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,14 +30,12 @@ class CleanupStuckedResources extends Command
|
|||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
ray('Running cleanup stucked resources.');
|
|
||||||
echo "Running cleanup stucked resources.\n";
|
echo "Running cleanup stucked resources.\n";
|
||||||
$this->cleanup_stucked_resources();
|
$this->cleanup_stucked_resources();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function cleanup_stucked_resources()
|
private function cleanup_stucked_resources()
|
||||||
{
|
{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$servers = Server::all()->filter(function ($server) {
|
$servers = Server::all()->filter(function ($server) {
|
||||||
return $server->isFunctional();
|
return $server->isFunctional();
|
||||||
|
@@ -19,7 +19,6 @@ class CloudCleanupSubscriptions extends Command
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ray()->clearAll();
|
|
||||||
$this->info('Cleaning up subcriptions teams');
|
$this->info('Cleaning up subcriptions teams');
|
||||||
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
|
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
|
||||||
|
|
||||||
@@ -74,7 +73,6 @@ class CloudCleanupSubscriptions extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->error($e->getMessage());
|
$this->error($e->getMessage());
|
||||||
|
|
||||||
@@ -96,6 +94,5 @@ class CloudCleanupSubscriptions extends Command
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,6 @@ class Dev extends Command
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateOpenApi()
|
public function generateOpenApi()
|
||||||
|
@@ -15,7 +15,6 @@ use App\Notifications\Application\DeploymentSuccess;
|
|||||||
use App\Notifications\Application\StatusChanged;
|
use App\Notifications\Application\StatusChanged;
|
||||||
use App\Notifications\Database\BackupFailed;
|
use App\Notifications\Database\BackupFailed;
|
||||||
use App\Notifications\Database\BackupSuccess;
|
use App\Notifications\Database\BackupSuccess;
|
||||||
use App\Notifications\Database\DailyBackup;
|
|
||||||
use App\Notifications\Test;
|
use App\Notifications\Test;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
@@ -121,28 +120,10 @@ class Emails extends Command
|
|||||||
$this->mail = (new Test)->toMail();
|
$this->mail = (new Test)->toMail();
|
||||||
$this->sendEmail();
|
$this->sendEmail();
|
||||||
break;
|
break;
|
||||||
case 'database-backup-statuses-daily':
|
|
||||||
$scheduled_backups = ScheduledDatabaseBackup::all();
|
|
||||||
$databases = collect();
|
|
||||||
foreach ($scheduled_backups as $scheduled_backup) {
|
|
||||||
$last_days_backups = $scheduled_backup->get_last_days_backup_status();
|
|
||||||
if ($last_days_backups->isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$failed = $last_days_backups->where('status', 'failed');
|
|
||||||
$database = $scheduled_backup->database;
|
|
||||||
$databases->put($database->name, [
|
|
||||||
'failed_count' => $failed->count(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
$this->mail = (new DailyBackup($databases))->toMail();
|
|
||||||
$this->sendEmail();
|
|
||||||
break;
|
|
||||||
case 'application-deployment-success-daily':
|
case 'application-deployment-success-daily':
|
||||||
$applications = Application::all();
|
$applications = Application::all();
|
||||||
foreach ($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
$deployments = $application->get_last_days_deployments();
|
$deployments = $application->get_last_days_deployments();
|
||||||
ray($deployments);
|
|
||||||
if ($deployments->isEmpty()) {
|
if ($deployments->isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,7 @@ use App\Models\Environment;
|
|||||||
use App\Models\ScheduledDatabaseBackup;
|
use App\Models\ScheduledDatabaseBackup;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\User;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
@@ -32,16 +33,16 @@ class Init extends Command
|
|||||||
|
|
||||||
$this->servers = Server::all();
|
$this->servers = Server::all();
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$this->send_alive_signal();
|
$this->send_alive_signal();
|
||||||
get_public_ips();
|
get_public_ips();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backward compatibility
|
// Backward compatibility
|
||||||
$this->disable_metrics();
|
// $this->disable_metrics();
|
||||||
$this->replace_slash_in_environment_name();
|
$this->replace_slash_in_environment_name();
|
||||||
$this->restore_coolify_db_backup();
|
$this->restore_coolify_db_backup();
|
||||||
|
$this->update_user_emails();
|
||||||
//
|
//
|
||||||
$this->update_traefik_labels();
|
$this->update_traefik_labels();
|
||||||
if (! isCloud() || $this->option('force-cloud')) {
|
if (! isCloud() || $this->option('force-cloud')) {
|
||||||
@@ -79,17 +80,26 @@ class Init extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function disable_metrics()
|
// private function disable_metrics()
|
||||||
|
// {
|
||||||
|
// if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
|
||||||
|
// foreach ($this->servers as $server) {
|
||||||
|
// if ($server->settings->is_metrics_enabled === true) {
|
||||||
|
// $server->settings->update(['is_metrics_enabled' => false]);
|
||||||
|
// }
|
||||||
|
// if ($server->isFunctional()) {
|
||||||
|
// StopSentinel::dispatch($server)->onQueue('high');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private function update_user_emails()
|
||||||
{
|
{
|
||||||
if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
|
try {
|
||||||
foreach ($this->servers as $server) {
|
User::whereRaw('email ~ \'[A-Z]\'')->get()->each(fn (User $user) => $user->update(['email' => strtolower($user->email)]));
|
||||||
if ($server->settings->is_metrics_enabled === true) {
|
} catch (\Throwable $e) {
|
||||||
$server->settings->update(['is_metrics_enabled' => false]);
|
echo "Error in updating user emails: {$e->getMessage()}\n";
|
||||||
}
|
|
||||||
if ($server->isFunctional()) {
|
|
||||||
StopSentinel::dispatch($server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +130,6 @@ class Init extends Command
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n";
|
echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +189,7 @@ class Init extends Command
|
|||||||
'save_s3' => false,
|
'save_s3' => false,
|
||||||
'frequency' => '0 0 * * *',
|
'frequency' => '0 0 * * *',
|
||||||
'database_id' => $database->id,
|
'database_id' => $database->id,
|
||||||
'database_type' => 'App\Models\StandalonePostgresql',
|
'database_type' => \App\Models\StandalonePostgresql::class,
|
||||||
'team_id' => 0,
|
'team_id' => 0,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -219,7 +228,6 @@ class Init extends Command
|
|||||||
}
|
}
|
||||||
$queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
|
$queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
|
||||||
foreach ($queued_inprogress_deployments as $deployment) {
|
foreach ($queued_inprogress_deployments as $deployment) {
|
||||||
ray($deployment->id, $deployment->status);
|
|
||||||
echo "Cleaning up deployment: {$deployment->id}\n";
|
echo "Cleaning up deployment: {$deployment->id}\n";
|
||||||
$deployment->status = ApplicationDeploymentStatus::FAILED->value;
|
$deployment->status = ApplicationDeploymentStatus::FAILED->value;
|
||||||
$deployment->save();
|
$deployment->save();
|
||||||
|
@@ -36,8 +36,6 @@ class NotifyDemo extends Command
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ray($channel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function showHelp()
|
private function showHelp()
|
||||||
|
@@ -21,6 +21,5 @@ class OpenApi extends Command
|
|||||||
$error = preg_replace('/^\h*\v+/m', '', $error);
|
$error = preg_replace('/^\h*\v+/m', '', $error);
|
||||||
echo $error;
|
echo $error;
|
||||||
echo $process->output();
|
echo $process->output();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -96,7 +96,7 @@ class ServicesDelete extends Command
|
|||||||
if (! $confirmed) {
|
if (! $confirmed) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DeleteResourceJob::dispatch($toDelete);
|
DeleteResourceJob::dispatch($toDelete)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ class ServicesDelete extends Command
|
|||||||
if (! $confirmed) {
|
if (! $confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DeleteResourceJob::dispatch($toDelete);
|
DeleteResourceJob::dispatch($toDelete)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ class ServicesDelete extends Command
|
|||||||
if (! $confirmed) {
|
if (! $confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DeleteResourceJob::dispatch($toDelete);
|
DeleteResourceJob::dispatch($toDelete)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,128 +3,82 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
class ServicesGenerate extends Command
|
class ServicesGenerate extends Command
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
*/
|
||||||
protected $signature = 'services:generate';
|
protected $signature = 'services:generate';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
*/
|
||||||
protected $description = 'Generate service-templates.yaml based on /templates/compose directory';
|
protected $description = 'Generate service-templates.yaml based on /templates/compose directory';
|
||||||
|
|
||||||
/**
|
public function handle(): int
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
$files = array_diff(scandir(base_path('templates/compose')), ['.', '..']);
|
$serviceTemplatesJson = collect(glob(base_path('templates/compose/*.yaml')))
|
||||||
$files = array_filter($files, function ($file) {
|
->mapWithKeys(function ($file): array {
|
||||||
return strpos($file, '.yaml') !== false;
|
$file = basename($file);
|
||||||
});
|
$parsed = $this->processFile($file);
|
||||||
$serviceTemplatesJson = [];
|
|
||||||
foreach ($files as $file) {
|
return $parsed === false ? [] : [
|
||||||
$parsed = $this->process_file($file);
|
Arr::pull($parsed, 'name') => $parsed,
|
||||||
if ($parsed) {
|
];
|
||||||
$name = data_get($parsed, 'name');
|
})->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||||
$parsed = data_forget($parsed, 'name');
|
|
||||||
$serviceTemplatesJson[$name] = $parsed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$serviceTemplatesJson = json_encode($serviceTemplatesJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
|
||||||
file_put_contents(base_path('templates/service-templates.json'), $serviceTemplatesJson.PHP_EOL);
|
file_put_contents(base_path('templates/service-templates.json'), $serviceTemplatesJson.PHP_EOL);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function process_file($file)
|
private function processFile(string $file): false|array
|
||||||
{
|
{
|
||||||
$serviceName = str($file)->before('.yaml')->value();
|
|
||||||
$content = file_get_contents(base_path("templates/compose/$file"));
|
$content = file_get_contents(base_path("templates/compose/$file"));
|
||||||
// $this->info($content);
|
|
||||||
$ignore = collect(preg_grep('/^# ignore:/', explode("\n", $content)))->values();
|
$data = collect(explode(PHP_EOL, $content))->mapWithKeys(function ($line): array {
|
||||||
if ($ignore->count() > 0) {
|
preg_match('/^#(?<key>.*):(?<value>.*)$/U', $line, $m);
|
||||||
$ignore = (bool) str($ignore[0])->after('# ignore:')->trim()->value();
|
|
||||||
} else {
|
return $m ? [trim($m['key']) => trim($m['value'])] : [];
|
||||||
$ignore = false;
|
});
|
||||||
}
|
|
||||||
if ($ignore) {
|
if (str($data->get('ignore'))->toBoolean()) {
|
||||||
$this->info("Ignoring $file");
|
$this->info("Ignoring $file");
|
||||||
|
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->info("Processing $file");
|
$this->info("Processing $file");
|
||||||
$documentation = collect(preg_grep('/^# documentation:/', explode("\n", $content)))->values();
|
|
||||||
if ($documentation->count() > 0) {
|
|
||||||
$documentation = str($documentation[0])->after('# documentation:')->trim()->value();
|
|
||||||
$documentation = str($documentation)->append('?utm_source=coolify.io');
|
|
||||||
} else {
|
|
||||||
$documentation = 'https://coolify.io/docs';
|
|
||||||
}
|
|
||||||
|
|
||||||
$slogan = collect(preg_grep('/^# slogan:/', explode("\n", $content)))->values();
|
$documentation = $data->get('documentation');
|
||||||
if ($slogan->count() > 0) {
|
$documentation = $documentation ? $documentation.'?utm_source=coolify.io' : 'https://coolify.io/docs';
|
||||||
$slogan = str($slogan[0])->after('# slogan:')->trim()->value();
|
|
||||||
} else {
|
|
||||||
$slogan = str($file)->headline()->value();
|
|
||||||
}
|
|
||||||
$logo = collect(preg_grep('/^# logo:/', explode("\n", $content)))->values();
|
|
||||||
if ($logo->count() > 0) {
|
|
||||||
$logo = str($logo[0])->after('# logo:')->trim()->value();
|
|
||||||
} else {
|
|
||||||
$logo = 'svgs/coolify.png';
|
|
||||||
}
|
|
||||||
$minversion = collect(preg_grep('/^# minversion:/', explode("\n", $content)))->values();
|
|
||||||
if ($minversion->count() > 0) {
|
|
||||||
$minversion = str($minversion[0])->after('# minversion:')->trim()->value();
|
|
||||||
} else {
|
|
||||||
$minversion = '0.0.0';
|
|
||||||
}
|
|
||||||
$env_file = collect(preg_grep('/^# env_file:/', explode("\n", $content)))->values();
|
|
||||||
if ($env_file->count() > 0) {
|
|
||||||
$env_file = str($env_file[0])->after('# env_file:')->trim()->value();
|
|
||||||
} else {
|
|
||||||
$env_file = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tags = collect(preg_grep('/^# tags:/', explode("\n", $content)))->values();
|
|
||||||
if ($tags->count() > 0) {
|
|
||||||
$tags = str($tags[0])->after('# tags:')->trim()->explode(',')->map(function ($tag) {
|
|
||||||
return str($tag)->trim()->lower()->value();
|
|
||||||
})->values();
|
|
||||||
} else {
|
|
||||||
$tags = null;
|
|
||||||
}
|
|
||||||
$port = collect(preg_grep('/^# port:/', explode("\n", $content)))->values();
|
|
||||||
if ($port->count() > 0) {
|
|
||||||
$port = str($port[0])->after('# port:')->trim()->value();
|
|
||||||
} else {
|
|
||||||
$port = null;
|
|
||||||
}
|
|
||||||
$json = Yaml::parse($content);
|
$json = Yaml::parse($content);
|
||||||
$yaml = base64_encode(Yaml::dump($json, 10, 2));
|
$compose = base64_encode(Yaml::dump($json, 10, 2));
|
||||||
|
|
||||||
|
$tags = str($data->get('tags'))->lower()->explode(',')->map(fn ($tag) => trim($tag))->filter();
|
||||||
|
$tags = $tags->isEmpty() ? null : $tags->all();
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'name' => $serviceName,
|
'name' => pathinfo($file, PATHINFO_FILENAME),
|
||||||
'documentation' => $documentation,
|
'documentation' => $documentation,
|
||||||
'slogan' => $slogan,
|
'slogan' => $data->get('slogan', str($file)->headline()),
|
||||||
'compose' => $yaml,
|
'compose' => $compose,
|
||||||
'tags' => $tags,
|
'tags' => $tags,
|
||||||
'logo' => $logo,
|
'logo' => $data->get('logo', 'svgs/coolify.png'),
|
||||||
'minversion' => $minversion,
|
'minversion' => $data->get('minversion', '0.0.0'),
|
||||||
];
|
];
|
||||||
if ($port) {
|
|
||||||
|
if ($port = $data->get('port')) {
|
||||||
$payload['port'] = $port;
|
$payload['port'] = $port;
|
||||||
}
|
}
|
||||||
if ($env_file) {
|
|
||||||
$env_file_content = file_get_contents(base_path("templates/compose/$env_file"));
|
if ($envFile = $data->get('env_file')) {
|
||||||
$env_file_base64 = base64_encode($env_file_content);
|
$envFileContent = file_get_contents(base_path("templates/compose/$envFile"));
|
||||||
$payload['envs'] = $env_file_base64;
|
$payload['envs'] = base64_encode($envFileContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $payload;
|
return $payload;
|
||||||
|
58
app/Console/Commands/Weird.php
Normal file
58
app/Console/Commands/Weird.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Actions\Server\ServerCheck;
|
||||||
|
use App\Enums\ProxyStatus;
|
||||||
|
use App\Enums\ProxyTypes;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Str;
|
||||||
|
|
||||||
|
class Weird extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'weird {--number=1} {--run}';
|
||||||
|
|
||||||
|
protected $description = 'Weird stuff';
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (! isDev()) {
|
||||||
|
$this->error('This command can only be run in development mode');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$run = $this->option('run');
|
||||||
|
if ($run) {
|
||||||
|
$servers = Server::all();
|
||||||
|
foreach ($servers as $server) {
|
||||||
|
ServerCheck::dispatch($server);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$number = $this->option('number');
|
||||||
|
for ($i = 0; $i < $number; $i++) {
|
||||||
|
$uuid = Str::uuid();
|
||||||
|
$server = Server::create([
|
||||||
|
'name' => 'localhost-'.$uuid,
|
||||||
|
'description' => 'This is a test docker container in development mode',
|
||||||
|
'ip' => 'coolify-testing-host',
|
||||||
|
'team_id' => 0,
|
||||||
|
'private_key_id' => 1,
|
||||||
|
'proxy' => [
|
||||||
|
'type' => ProxyTypes::NONE->value,
|
||||||
|
'status' => ProxyStatus::EXITED->value,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$server->settings->update([
|
||||||
|
'is_usable' => true,
|
||||||
|
'is_reachable' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -2,33 +2,45 @@
|
|||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
|
use App\Jobs\CheckAndStartSentinelJob;
|
||||||
use App\Jobs\CheckForUpdatesJob;
|
use App\Jobs\CheckForUpdatesJob;
|
||||||
|
use App\Jobs\CheckHelperImageJob;
|
||||||
use App\Jobs\CleanupInstanceStuffsJob;
|
use App\Jobs\CleanupInstanceStuffsJob;
|
||||||
use App\Jobs\CleanupStaleMultiplexedConnections;
|
use App\Jobs\CleanupStaleMultiplexedConnections;
|
||||||
use App\Jobs\DatabaseBackupJob;
|
use App\Jobs\DatabaseBackupJob;
|
||||||
use App\Jobs\DockerCleanupJob;
|
use App\Jobs\DockerCleanupJob;
|
||||||
use App\Jobs\PullHelperImageJob;
|
|
||||||
use App\Jobs\PullSentinelImageJob;
|
|
||||||
use App\Jobs\PullTemplatesFromCDN;
|
use App\Jobs\PullTemplatesFromCDN;
|
||||||
use App\Jobs\ScheduledTaskJob;
|
use App\Jobs\ScheduledTaskJob;
|
||||||
use App\Jobs\ServerCheckJob;
|
use App\Jobs\ServerCheckJob;
|
||||||
|
use App\Jobs\ServerCleanupMux;
|
||||||
use App\Jobs\ServerStorageCheckJob;
|
use App\Jobs\ServerStorageCheckJob;
|
||||||
use App\Jobs\UpdateCoolifyJob;
|
use App\Jobs\UpdateCoolifyJob;
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\ScheduledDatabaseBackup;
|
use App\Models\ScheduledDatabaseBackup;
|
||||||
use App\Models\ScheduledTask;
|
use App\Models\ScheduledTask;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
class Kernel extends ConsoleKernel
|
class Kernel extends ConsoleKernel
|
||||||
{
|
{
|
||||||
private $all_servers;
|
private $allServers;
|
||||||
|
|
||||||
|
private InstanceSettings $settings;
|
||||||
|
|
||||||
|
private string $updateCheckFrequency;
|
||||||
|
|
||||||
|
private string $instanceTimezone;
|
||||||
|
|
||||||
protected function schedule(Schedule $schedule): void
|
protected function schedule(Schedule $schedule): void
|
||||||
{
|
{
|
||||||
$this->all_servers = Server::all();
|
$this->allServers = Server::where('ip', '!=', '1.2.3.4');
|
||||||
$settings = instanceSettings();
|
|
||||||
|
$this->settings = instanceSettings();
|
||||||
|
$this->updateCheckFrequency = $this->settings->update_check_frequency ?: '0 * * * *';
|
||||||
|
$this->instanceTimezone = $this->settings->instance_timezone ?: config('app.timezone');
|
||||||
|
|
||||||
$schedule->job(new CleanupStaleMultiplexedConnections)->hourly();
|
$schedule->job(new CleanupStaleMultiplexedConnections)->hourly();
|
||||||
|
|
||||||
@@ -36,108 +48,118 @@ class Kernel extends ConsoleKernel
|
|||||||
// Instance Jobs
|
// Instance Jobs
|
||||||
$schedule->command('horizon:snapshot')->everyMinute();
|
$schedule->command('horizon:snapshot')->everyMinute();
|
||||||
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
||||||
|
$schedule->job(new CheckHelperImageJob)->everyTenMinutes()->onOneServer();
|
||||||
|
|
||||||
// Server Jobs
|
// Server Jobs
|
||||||
$this->check_scheduled_backups($schedule);
|
$this->checkResources($schedule);
|
||||||
$this->check_resources($schedule);
|
|
||||||
$this->check_scheduled_tasks($schedule);
|
$this->checkScheduledBackups($schedule);
|
||||||
|
$this->checkScheduledTasks($schedule);
|
||||||
|
|
||||||
$schedule->command('uploads:clear')->everyTwoMinutes();
|
$schedule->command('uploads:clear')->everyTwoMinutes();
|
||||||
|
|
||||||
$schedule->command('telescope:prune')->daily();
|
|
||||||
|
|
||||||
$schedule->job(new PullHelperImageJob)->everyFiveMinutes()->onOneServer();
|
|
||||||
} else {
|
} else {
|
||||||
// Instance Jobs
|
// Instance Jobs
|
||||||
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||||
$schedule->command('cleanup:unreachable-servers')->daily()->onOneServer();
|
$schedule->command('cleanup:unreachable-servers')->daily()->onOneServer();
|
||||||
$schedule->job(new PullTemplatesFromCDN)->cron($settings->update_check_frequency)->timezone($settings->instance_timezone)->onOneServer();
|
$schedule->job(new PullTemplatesFromCDN)->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||||
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
||||||
$this->schedule_updates($schedule);
|
$this->scheduleUpdates($schedule);
|
||||||
|
|
||||||
// Server Jobs
|
// Server Jobs
|
||||||
$this->check_scheduled_backups($schedule);
|
$this->checkResources($schedule);
|
||||||
$this->check_resources($schedule);
|
|
||||||
$this->pull_images($schedule);
|
$this->pullImages($schedule);
|
||||||
$this->check_scheduled_tasks($schedule);
|
|
||||||
|
$this->checkScheduledBackups($schedule);
|
||||||
|
$this->checkScheduledTasks($schedule);
|
||||||
|
|
||||||
$schedule->command('cleanup:database --yes')->daily();
|
$schedule->command('cleanup:database --yes')->daily();
|
||||||
$schedule->command('uploads:clear')->everyTwoMinutes();
|
$schedule->command('uploads:clear')->everyTwoMinutes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function pull_images($schedule)
|
private function pullImages($schedule): void
|
||||||
{
|
{
|
||||||
$settings = instanceSettings();
|
$servers = $this->allServers->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_reachable', true)->get();
|
||||||
$servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
|
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
if ($server->isSentinelEnabled()) {
|
if ($server->isSentinelEnabled()) {
|
||||||
$schedule->job(function () use ($server) {
|
$schedule->job(function () use ($server) {
|
||||||
$sentinel_found = instant_remote_process(['docker inspect coolify-sentinel'], $server, false);
|
CheckAndStartSentinelJob::dispatch($server);
|
||||||
$sentinel_found = json_decode($sentinel_found, true);
|
})->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||||
$status = data_get($sentinel_found, '0.State.Status', 'exited');
|
|
||||||
if ($status !== 'running') {
|
|
||||||
PullSentinelImageJob::dispatch($server);
|
|
||||||
}
|
|
||||||
})->cron($settings->update_check_frequency)->timezone($settings->instance_timezone)->onOneServer();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$schedule->job(new PullHelperImageJob)
|
$schedule->job(new CheckHelperImageJob)
|
||||||
->cron($settings->update_check_frequency)
|
->cron($this->updateCheckFrequency)
|
||||||
->timezone($settings->instance_timezone)
|
->timezone($this->instanceTimezone)
|
||||||
->onOneServer();
|
->onOneServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function schedule_updates($schedule)
|
private function scheduleUpdates($schedule): void
|
||||||
{
|
{
|
||||||
$settings = instanceSettings();
|
|
||||||
|
|
||||||
$updateCheckFrequency = $settings->update_check_frequency;
|
|
||||||
$schedule->job(new CheckForUpdatesJob)
|
$schedule->job(new CheckForUpdatesJob)
|
||||||
->cron($updateCheckFrequency)
|
->cron($this->updateCheckFrequency)
|
||||||
->timezone($settings->instance_timezone)
|
->timezone($this->instanceTimezone)
|
||||||
->onOneServer();
|
->onOneServer();
|
||||||
|
|
||||||
if ($settings->is_auto_update_enabled) {
|
if ($this->settings->is_auto_update_enabled) {
|
||||||
$autoUpdateFrequency = $settings->auto_update_frequency;
|
$autoUpdateFrequency = $this->settings->auto_update_frequency;
|
||||||
$schedule->job(new UpdateCoolifyJob)
|
$schedule->job(new UpdateCoolifyJob)
|
||||||
->cron($autoUpdateFrequency)
|
->cron($autoUpdateFrequency)
|
||||||
->timezone($settings->instance_timezone)
|
->timezone($this->instanceTimezone)
|
||||||
->onOneServer();
|
->onOneServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function check_resources($schedule)
|
private function checkResources($schedule): void
|
||||||
{
|
{
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
$servers = $this->all_servers->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended', false)->where('ip', '!=', '1.2.3.4');
|
$servers = $this->allServers->whereHas('team.subscription')->get();
|
||||||
$own = Team::find(0)->servers;
|
$own = Team::find(0)->servers;
|
||||||
$servers = $servers->merge($own);
|
$servers = $servers->merge($own);
|
||||||
} else {
|
} else {
|
||||||
$servers = $this->all_servers->where('ip', '!=', '1.2.3.4');
|
$servers = $this->allServers->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
$schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer();
|
|
||||||
// $schedule->job(new ServerStorageCheckJob($server))->everyMinute()->onOneServer();
|
|
||||||
$serverTimezone = $server->settings->server_timezone;
|
$serverTimezone = $server->settings->server_timezone;
|
||||||
|
|
||||||
|
// Sentinel check
|
||||||
|
$lastSentinelUpdate = $server->sentinel_updated_at;
|
||||||
|
if (Carbon::parse($lastSentinelUpdate)->isBefore(now()->subSeconds($server->waitBeforeDoingSshCheck()))) {
|
||||||
|
// Check container status every minute if Sentinel does not activated
|
||||||
|
$schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer();
|
||||||
|
// $schedule->job(new \App\Jobs\ServerCheckNewJob($server))->everyMinute()->onOneServer();
|
||||||
|
|
||||||
|
// Check storage usage every 10 minutes if Sentinel does not activated
|
||||||
|
$schedule->job(new ServerStorageCheckJob($server))->everyTenMinutes()->onOneServer();
|
||||||
|
}
|
||||||
if ($server->settings->force_docker_cleanup) {
|
if ($server->settings->force_docker_cleanup) {
|
||||||
$schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer();
|
$schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer();
|
||||||
} else {
|
} else {
|
||||||
$schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer();
|
$schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleanup multiplexed connections every hour
|
||||||
|
$schedule->job(new ServerCleanupMux($server))->hourly()->onOneServer();
|
||||||
|
|
||||||
|
// Temporary solution until we have better memory management for Sentinel
|
||||||
|
if ($server->isSentinelEnabled()) {
|
||||||
|
$schedule->job(function () use ($server) {
|
||||||
|
$server->restartContainer('coolify-sentinel');
|
||||||
|
})->daily()->onOneServer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function check_scheduled_backups($schedule)
|
private function checkScheduledBackups($schedule): void
|
||||||
{
|
{
|
||||||
$scheduled_backups = ScheduledDatabaseBackup::all();
|
$scheduled_backups = ScheduledDatabaseBackup::where('enabled', true)->get();
|
||||||
if ($scheduled_backups->isEmpty()) {
|
if ($scheduled_backups->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($scheduled_backups as $scheduled_backup) {
|
foreach ($scheduled_backups as $scheduled_backup) {
|
||||||
if (! $scheduled_backup->enabled) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (is_null(data_get($scheduled_backup, 'database'))) {
|
if (is_null(data_get($scheduled_backup, 'database'))) {
|
||||||
ray('database not found');
|
|
||||||
$scheduled_backup->delete();
|
$scheduled_backup->delete();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -145,35 +167,30 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
$server = $scheduled_backup->server();
|
$server = $scheduled_backup->server();
|
||||||
|
|
||||||
if (! $server) {
|
if (is_null($server)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$serverTimezone = $server->settings->server_timezone;
|
|
||||||
|
|
||||||
if (isset(VALID_CRON_STRINGS[$scheduled_backup->frequency])) {
|
if (isset(VALID_CRON_STRINGS[$scheduled_backup->frequency])) {
|
||||||
$scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency];
|
$scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency];
|
||||||
}
|
}
|
||||||
$schedule->job(new DatabaseBackupJob(
|
$schedule->job(new DatabaseBackupJob(
|
||||||
backup: $scheduled_backup
|
backup: $scheduled_backup
|
||||||
))->cron($scheduled_backup->frequency)->timezone($serverTimezone)->onOneServer();
|
))->cron($scheduled_backup->frequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function check_scheduled_tasks($schedule)
|
private function checkScheduledTasks($schedule): void
|
||||||
{
|
{
|
||||||
$scheduled_tasks = ScheduledTask::all();
|
$scheduled_tasks = ScheduledTask::where('enabled', true)->get();
|
||||||
if ($scheduled_tasks->isEmpty()) {
|
if ($scheduled_tasks->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($scheduled_tasks as $scheduled_task) {
|
foreach ($scheduled_tasks as $scheduled_task) {
|
||||||
if ($scheduled_task->enabled === false) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$service = $scheduled_task->service;
|
$service = $scheduled_task->service;
|
||||||
$application = $scheduled_task->application;
|
$application = $scheduled_task->application;
|
||||||
|
|
||||||
if (! $application && ! $service) {
|
if (! $application && ! $service) {
|
||||||
ray('application/service attached to scheduled task does not exist');
|
|
||||||
$scheduled_task->delete();
|
$scheduled_task->delete();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -193,14 +210,13 @@ class Kernel extends ConsoleKernel
|
|||||||
if (! $server) {
|
if (! $server) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$serverTimezone = $server->settings->server_timezone ?: config('app.timezone');
|
|
||||||
|
|
||||||
if (isset(VALID_CRON_STRINGS[$scheduled_task->frequency])) {
|
if (isset(VALID_CRON_STRINGS[$scheduled_task->frequency])) {
|
||||||
$scheduled_task->frequency = VALID_CRON_STRINGS[$scheduled_task->frequency];
|
$scheduled_task->frequency = VALID_CRON_STRINGS[$scheduled_task->frequency];
|
||||||
}
|
}
|
||||||
$schedule->job(new ScheduledTaskJob(
|
$schedule->job(new ScheduledTaskJob(
|
||||||
task: $scheduled_task
|
task: $scheduled_task
|
||||||
))->cron($scheduled_task->frequency)->timezone($serverTimezone)->onOneServer();
|
))->cron($scheduled_task->frequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
app/Enums/Role.php
Normal file
37
app/Enums/Role.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum Role: string
|
||||||
|
{
|
||||||
|
case MEMBER = 'member';
|
||||||
|
case ADMIN = 'admin';
|
||||||
|
case OWNER = 'owner';
|
||||||
|
|
||||||
|
public function rank(): int
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::MEMBER => 1,
|
||||||
|
self::ADMIN => 2,
|
||||||
|
self::OWNER => 3,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lt(Role|string $role): bool
|
||||||
|
{
|
||||||
|
if (is_string($role)) {
|
||||||
|
$role = Role::from($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->rank() < $role->rank();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gt(Role|string $role): bool
|
||||||
|
{
|
||||||
|
if (is_string($role)) {
|
||||||
|
$role = Role::from($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->rank() > $role->rank();
|
||||||
|
}
|
||||||
|
}
|
35
app/Events/DatabaseProxyStopped.php
Normal file
35
app/Events/DatabaseProxyStopped.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class DatabaseProxyStopped implements ShouldBroadcast
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
public $teamId;
|
||||||
|
|
||||||
|
public function __construct($teamId = null)
|
||||||
|
{
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
$teamId = Auth::user()->currentTeam()->id ?? null;
|
||||||
|
}
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
throw new \Exception('Team id is null');
|
||||||
|
}
|
||||||
|
$this->teamId = $teamId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function broadcastOn(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new PrivateChannel("team.{$this->teamId}"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -7,27 +7,29 @@ use Illuminate\Broadcasting\PrivateChannel;
|
|||||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class DatabaseStatusChanged implements ShouldBroadcast
|
class DatabaseStatusChanged implements ShouldBroadcast
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
public ?string $userId = null;
|
public $userId = null;
|
||||||
|
|
||||||
public function __construct($userId = null)
|
public function __construct($userId = null)
|
||||||
{
|
{
|
||||||
if (is_null($userId)) {
|
if (is_null($userId)) {
|
||||||
$userId = auth()->user()->id ?? null;
|
$userId = Auth::id() ?? null;
|
||||||
}
|
}
|
||||||
if (is_null($userId)) {
|
if (is_null($userId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function broadcastOn(): ?array
|
public function broadcastOn(): ?array
|
||||||
{
|
{
|
||||||
if ($this->userId) {
|
if (! is_null($this->userId)) {
|
||||||
return [
|
return [
|
||||||
new PrivateChannel("user.{$this->userId}"),
|
new PrivateChannel("user.{$this->userId}"),
|
||||||
];
|
];
|
||||||
|
@@ -16,7 +16,6 @@ class FileStorageChanged implements ShouldBroadcast
|
|||||||
|
|
||||||
public function __construct($teamId = null)
|
public function __construct($teamId = null)
|
||||||
{
|
{
|
||||||
ray($teamId);
|
|
||||||
if (is_null($teamId)) {
|
if (is_null($teamId)) {
|
||||||
throw new \Exception('Team id is null');
|
throw new \Exception('Team id is null');
|
||||||
}
|
}
|
||||||
|
34
app/Events/ScheduledTaskDone.php
Normal file
34
app/Events/ScheduledTaskDone.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class ScheduledTaskDone implements ShouldBroadcast
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
public $teamId;
|
||||||
|
|
||||||
|
public function __construct($teamId = null)
|
||||||
|
{
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
$teamId = auth()->user()->currentTeam()->id ?? null;
|
||||||
|
}
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
throw new \Exception('Team id is null');
|
||||||
|
}
|
||||||
|
$this->teamId = $teamId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function broadcastOn(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new PrivateChannel("team.{$this->teamId}"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -7,6 +7,7 @@ use Illuminate\Broadcasting\PrivateChannel;
|
|||||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class ServiceStatusChanged implements ShouldBroadcast
|
class ServiceStatusChanged implements ShouldBroadcast
|
||||||
{
|
{
|
||||||
@@ -17,7 +18,7 @@ class ServiceStatusChanged implements ShouldBroadcast
|
|||||||
public function __construct($userId = null)
|
public function __construct($userId = null)
|
||||||
{
|
{
|
||||||
if (is_null($userId)) {
|
if (is_null($userId)) {
|
||||||
$userId = auth()->user()->id ?? null;
|
$userId = Auth::id() ?? null;
|
||||||
}
|
}
|
||||||
if (is_null($userId)) {
|
if (is_null($userId)) {
|
||||||
return false;
|
return false;
|
||||||
|
@@ -84,7 +84,6 @@ class Handler extends ExceptionHandler
|
|||||||
if (str($e->getMessage())->contains('No space left on device')) {
|
if (str($e->getMessage())->contains('No space left on device')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ray('reporting to sentry');
|
|
||||||
Integration::captureUnhandledException($e);
|
Integration::captureUnhandledException($e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -1203,7 +1203,7 @@ class ApplicationsController extends Controller
|
|||||||
$service->name = "service-$service->uuid";
|
$service->name = "service-$service->uuid";
|
||||||
$service->parse(isNew: true);
|
$service->parse(isNew: true);
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartService::dispatch($service);
|
StartService::dispatch($service)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(serializeApiResponse([
|
return response()->json(serializeApiResponse([
|
||||||
@@ -1213,7 +1213,6 @@ class ApplicationsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(['message' => 'Invalid type.'], 400);
|
return response()->json(['message' => 'Invalid type.'], 400);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Get(
|
#[OA\Get(
|
||||||
@@ -1359,7 +1358,7 @@ class ApplicationsController extends Controller
|
|||||||
deleteVolumes: $request->query->get('delete_volumes', true),
|
deleteVolumes: $request->query->get('delete_volumes', true),
|
||||||
dockerCleanup: $request->query->get('docker_cleanup', true),
|
dockerCleanup: $request->query->get('docker_cleanup', true),
|
||||||
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
||||||
);
|
)->onQueue('high');
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Application deletion request queued.',
|
'message' => 'Application deletion request queued.',
|
||||||
@@ -1579,11 +1578,16 @@ class ApplicationsController extends Controller
|
|||||||
$request->offsetUnset('docker_compose_domains');
|
$request->offsetUnset('docker_compose_domains');
|
||||||
}
|
}
|
||||||
$instantDeploy = $request->instant_deploy;
|
$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)) {
|
if (isset($isStatic)) {
|
||||||
$application->settings->is_build_server_enabled = $use_build_server;
|
$application->settings->is_static = $isStatic;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1687,9 +1691,8 @@ class ApplicationsController extends Controller
|
|||||||
'standalone_postgresql_id',
|
'standalone_postgresql_id',
|
||||||
'standalone_redis_id',
|
'standalone_redis_id',
|
||||||
]);
|
]);
|
||||||
$env = $this->removeSensitiveData($env);
|
|
||||||
|
|
||||||
return $env;
|
return $this->removeSensitiveData($env);
|
||||||
});
|
});
|
||||||
|
|
||||||
return response()->json($envs);
|
return response()->json($envs);
|
||||||
@@ -1864,18 +1867,15 @@ class ApplicationsController extends Controller
|
|||||||
|
|
||||||
return response()->json($this->removeSensitiveData($env))->setStatusCode(201);
|
return response()->json($this->removeSensitiveData($env))->setStatusCode(201);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Environment variable not found.',
|
'message' => 'Environment variable not found.',
|
||||||
], 404);
|
], 404);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Something is not okay. Are you okay?',
|
'message' => 'Something is not okay. Are you okay?',
|
||||||
], 500);
|
], 500);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Patch(
|
#[OA\Patch(
|
||||||
@@ -2220,14 +2220,12 @@ class ApplicationsController extends Controller
|
|||||||
return response()->json([
|
return response()->json([
|
||||||
'uuid' => $env->uuid,
|
'uuid' => $env->uuid,
|
||||||
])->setStatusCode(201);
|
])->setStatusCode(201);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Something went wrong.',
|
'message' => 'Something went wrong.',
|
||||||
], 500);
|
], 500);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Delete(
|
#[OA\Delete(
|
||||||
@@ -2484,7 +2482,7 @@ class ApplicationsController extends Controller
|
|||||||
if (! $application) {
|
if (! $application) {
|
||||||
return response()->json(['message' => 'Application not found.'], 404);
|
return response()->json(['message' => 'Application not found.'], 404);
|
||||||
}
|
}
|
||||||
StopApplication::dispatch($application);
|
StopApplication::dispatch($application)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
@@ -2575,7 +2573,6 @@ class ApplicationsController extends Controller
|
|||||||
'deployment_uuid' => $deployment_uuid->toString(),
|
'deployment_uuid' => $deployment_uuid->toString(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Post(
|
#[OA\Post(
|
||||||
@@ -2741,7 +2738,6 @@ class ApplicationsController extends Controller
|
|||||||
'custom_labels' => 'The custom_labels should be base64 encoded.',
|
'custom_labels' => 'The custom_labels should be base64 encoded.',
|
||||||
],
|
],
|
||||||
], 422);
|
], 422);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($request->has('domains') && $server->isProxyShouldRun()) {
|
if ($request->has('domains') && $server->isProxyShouldRun()) {
|
||||||
|
@@ -471,7 +471,6 @@ class DatabasesController extends Controller
|
|||||||
$request->offsetSet('mysql_conf', $mysqlConf);
|
$request->offsetSet('mysql_conf', $mysqlConf);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||||
if ($validator->fails() || ! empty($extraFields)) {
|
if ($validator->fails() || ! empty($extraFields)) {
|
||||||
@@ -498,15 +497,14 @@ class DatabasesController extends Controller
|
|||||||
$database->update($request->all());
|
$database->update($request->all());
|
||||||
|
|
||||||
if ($whatToDoWithDatabaseProxy === 'start') {
|
if ($whatToDoWithDatabaseProxy === 'start') {
|
||||||
StartDatabaseProxy::dispatch($database);
|
StartDatabaseProxy::dispatch($database)->onQueue('high');
|
||||||
} elseif ($whatToDoWithDatabaseProxy === 'stop') {
|
} elseif ($whatToDoWithDatabaseProxy === 'stop') {
|
||||||
StopDatabaseProxy::dispatch($database);
|
StopDatabaseProxy::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Database updated.',
|
'message' => 'Database updated.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Post(
|
#[OA\Post(
|
||||||
@@ -1153,7 +1151,7 @@ class DatabasesController extends Controller
|
|||||||
}
|
}
|
||||||
$database = create_standalone_postgresql($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_postgresql($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
$payload = [
|
$payload = [
|
||||||
@@ -1165,7 +1163,6 @@ class DatabasesController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
||||||
|
|
||||||
} elseif ($type === NewDatabaseTypes::MARIADB) {
|
} elseif ($type === NewDatabaseTypes::MARIADB) {
|
||||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database'];
|
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database'];
|
||||||
$validator = customApiValidator($request->all(), [
|
$validator = customApiValidator($request->all(), [
|
||||||
@@ -1209,7 +1206,7 @@ class DatabasesController extends Controller
|
|||||||
}
|
}
|
||||||
$database = create_standalone_mariadb($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_mariadb($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
@@ -1267,7 +1264,7 @@ class DatabasesController extends Controller
|
|||||||
}
|
}
|
||||||
$database = create_standalone_mysql($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_mysql($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
@@ -1323,7 +1320,7 @@ class DatabasesController extends Controller
|
|||||||
}
|
}
|
||||||
$database = create_standalone_redis($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_redis($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
@@ -1360,7 +1357,7 @@ class DatabasesController extends Controller
|
|||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
$database = create_standalone_dragonfly($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_dragonfly($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(serializeApiResponse([
|
return response()->json(serializeApiResponse([
|
||||||
@@ -1409,7 +1406,7 @@ class DatabasesController extends Controller
|
|||||||
}
|
}
|
||||||
$database = create_standalone_keydb($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_keydb($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
@@ -1445,7 +1442,7 @@ class DatabasesController extends Controller
|
|||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
$database = create_standalone_clickhouse($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_clickhouse($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
@@ -1503,7 +1500,7 @@ class DatabasesController extends Controller
|
|||||||
}
|
}
|
||||||
$database = create_standalone_mongodb($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_mongodb($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
@@ -1596,7 +1593,7 @@ class DatabasesController extends Controller
|
|||||||
deleteVolumes: $request->query->get('delete_volumes', true),
|
deleteVolumes: $request->query->get('delete_volumes', true),
|
||||||
dockerCleanup: $request->query->get('docker_cleanup', true),
|
dockerCleanup: $request->query->get('docker_cleanup', true),
|
||||||
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
||||||
);
|
)->onQueue('high');
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Database deletion request queued.',
|
'message' => 'Database deletion request queued.',
|
||||||
@@ -1669,7 +1666,7 @@ class DatabasesController extends Controller
|
|||||||
if (str($database->status)->contains('running')) {
|
if (str($database->status)->contains('running')) {
|
||||||
return response()->json(['message' => 'Database is already running.'], 400);
|
return response()->json(['message' => 'Database is already running.'], 400);
|
||||||
}
|
}
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
@@ -1745,7 +1742,7 @@ class DatabasesController extends Controller
|
|||||||
if (str($database->status)->contains('stopped') || str($database->status)->contains('exited')) {
|
if (str($database->status)->contains('stopped') || str($database->status)->contains('exited')) {
|
||||||
return response()->json(['message' => 'Database is already stopped.'], 400);
|
return response()->json(['message' => 'Database is already stopped.'], 400);
|
||||||
}
|
}
|
||||||
StopDatabase::dispatch($database);
|
StopDatabase::dispatch($database)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
@@ -1818,7 +1815,7 @@ class DatabasesController extends Controller
|
|||||||
if (! $database) {
|
if (! $database) {
|
||||||
return response()->json(['message' => 'Database not found.'], 404);
|
return response()->json(['message' => 'Database not found.'], 404);
|
||||||
}
|
}
|
||||||
RestartDatabase::dispatch($database);
|
RestartDatabase::dispatch($database)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
@@ -1826,6 +1823,5 @@ class DatabasesController extends Controller
|
|||||||
],
|
],
|
||||||
200
|
200
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -292,7 +292,7 @@ class DeployController extends Controller
|
|||||||
return ['message' => "Resource ($resource) not found.", 'deployment_uuid' => $deployment_uuid];
|
return ['message' => "Resource ($resource) not found.", 'deployment_uuid' => $deployment_uuid];
|
||||||
}
|
}
|
||||||
switch ($resource?->getMorphClass()) {
|
switch ($resource?->getMorphClass()) {
|
||||||
case 'App\Models\Application':
|
case \App\Models\Application::class:
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $resource,
|
application: $resource,
|
||||||
@@ -301,13 +301,13 @@ class DeployController extends Controller
|
|||||||
);
|
);
|
||||||
$message = "Application {$resource->name} deployment queued.";
|
$message = "Application {$resource->name} deployment queued.";
|
||||||
break;
|
break;
|
||||||
case 'App\Models\Service':
|
case \App\Models\Service::class:
|
||||||
StartService::run($resource);
|
StartService::run($resource);
|
||||||
$message = "Service {$resource->name} started. It could take a while, be patient.";
|
$message = "Service {$resource->name} started. It could take a while, be patient.";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Database resource
|
// Database resource
|
||||||
StartDatabase::dispatch($resource);
|
StartDatabase::dispatch($resource)->onQueue('high');
|
||||||
$resource->update([
|
$resource->update([
|
||||||
'started_at' => now(),
|
'started_at' => now(),
|
||||||
]);
|
]);
|
||||||
|
@@ -160,7 +160,7 @@ class OtherController extends Controller
|
|||||||
#[OA\Get(
|
#[OA\Get(
|
||||||
summary: 'Healthcheck',
|
summary: 'Healthcheck',
|
||||||
description: 'Healthcheck endpoint.',
|
description: 'Healthcheck endpoint.',
|
||||||
path: '/healthcheck',
|
path: '/health',
|
||||||
operationId: 'healthcheck',
|
operationId: 'healthcheck',
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
|
@@ -356,7 +356,6 @@ class ProjectController extends Controller
|
|||||||
'name' => $project->name,
|
'name' => $project->name,
|
||||||
'description' => $project->description,
|
'description' => $project->description,
|
||||||
])->setStatusCode(201);
|
])->setStatusCode(201);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Delete(
|
#[OA\Delete(
|
||||||
@@ -423,7 +422,7 @@ class ProjectController extends Controller
|
|||||||
if (! $project) {
|
if (! $project) {
|
||||||
return response()->json(['message' => 'Project not found.'], 404);
|
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);
|
return response()->json(['message' => 'Project has resources, so it cannot be deleted.'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,7 +53,7 @@ class ResourcesController extends Controller
|
|||||||
$resources = $resources->flatten();
|
$resources = $resources->flatten();
|
||||||
$resources = $resources->map(function ($resource) {
|
$resources = $resources->map(function ($resource) {
|
||||||
$payload = $resource->toArray();
|
$payload = $resource->toArray();
|
||||||
if ($resource->getMorphClass() === 'App\Models\Service') {
|
if ($resource->getMorphClass() === \App\Models\Service::class) {
|
||||||
$payload['status'] = $resource->status();
|
$payload['status'] = $resource->status();
|
||||||
} else {
|
} else {
|
||||||
$payload['status'] = $resource->status;
|
$payload['status'] = $resource->status;
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Actions\Server\DeleteServer;
|
||||||
use App\Actions\Server\ValidateServer;
|
use App\Actions\Server\ValidateServer;
|
||||||
use App\Enums\ProxyStatus;
|
use App\Enums\ProxyStatus;
|
||||||
use App\Enums\ProxyTypes;
|
use App\Enums\ProxyTypes;
|
||||||
@@ -23,7 +24,7 @@ class ServersController extends Controller
|
|||||||
return serializeApiResponse($settings);
|
return serializeApiResponse($settings);
|
||||||
}
|
}
|
||||||
$settings = $settings->makeHidden([
|
$settings = $settings->makeHidden([
|
||||||
'metrics_token',
|
'sentinel_token',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return serializeApiResponse($settings);
|
return serializeApiResponse($settings);
|
||||||
@@ -248,7 +249,6 @@ class ServersController extends Controller
|
|||||||
return $payload;
|
return $payload;
|
||||||
});
|
});
|
||||||
$server = $this->removeSensitiveData($server);
|
$server = $this->removeSensitiveData($server);
|
||||||
ray($server);
|
|
||||||
|
|
||||||
return response()->json(serializeApiResponse(data_get($server, 'resources')));
|
return response()->json(serializeApiResponse(data_get($server, 'resources')));
|
||||||
}
|
}
|
||||||
@@ -538,7 +538,7 @@ class ServersController extends Controller
|
|||||||
'is_build_server' => $request->is_build_server,
|
'is_build_server' => $request->is_build_server,
|
||||||
]);
|
]);
|
||||||
if ($request->instant_validate) {
|
if ($request->instant_validate) {
|
||||||
ValidateServer::dispatch($server);
|
ValidateServer::dispatch($server)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@@ -651,7 +651,7 @@ class ServersController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if ($request->instant_validate) {
|
if ($request->instant_validate) {
|
||||||
ValidateServer::dispatch($server);
|
ValidateServer::dispatch($server)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(serializeApiResponse($server))->setStatusCode(201);
|
return response()->json(serializeApiResponse($server))->setStatusCode(201);
|
||||||
@@ -726,6 +726,7 @@ class ServersController extends Controller
|
|||||||
return response()->json(['message' => 'Server has resources, so you need to delete them before.'], 400);
|
return response()->json(['message' => 'Server has resources, so you need to delete them before.'], 400);
|
||||||
}
|
}
|
||||||
$server->delete();
|
$server->delete();
|
||||||
|
DeleteServer::dispatch($server);
|
||||||
|
|
||||||
return response()->json(['message' => 'Server deleted.']);
|
return response()->json(['message' => 'Server deleted.']);
|
||||||
}
|
}
|
||||||
@@ -786,7 +787,7 @@ class ServersController extends Controller
|
|||||||
if (! $server) {
|
if (! $server) {
|
||||||
return response()->json(['message' => 'Server not found.'], 404);
|
return response()->json(['message' => 'Server not found.'], 404);
|
||||||
}
|
}
|
||||||
ValidateServer::dispatch($server);
|
ValidateServer::dispatch($server)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(['message' => 'Validation started.']);
|
return response()->json(['message' => 'Validation started.']);
|
||||||
}
|
}
|
||||||
|
@@ -342,7 +342,7 @@ class ServicesController extends Controller
|
|||||||
}
|
}
|
||||||
$service->parse(isNew: true);
|
$service->parse(isNew: true);
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartService::dispatch($service);
|
StartService::dispatch($service)->onQueue('high');
|
||||||
}
|
}
|
||||||
$domains = $service->applications()->get()->pluck('fqdn')->sort();
|
$domains = $service->applications()->get()->pluck('fqdn')->sort();
|
||||||
$domains = $domains->map(function ($domain) {
|
$domains = $domains->map(function ($domain) {
|
||||||
@@ -487,7 +487,7 @@ class ServicesController extends Controller
|
|||||||
deleteVolumes: $request->query->get('delete_volumes', true),
|
deleteVolumes: $request->query->get('delete_volumes', true),
|
||||||
dockerCleanup: $request->query->get('docker_cleanup', true),
|
dockerCleanup: $request->query->get('docker_cleanup', true),
|
||||||
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
||||||
);
|
)->onQueue('high');
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Service deletion request queued.',
|
'message' => 'Service deletion request queued.',
|
||||||
@@ -566,9 +566,8 @@ class ServicesController extends Controller
|
|||||||
'standalone_postgresql_id',
|
'standalone_postgresql_id',
|
||||||
'standalone_redis_id',
|
'standalone_redis_id',
|
||||||
]);
|
]);
|
||||||
$env = $this->removeSensitiveData($env);
|
|
||||||
|
|
||||||
return $env;
|
return $this->removeSensitiveData($env);
|
||||||
});
|
});
|
||||||
|
|
||||||
return response()->json($envs);
|
return response()->json($envs);
|
||||||
@@ -1077,7 +1076,7 @@ class ServicesController extends Controller
|
|||||||
if (str($service->status())->contains('running')) {
|
if (str($service->status())->contains('running')) {
|
||||||
return response()->json(['message' => 'Service is already running.'], 400);
|
return response()->json(['message' => 'Service is already running.'], 400);
|
||||||
}
|
}
|
||||||
StartService::dispatch($service);
|
StartService::dispatch($service)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
@@ -1155,7 +1154,7 @@ class ServicesController extends Controller
|
|||||||
if (str($service->status())->contains('stopped') || str($service->status())->contains('exited')) {
|
if (str($service->status())->contains('stopped') || str($service->status())->contains('exited')) {
|
||||||
return response()->json(['message' => 'Service is already stopped.'], 400);
|
return response()->json(['message' => 'Service is already stopped.'], 400);
|
||||||
}
|
}
|
||||||
StopService::dispatch($service);
|
StopService::dispatch($service)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
@@ -1230,7 +1229,7 @@ class ServicesController extends Controller
|
|||||||
if (! $service) {
|
if (! $service) {
|
||||||
return response()->json(['message' => 'Service not found.'], 404);
|
return response()->json(['message' => 'Service not found.'], 404);
|
||||||
}
|
}
|
||||||
RestartService::dispatch($service);
|
RestartService::dispatch($service)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
@@ -1238,6 +1237,5 @@ class ServicesController extends Controller
|
|||||||
],
|
],
|
||||||
200
|
200
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -110,59 +110,54 @@ class Controller extends BaseController
|
|||||||
return redirect()->route('login')->with('error', 'Invalid credentials.');
|
return redirect()->route('login')->with('error', 'Invalid credentials.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function accept_invitation()
|
public function acceptInvitation()
|
||||||
{
|
{
|
||||||
try {
|
$resetPassword = request()->query('reset-password');
|
||||||
$resetPassword = request()->query('reset-password');
|
$invitationUuid = request()->route('uuid');
|
||||||
$invitationUuid = request()->route('uuid');
|
|
||||||
$invitation = TeamInvitation::whereUuid($invitationUuid)->firstOrFail();
|
|
||||||
$user = User::whereEmail($invitation->email)->firstOrFail();
|
|
||||||
$invitationValid = $invitation->isValid();
|
|
||||||
if ($invitationValid) {
|
|
||||||
if ($resetPassword) {
|
|
||||||
$user->update([
|
|
||||||
'password' => Hash::make($invitationUuid),
|
|
||||||
'force_password_reset' => true,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
if ($user->teams()->where('team_id', $invitation->team->id)->exists()) {
|
|
||||||
$invitation->delete();
|
|
||||||
|
|
||||||
return redirect()->route('team.index');
|
$invitation = TeamInvitation::whereUuid($invitationUuid)->firstOrFail();
|
||||||
}
|
$user = User::whereEmail($invitation->email)->firstOrFail();
|
||||||
$user->teams()->attach($invitation->team->id, ['role' => $invitation->role]);
|
|
||||||
|
if (Auth::id() !== $user->id) {
|
||||||
|
abort(400, 'You are not allowed to accept this invitation.');
|
||||||
|
}
|
||||||
|
$invitationValid = $invitation->isValid();
|
||||||
|
|
||||||
|
if ($invitationValid) {
|
||||||
|
if ($resetPassword) {
|
||||||
|
$user->update([
|
||||||
|
'password' => Hash::make($invitationUuid),
|
||||||
|
'force_password_reset' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if ($user->teams()->where('team_id', $invitation->team->id)->exists()) {
|
||||||
$invitation->delete();
|
$invitation->delete();
|
||||||
if (auth()->user()?->id !== $user->id) {
|
|
||||||
return redirect()->route('login');
|
|
||||||
}
|
|
||||||
refreshSession($invitation->team);
|
|
||||||
|
|
||||||
return redirect()->route('team.index');
|
return redirect()->route('team.index');
|
||||||
} else {
|
|
||||||
abort(401);
|
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
$user->teams()->attach($invitation->team->id, ['role' => $invitation->role]);
|
||||||
ray($e->getMessage());
|
$invitation->delete();
|
||||||
throw $e;
|
|
||||||
|
refreshSession($invitation->team);
|
||||||
|
|
||||||
|
return redirect()->route('team.index');
|
||||||
|
} else {
|
||||||
|
abort(400, 'Invitation expired.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function revoke_invitation()
|
public function revoke_invitation()
|
||||||
{
|
{
|
||||||
try {
|
$invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();
|
||||||
$invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();
|
$user = User::whereEmail($invitation->email)->firstOrFail();
|
||||||
$user = User::whereEmail($invitation->email)->firstOrFail();
|
if (is_null(Auth::user())) {
|
||||||
if (is_null(auth()->user())) {
|
return redirect()->route('login');
|
||||||
return redirect()->route('login');
|
|
||||||
}
|
|
||||||
if (auth()->user()->id !== $user->id) {
|
|
||||||
abort(401);
|
|
||||||
}
|
|
||||||
$invitation->delete();
|
|
||||||
|
|
||||||
return redirect()->route('team.index');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
throw $e;
|
|
||||||
}
|
}
|
||||||
|
if (Auth::id() !== $user->id) {
|
||||||
|
abort(401);
|
||||||
|
}
|
||||||
|
$invitation->delete();
|
||||||
|
|
||||||
|
return redirect()->route('team.index');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,8 +35,6 @@ class OauthController extends Controller
|
|||||||
|
|
||||||
return redirect('/');
|
return redirect('/');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
$errorCode = $e instanceof HttpException ? 'auth.failed' : 'auth.failed.callback';
|
$errorCode = $e instanceof HttpException ? 'auth.failed' : 'auth.failed.callback';
|
||||||
|
|
||||||
return redirect()->route('login')->withErrors([__($errorCode)]);
|
return redirect()->route('login')->withErrors([__($errorCode)]);
|
||||||
|
@@ -5,7 +5,6 @@ namespace App\Http\Controllers;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Routing\Controller as BaseController;
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException;
|
use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException;
|
||||||
use Pion\Laravel\ChunkUpload\Handler\HandlerFactory;
|
use Pion\Laravel\ChunkUpload\Handler\HandlerFactory;
|
||||||
use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;
|
use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;
|
||||||
|
@@ -16,7 +16,6 @@ class Bitbucket extends Controller
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (app()->isDownForMaintenance()) {
|
if (app()->isDownForMaintenance()) {
|
||||||
ray('Maintenance mode is on');
|
|
||||||
$epoch = now()->valueOf();
|
$epoch = now()->valueOf();
|
||||||
$data = [
|
$data = [
|
||||||
'attributes' => $request->attributes->all(),
|
'attributes' => $request->attributes->all(),
|
||||||
@@ -55,7 +54,6 @@ class Bitbucket extends Controller
|
|||||||
'message' => 'Nothing to do. No branch found in the request.',
|
'message' => 'Nothing to do. No branch found in the request.',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
ray('Manual webhook bitbucket push event with branch: '.$branch);
|
|
||||||
}
|
}
|
||||||
if ($x_bitbucket_event === 'pullrequest:created' || $x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
|
if ($x_bitbucket_event === 'pullrequest:created' || $x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
|
||||||
$branch = data_get($payload, 'pullrequest.destination.branch.name');
|
$branch = data_get($payload, 'pullrequest.destination.branch.name');
|
||||||
@@ -85,7 +83,6 @@ class Bitbucket extends Controller
|
|||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Invalid signature.',
|
'message' => 'Invalid signature.',
|
||||||
]);
|
]);
|
||||||
ray('Invalid signature');
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -96,13 +93,11 @@ class Bitbucket extends Controller
|
|||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Server is not functional.',
|
'message' => 'Server is not functional.',
|
||||||
]);
|
]);
|
||||||
ray('Server is not functional: '.$application->destination->server->name);
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($x_bitbucket_event === 'repo:push') {
|
if ($x_bitbucket_event === 'repo:push') {
|
||||||
if ($application->isDeployable()) {
|
if ($application->isDeployable()) {
|
||||||
ray('Deploying '.$application->name.' with branch '.$branch);
|
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -126,7 +121,6 @@ class Bitbucket extends Controller
|
|||||||
}
|
}
|
||||||
if ($x_bitbucket_event === 'pullrequest:created') {
|
if ($x_bitbucket_event === 'pullrequest:created') {
|
||||||
if ($application->isPRDeployable()) {
|
if ($application->isPRDeployable()) {
|
||||||
ray('Deploying preview for '.$application->name.' with branch '.$branch.' and base branch '.$base_branch.' and pull request id '.$pull_request_id);
|
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||||
if (! $found) {
|
if (! $found) {
|
||||||
@@ -171,7 +165,6 @@ class Bitbucket extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
|
if ($x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
|
||||||
ray('Pull request rejected');
|
|
||||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||||
if ($found) {
|
if ($found) {
|
||||||
$found->delete();
|
$found->delete();
|
||||||
@@ -191,12 +184,9 @@ class Bitbucket extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ray($return_payloads);
|
|
||||||
|
|
||||||
return response($return_payloads);
|
return response($return_payloads);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ray($e);
|
|
||||||
|
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,15 +19,12 @@ class Gitea extends Controller
|
|||||||
$return_payloads = collect([]);
|
$return_payloads = collect([]);
|
||||||
$x_gitea_delivery = request()->header('X-Gitea-Delivery');
|
$x_gitea_delivery = request()->header('X-Gitea-Delivery');
|
||||||
if (app()->isDownForMaintenance()) {
|
if (app()->isDownForMaintenance()) {
|
||||||
ray('Maintenance mode is on');
|
|
||||||
$epoch = now()->valueOf();
|
$epoch = now()->valueOf();
|
||||||
$files = Storage::disk('webhooks-during-maintenance')->files();
|
$files = Storage::disk('webhooks-during-maintenance')->files();
|
||||||
$gitea_delivery_found = collect($files)->filter(function ($file) use ($x_gitea_delivery) {
|
$gitea_delivery_found = collect($files)->filter(function ($file) use ($x_gitea_delivery) {
|
||||||
return Str::contains($file, $x_gitea_delivery);
|
return Str::contains($file, $x_gitea_delivery);
|
||||||
})->first();
|
})->first();
|
||||||
if ($gitea_delivery_found) {
|
if ($gitea_delivery_found) {
|
||||||
ray('Webhook already found');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$data = [
|
$data = [
|
||||||
@@ -67,8 +64,6 @@ class Gitea extends Controller
|
|||||||
$removed_files = data_get($payload, 'commits.*.removed');
|
$removed_files = data_get($payload, 'commits.*.removed');
|
||||||
$modified_files = data_get($payload, 'commits.*.modified');
|
$modified_files = data_get($payload, 'commits.*.modified');
|
||||||
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
||||||
ray($changed_files);
|
|
||||||
ray('Manual Webhook Gitea Push Event with branch: '.$branch);
|
|
||||||
}
|
}
|
||||||
if ($x_gitea_event === 'pull_request') {
|
if ($x_gitea_event === 'pull_request') {
|
||||||
$action = data_get($payload, 'action');
|
$action = data_get($payload, 'action');
|
||||||
@@ -77,7 +72,6 @@ class Gitea extends Controller
|
|||||||
$pull_request_html_url = data_get($payload, 'pull_request.html_url');
|
$pull_request_html_url = data_get($payload, 'pull_request.html_url');
|
||||||
$branch = data_get($payload, 'pull_request.head.ref');
|
$branch = data_get($payload, 'pull_request.head.ref');
|
||||||
$base_branch = data_get($payload, 'pull_request.base.ref');
|
$base_branch = data_get($payload, 'pull_request.base.ref');
|
||||||
ray('Webhook Gitea Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id);
|
|
||||||
}
|
}
|
||||||
if (! $branch) {
|
if (! $branch) {
|
||||||
return response('Nothing to do. No branch found in the request.');
|
return response('Nothing to do. No branch found in the request.');
|
||||||
@@ -99,7 +93,6 @@ class Gitea extends Controller
|
|||||||
$webhook_secret = data_get($application, 'manual_webhook_secret_gitea');
|
$webhook_secret = data_get($application, 'manual_webhook_secret_gitea');
|
||||||
$hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
|
$hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
|
||||||
if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) {
|
if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) {
|
||||||
ray('Invalid signature');
|
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
'application' => $application->name,
|
||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
@@ -122,7 +115,6 @@ class Gitea extends Controller
|
|||||||
if ($application->isDeployable()) {
|
if ($application->isDeployable()) {
|
||||||
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
||||||
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
||||||
ray('Deploying '.$application->name.' with branch '.$branch);
|
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -182,7 +174,6 @@ class Gitea extends Controller
|
|||||||
'pull_request_html_url' => $pull_request_html_url,
|
'pull_request_html_url' => $pull_request_html_url,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -228,12 +219,9 @@ class Gitea extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ray($return_payloads);
|
|
||||||
|
|
||||||
return response($return_payloads);
|
return response($return_payloads);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,15 +25,12 @@ class Github extends Controller
|
|||||||
$return_payloads = collect([]);
|
$return_payloads = collect([]);
|
||||||
$x_github_delivery = request()->header('X-GitHub-Delivery');
|
$x_github_delivery = request()->header('X-GitHub-Delivery');
|
||||||
if (app()->isDownForMaintenance()) {
|
if (app()->isDownForMaintenance()) {
|
||||||
ray('Maintenance mode is on');
|
|
||||||
$epoch = now()->valueOf();
|
$epoch = now()->valueOf();
|
||||||
$files = Storage::disk('webhooks-during-maintenance')->files();
|
$files = Storage::disk('webhooks-during-maintenance')->files();
|
||||||
$github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) {
|
$github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) {
|
||||||
return Str::contains($file, $x_github_delivery);
|
return Str::contains($file, $x_github_delivery);
|
||||||
})->first();
|
})->first();
|
||||||
if ($github_delivery_found) {
|
if ($github_delivery_found) {
|
||||||
ray('Webhook already found');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$data = [
|
$data = [
|
||||||
@@ -73,7 +70,6 @@ class Github extends Controller
|
|||||||
$removed_files = data_get($payload, 'commits.*.removed');
|
$removed_files = data_get($payload, 'commits.*.removed');
|
||||||
$modified_files = data_get($payload, 'commits.*.modified');
|
$modified_files = data_get($payload, 'commits.*.modified');
|
||||||
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
||||||
ray('Manual Webhook GitHub Push Event with branch: '.$branch);
|
|
||||||
}
|
}
|
||||||
if ($x_github_event === 'pull_request') {
|
if ($x_github_event === 'pull_request') {
|
||||||
$action = data_get($payload, 'action');
|
$action = data_get($payload, 'action');
|
||||||
@@ -82,7 +78,6 @@ class Github extends Controller
|
|||||||
$pull_request_html_url = data_get($payload, 'pull_request.html_url');
|
$pull_request_html_url = data_get($payload, 'pull_request.html_url');
|
||||||
$branch = data_get($payload, 'pull_request.head.ref');
|
$branch = data_get($payload, 'pull_request.head.ref');
|
||||||
$base_branch = data_get($payload, 'pull_request.base.ref');
|
$base_branch = data_get($payload, 'pull_request.base.ref');
|
||||||
ray('Webhook GitHub Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id);
|
|
||||||
}
|
}
|
||||||
if (! $branch) {
|
if (! $branch) {
|
||||||
return response('Nothing to do. No branch found in the request.');
|
return response('Nothing to do. No branch found in the request.');
|
||||||
@@ -104,7 +99,6 @@ class Github extends Controller
|
|||||||
$webhook_secret = data_get($application, 'manual_webhook_secret_github');
|
$webhook_secret = data_get($application, 'manual_webhook_secret_github');
|
||||||
$hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
|
$hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
|
||||||
if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) {
|
if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) {
|
||||||
ray('Invalid signature');
|
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
'application' => $application->name,
|
||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
@@ -127,7 +121,6 @@ class Github extends Controller
|
|||||||
if ($application->isDeployable()) {
|
if ($application->isDeployable()) {
|
||||||
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
||||||
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
||||||
ray('Deploying '.$application->name.' with branch '.$branch);
|
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -232,12 +225,9 @@ class Github extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ray($return_payloads);
|
|
||||||
|
|
||||||
return response($return_payloads);
|
return response($return_payloads);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,15 +239,12 @@ class Github extends Controller
|
|||||||
$id = null;
|
$id = null;
|
||||||
$x_github_delivery = $request->header('X-GitHub-Delivery');
|
$x_github_delivery = $request->header('X-GitHub-Delivery');
|
||||||
if (app()->isDownForMaintenance()) {
|
if (app()->isDownForMaintenance()) {
|
||||||
ray('Maintenance mode is on');
|
|
||||||
$epoch = now()->valueOf();
|
$epoch = now()->valueOf();
|
||||||
$files = Storage::disk('webhooks-during-maintenance')->files();
|
$files = Storage::disk('webhooks-during-maintenance')->files();
|
||||||
$github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) {
|
$github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) {
|
||||||
return Str::contains($file, $x_github_delivery);
|
return Str::contains($file, $x_github_delivery);
|
||||||
})->first();
|
})->first();
|
||||||
if ($github_delivery_found) {
|
if ($github_delivery_found) {
|
||||||
ray('Webhook already found');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$data = [
|
$data = [
|
||||||
@@ -313,7 +300,6 @@ class Github extends Controller
|
|||||||
$removed_files = data_get($payload, 'commits.*.removed');
|
$removed_files = data_get($payload, 'commits.*.removed');
|
||||||
$modified_files = data_get($payload, 'commits.*.modified');
|
$modified_files = data_get($payload, 'commits.*.modified');
|
||||||
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
||||||
ray('Webhook GitHub Push Event: '.$id.' with branch: '.$branch);
|
|
||||||
}
|
}
|
||||||
if ($x_github_event === 'pull_request') {
|
if ($x_github_event === 'pull_request') {
|
||||||
$action = data_get($payload, 'action');
|
$action = data_get($payload, 'action');
|
||||||
@@ -322,7 +308,6 @@ class Github extends Controller
|
|||||||
$pull_request_html_url = data_get($payload, 'pull_request.html_url');
|
$pull_request_html_url = data_get($payload, 'pull_request.html_url');
|
||||||
$branch = data_get($payload, 'pull_request.head.ref');
|
$branch = data_get($payload, 'pull_request.head.ref');
|
||||||
$base_branch = data_get($payload, 'pull_request.base.ref');
|
$base_branch = data_get($payload, 'pull_request.base.ref');
|
||||||
ray('Webhook GitHub Pull Request Event: '.$id.' with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id);
|
|
||||||
}
|
}
|
||||||
if (! $id || ! $branch) {
|
if (! $id || ! $branch) {
|
||||||
return response('Nothing to do. No id or branch found.');
|
return response('Nothing to do. No id or branch found.');
|
||||||
@@ -356,7 +341,6 @@ class Github extends Controller
|
|||||||
if ($application->isDeployable()) {
|
if ($application->isDeployable()) {
|
||||||
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
||||||
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
||||||
ray('Deploying '.$application->name.' with branch '.$branch);
|
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -460,8 +444,6 @@ class Github extends Controller
|
|||||||
|
|
||||||
return response($return_payloads);
|
return response($return_payloads);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -505,7 +487,6 @@ class Github extends Controller
|
|||||||
try {
|
try {
|
||||||
$installation_id = $request->get('installation_id');
|
$installation_id = $request->get('installation_id');
|
||||||
if (app()->isDownForMaintenance()) {
|
if (app()->isDownForMaintenance()) {
|
||||||
ray('Maintenance mode is on');
|
|
||||||
$epoch = now()->valueOf();
|
$epoch = now()->valueOf();
|
||||||
$data = [
|
$data = [
|
||||||
'attributes' => $request->attributes->all(),
|
'attributes' => $request->attributes->all(),
|
||||||
|
@@ -17,7 +17,6 @@ class Gitlab extends Controller
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (app()->isDownForMaintenance()) {
|
if (app()->isDownForMaintenance()) {
|
||||||
ray('Maintenance mode is on');
|
|
||||||
$epoch = now()->valueOf();
|
$epoch = now()->valueOf();
|
||||||
$data = [
|
$data = [
|
||||||
'attributes' => $request->attributes->all(),
|
'attributes' => $request->attributes->all(),
|
||||||
@@ -67,7 +66,6 @@ class Gitlab extends Controller
|
|||||||
$removed_files = data_get($payload, 'commits.*.removed');
|
$removed_files = data_get($payload, 'commits.*.removed');
|
||||||
$modified_files = data_get($payload, 'commits.*.modified');
|
$modified_files = data_get($payload, 'commits.*.modified');
|
||||||
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
||||||
ray('Manual Webhook GitLab Push Event with branch: '.$branch);
|
|
||||||
}
|
}
|
||||||
if ($x_gitlab_event === 'merge_request') {
|
if ($x_gitlab_event === 'merge_request') {
|
||||||
$action = data_get($payload, 'object_attributes.action');
|
$action = data_get($payload, 'object_attributes.action');
|
||||||
@@ -84,7 +82,6 @@ class Gitlab extends Controller
|
|||||||
|
|
||||||
return response($return_payloads);
|
return response($return_payloads);
|
||||||
}
|
}
|
||||||
ray('Webhook GitHub Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id);
|
|
||||||
}
|
}
|
||||||
$applications = Application::where('git_repository', 'like', "%$full_name%");
|
$applications = Application::where('git_repository', 'like', "%$full_name%");
|
||||||
if ($x_gitlab_event === 'push') {
|
if ($x_gitlab_event === 'push') {
|
||||||
@@ -117,7 +114,6 @@ class Gitlab extends Controller
|
|||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Invalid signature.',
|
'message' => 'Invalid signature.',
|
||||||
]);
|
]);
|
||||||
ray('Invalid signature');
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -128,7 +124,6 @@ class Gitlab extends Controller
|
|||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Server is not functional',
|
'message' => 'Server is not functional',
|
||||||
]);
|
]);
|
||||||
ray('Server is not functional: '.$application->destination->server->name);
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -136,7 +131,6 @@ class Gitlab extends Controller
|
|||||||
if ($application->isDeployable()) {
|
if ($application->isDeployable()) {
|
||||||
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
||||||
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
||||||
ray('Deploying '.$application->name.' with branch '.$branch);
|
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -171,7 +165,6 @@ class Gitlab extends Controller
|
|||||||
'application_uuid' => $application->uuid,
|
'application_uuid' => $application->uuid,
|
||||||
'application_name' => $application->name,
|
'application_name' => $application->name,
|
||||||
]);
|
]);
|
||||||
ray('Deployments disabled for '.$application->name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($x_gitlab_event === 'merge_request') {
|
if ($x_gitlab_event === 'merge_request') {
|
||||||
@@ -207,7 +200,6 @@ class Gitlab extends Controller
|
|||||||
is_webhook: true,
|
is_webhook: true,
|
||||||
git_type: 'gitlab'
|
git_type: 'gitlab'
|
||||||
);
|
);
|
||||||
ray('Deploying preview for '.$application->name.' with branch '.$branch.' and base branch '.$base_branch.' and pull request id '.$pull_request_id);
|
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
'application' => $application->name,
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
@@ -219,7 +211,6 @@ class Gitlab extends Controller
|
|||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Preview deployments disabled',
|
'message' => 'Preview deployments disabled',
|
||||||
]);
|
]);
|
||||||
ray('Preview deployments disabled for '.$application->name);
|
|
||||||
}
|
}
|
||||||
} elseif ($action === 'closed' || $action === 'close' || $action === 'merge') {
|
} elseif ($action === 'closed' || $action === 'close' || $action === 'merge') {
|
||||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||||
@@ -253,8 +244,6 @@ class Gitlab extends Controller
|
|||||||
|
|
||||||
return response($return_payloads);
|
return response($return_payloads);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,6 @@ use App\Models\Webhook;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Sleep;
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Stripe extends Controller
|
class Stripe extends Controller
|
||||||
@@ -22,7 +21,6 @@ class Stripe extends Controller
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (app()->isDownForMaintenance()) {
|
if (app()->isDownForMaintenance()) {
|
||||||
ray('Maintenance mode is on');
|
|
||||||
$epoch = now()->valueOf();
|
$epoch = now()->valueOf();
|
||||||
$data = [
|
$data = [
|
||||||
'attributes' => $request->attributes->all(),
|
'attributes' => $request->attributes->all(),
|
||||||
@@ -65,22 +63,18 @@ class Stripe extends Controller
|
|||||||
$piData = $stripe->paymentIntents->retrieve($pi, []);
|
$piData = $stripe->paymentIntents->retrieve($pi, []);
|
||||||
$customerId = data_get($piData, 'customer');
|
$customerId = data_get($piData, 'customer');
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||||
if (! $subscription) {
|
|
||||||
Sleep::for(5)->seconds();
|
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
|
||||||
}
|
|
||||||
if (! $subscription) {
|
|
||||||
Sleep::for(5)->seconds();
|
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
|
||||||
}
|
|
||||||
if ($subscription) {
|
if ($subscription) {
|
||||||
$subscriptionId = data_get($subscription, 'stripe_subscription_id');
|
$subscriptionId = data_get($subscription, 'stripe_subscription_id');
|
||||||
$stripe->subscriptions->cancel($subscriptionId, []);
|
$stripe->subscriptions->cancel($subscriptionId, []);
|
||||||
$subscription->update([
|
$subscription->update([
|
||||||
'stripe_invoice_paid' => false,
|
'stripe_invoice_paid' => false,
|
||||||
]);
|
]);
|
||||||
|
send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}");
|
||||||
|
} else {
|
||||||
|
send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}");
|
||||||
|
|
||||||
|
return response("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}", 400);
|
||||||
}
|
}
|
||||||
send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}");
|
|
||||||
break;
|
break;
|
||||||
case 'checkout.session.completed':
|
case 'checkout.session.completed':
|
||||||
$clientReferenceId = data_get($data, 'client_reference_id');
|
$clientReferenceId = data_get($data, 'client_reference_id');
|
||||||
@@ -96,7 +90,8 @@ class Stripe extends Controller
|
|||||||
$found = $team->members->where('id', $userId)->first();
|
$found = $team->members->where('id', $userId)->first();
|
||||||
if (! $found->isAdmin()) {
|
if (! $found->isAdmin()) {
|
||||||
send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
|
send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
|
||||||
throw new Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
|
|
||||||
|
return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.", 400);
|
||||||
}
|
}
|
||||||
$subscription = Subscription::where('team_id', $teamId)->first();
|
$subscription = Subscription::where('team_id', $teamId)->first();
|
||||||
if ($subscription) {
|
if ($subscription) {
|
||||||
@@ -124,13 +119,13 @@ class Stripe extends Controller
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||||
if (! $subscription) {
|
if ($subscription) {
|
||||||
Sleep::for(5)->seconds();
|
$subscription->update([
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
'stripe_invoice_paid' => true,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return response("No subscription found for customer: {$customerId}", 400);
|
||||||
}
|
}
|
||||||
$subscription->update([
|
|
||||||
'stripe_invoice_paid' => true,
|
|
||||||
]);
|
|
||||||
break;
|
break;
|
||||||
case 'invoice.payment_failed':
|
case 'invoice.payment_failed':
|
||||||
$customerId = data_get($data, 'customer');
|
$customerId = data_get($data, 'customer');
|
||||||
@@ -168,7 +163,42 @@ class Stripe extends Controller
|
|||||||
}
|
}
|
||||||
send_internal_notification('Subscription payment failed for customer: '.$customerId);
|
send_internal_notification('Subscription payment failed for customer: '.$customerId);
|
||||||
break;
|
break;
|
||||||
|
case 'customer.subscription.created':
|
||||||
|
$customerId = data_get($data, 'customer');
|
||||||
|
$subscriptionId = data_get($data, 'id');
|
||||||
|
$teamId = data_get($data, 'metadata.team_id');
|
||||||
|
$userId = data_get($data, 'metadata.user_id');
|
||||||
|
if (! $teamId || ! $userId) {
|
||||||
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||||
|
if ($subscription) {
|
||||||
|
return response("Subscription already exists for customer: {$customerId}", 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response('No team id or user id found', 400);
|
||||||
|
}
|
||||||
|
$team = Team::find($teamId);
|
||||||
|
$found = $team->members->where('id', $userId)->first();
|
||||||
|
if (! $found->isAdmin()) {
|
||||||
|
send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.");
|
||||||
|
|
||||||
|
return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.", 400);
|
||||||
|
}
|
||||||
|
$subscription = Subscription::where('team_id', $teamId)->first();
|
||||||
|
if ($subscription) {
|
||||||
|
return response("Subscription already exists for team: {$teamId}", 200);
|
||||||
|
} else {
|
||||||
|
Subscription::create([
|
||||||
|
'team_id' => $teamId,
|
||||||
|
'stripe_subscription_id' => $subscriptionId,
|
||||||
|
'stripe_customer_id' => $customerId,
|
||||||
|
'stripe_invoice_paid' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response('Subscription created');
|
||||||
|
}
|
||||||
case 'customer.subscription.updated':
|
case 'customer.subscription.updated':
|
||||||
|
$teamId = data_get($data, 'metadata.team_id');
|
||||||
|
$userId = data_get($data, 'metadata.user_id');
|
||||||
$customerId = data_get($data, 'customer');
|
$customerId = data_get($data, 'customer');
|
||||||
$status = data_get($data, 'status');
|
$status = data_get($data, 'status');
|
||||||
$subscriptionId = data_get($data, 'items.data.0.subscription');
|
$subscriptionId = data_get($data, 'items.data.0.subscription');
|
||||||
@@ -178,32 +208,27 @@ class Stripe extends Controller
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||||
if (! $subscription) {
|
|
||||||
Sleep::for(5)->seconds();
|
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
|
||||||
}
|
|
||||||
if (! $subscription) {
|
if (! $subscription) {
|
||||||
if ($status === 'incomplete_expired') {
|
if ($status === 'incomplete_expired') {
|
||||||
// send_internal_notification('Subscription incomplete expired for customer: '.$customerId);
|
|
||||||
|
|
||||||
return response('Subscription incomplete expired', 200);
|
return response('Subscription incomplete expired', 200);
|
||||||
}
|
}
|
||||||
// send_internal_notification('No subscription found for: '.$customerId);
|
if ($teamId) {
|
||||||
|
$subscription = Subscription::create([
|
||||||
return response('No subscription found', 400);
|
'team_id' => $teamId,
|
||||||
|
'stripe_subscription_id' => $subscriptionId,
|
||||||
|
'stripe_customer_id' => $customerId,
|
||||||
|
'stripe_invoice_paid' => false,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return response('No subscription and team id found', 400);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended');
|
|
||||||
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
|
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
|
||||||
$alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_cancel_at_period_end');
|
|
||||||
$feedback = data_get($data, 'cancellation_details.feedback');
|
$feedback = data_get($data, 'cancellation_details.feedback');
|
||||||
$comment = data_get($data, 'cancellation_details.comment');
|
$comment = data_get($data, 'cancellation_details.comment');
|
||||||
$lookup_key = data_get($data, 'items.data.0.price.lookup_key');
|
$lookup_key = data_get($data, 'items.data.0.price.lookup_key');
|
||||||
if (str($lookup_key)->contains('ultimate') || str($lookup_key)->contains('dynamic')) {
|
if (str($lookup_key)->contains('dynamic')) {
|
||||||
if (str($lookup_key)->contains('dynamic')) {
|
$quantity = data_get($data, 'items.data.0.quantity', 2);
|
||||||
$quantity = data_get($data, 'items.data.0.quantity', 2);
|
|
||||||
} else {
|
|
||||||
$quantity = data_get($data, 'items.data.0.quantity', 10);
|
|
||||||
}
|
|
||||||
$team = data_get($subscription, 'team');
|
$team = data_get($subscription, 'team');
|
||||||
if ($team) {
|
if ($team) {
|
||||||
$team->update([
|
$team->update([
|
||||||
@@ -222,28 +247,12 @@ class Stripe extends Controller
|
|||||||
$subscription->update([
|
$subscription->update([
|
||||||
'stripe_invoice_paid' => false,
|
'stripe_invoice_paid' => false,
|
||||||
]);
|
]);
|
||||||
// send_internal_notification('Subscription paused or incomplete for customer: '.$customerId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trial ended but subscribed, reactive servers
|
|
||||||
if ($trialEndedAlready && $status === 'active') {
|
|
||||||
$team = data_get($subscription, 'team');
|
|
||||||
$team->trialEndedButSubscribed();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($feedback) {
|
if ($feedback) {
|
||||||
$reason = "Cancellation feedback for {$customerId}: '".$feedback."'";
|
$reason = "Cancellation feedback for {$customerId}: '".$feedback."'";
|
||||||
if ($comment) {
|
if ($comment) {
|
||||||
$reason .= ' with comment: \''.$comment."'";
|
$reason .= ' with comment: \''.$comment."'";
|
||||||
}
|
}
|
||||||
// send_internal_notification($reason);
|
|
||||||
}
|
|
||||||
if ($alreadyCancelAtPeriodEnd !== $cancelAtPeriodEnd) {
|
|
||||||
if ($cancelAtPeriodEnd) {
|
|
||||||
// send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id);
|
|
||||||
} else {
|
|
||||||
// send_internal_notification('customer.subscription.updated for customer: '.$customerId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'customer.subscription.deleted':
|
case 'customer.subscription.deleted':
|
||||||
@@ -269,7 +278,7 @@ class Stripe extends Controller
|
|||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
$team = data_get($subscription, 'team');
|
$team = data_get($subscription, 'team');
|
||||||
if (! $team) {
|
if (! $team) {
|
||||||
throw new Exception('No team found for subscription: '.$subscription->id);
|
return response('No team found for subscription: '.$subscription->id, 400);
|
||||||
}
|
}
|
||||||
SubscriptionTrialEndsSoonJob::dispatch($team);
|
SubscriptionTrialEndsSoonJob::dispatch($team);
|
||||||
break;
|
break;
|
||||||
@@ -278,7 +287,7 @@ class Stripe extends Controller
|
|||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
$team = data_get($subscription, 'team');
|
$team = data_get($subscription, 'team');
|
||||||
if (! $team) {
|
if (! $team) {
|
||||||
throw new Exception('No team found for subscription: '.$subscription->id);
|
return response('No team found for subscription: '.$subscription->id, 400);
|
||||||
}
|
}
|
||||||
$team->trialEnded();
|
$team->trialEnded();
|
||||||
$subscription->update([
|
$subscription->update([
|
||||||
|
@@ -13,7 +13,6 @@ class Waitlist extends Controller
|
|||||||
{
|
{
|
||||||
$email = request()->get('email');
|
$email = request()->get('email');
|
||||||
$confirmation_code = request()->get('confirmation_code');
|
$confirmation_code = request()->get('confirmation_code');
|
||||||
ray($email, $confirmation_code);
|
|
||||||
try {
|
try {
|
||||||
$found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first();
|
$found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first();
|
||||||
if ($found) {
|
if ($found) {
|
||||||
@@ -36,7 +35,6 @@ class Waitlist extends Controller
|
|||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
send_internal_notification('Waitlist confirmation failed: '.$e->getMessage());
|
send_internal_notification('Waitlist confirmation failed: '.$e->getMessage());
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
@@ -58,7 +56,6 @@ class Waitlist extends Controller
|
|||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
send_internal_notification('Waitlist cancellation failed: '.$e->getMessage());
|
send_internal_notification('Waitlist cancellation failed: '.$e->getMessage());
|
||||||
ray($e->getMessage());
|
|
||||||
|
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,6 @@ class ApiAllowed
|
|||||||
{
|
{
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
ray()->clearAll();
|
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
@@ -208,7 +208,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$this->container_name = "{$this->application->settings->custom_internal_name}-pr-{$this->pull_request_id}";
|
$this->container_name = "{$this->application->settings->custom_internal_name}-pr-{$this->pull_request_id}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ray('New container name: ', $this->container_name)->green();
|
|
||||||
|
|
||||||
$this->saved_outputs = collect();
|
$this->saved_outputs = collect();
|
||||||
|
|
||||||
@@ -231,7 +230,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$this->application_deployment_queue->update([
|
$this->application_deployment_queue->update([
|
||||||
'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
|
'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
|
||||||
]);
|
]);
|
||||||
if (! $this->server->isFunctional()) {
|
if ($this->server->isFunctional() === false) {
|
||||||
$this->application_deployment_queue->addLogEntry('Server is not functional.');
|
$this->application_deployment_queue->addLogEntry('Server is not functional.');
|
||||||
$this->fail('Server is not functional.');
|
$this->fail('Server is not functional.');
|
||||||
|
|
||||||
@@ -298,7 +297,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
if ($this->pull_request_id !== 0 && $this->application->is_github_based()) {
|
if ($this->pull_request_id !== 0 && $this->application->is_github_based()) {
|
||||||
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::ERROR);
|
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::ERROR);
|
||||||
}
|
}
|
||||||
ray($e);
|
|
||||||
$this->fail($e);
|
$this->fail($e);
|
||||||
throw $e;
|
throw $e;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -389,7 +387,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
} else {
|
} else {
|
||||||
$this->dockerImageTag = $this->application->docker_registry_image_tag;
|
$this->dockerImageTag = $this->application->docker_registry_image_tag;
|
||||||
}
|
}
|
||||||
ray("echo 'Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.'");
|
|
||||||
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.");
|
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.");
|
||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
@@ -712,38 +709,26 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
$forceFail = true;
|
$forceFail = true;
|
||||||
if (str($this->application->docker_registry_image_name)->isEmpty()) {
|
if (str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||||
ray('empty docker_registry_image_name');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->restart_only) {
|
if ($this->restart_only) {
|
||||||
ray('restart_only');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->application->build_pack === 'dockerimage') {
|
if ($this->application->build_pack === 'dockerimage') {
|
||||||
ray('dockerimage');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->use_build_server) {
|
if ($this->use_build_server) {
|
||||||
ray('use_build_server');
|
|
||||||
$forceFail = true;
|
$forceFail = true;
|
||||||
}
|
}
|
||||||
if ($this->server->isSwarm() && $this->build_pack !== 'dockerimage') {
|
if ($this->server->isSwarm() && $this->build_pack !== 'dockerimage') {
|
||||||
ray('isSwarm');
|
|
||||||
$forceFail = true;
|
$forceFail = true;
|
||||||
}
|
}
|
||||||
if ($this->application->additional_servers->count() > 0) {
|
if ($this->application->additional_servers->count() > 0) {
|
||||||
ray('additional_servers');
|
|
||||||
$forceFail = true;
|
$forceFail = true;
|
||||||
}
|
}
|
||||||
if ($this->is_this_additional_server) {
|
if ($this->is_this_additional_server) {
|
||||||
ray('this is an additional_servers, no pushy pushy');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ray('push_to_docker_registry noww: '.$this->production_image_name);
|
|
||||||
try {
|
try {
|
||||||
instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server);
|
instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server);
|
||||||
$this->application_deployment_queue->addLogEntry('----------------------------------------');
|
$this->application_deployment_queue->addLogEntry('----------------------------------------');
|
||||||
@@ -775,7 +760,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
if ($forceFail) {
|
if ($forceFail) {
|
||||||
throw new RuntimeException($e->getMessage(), 69420);
|
throw new RuntimeException($e->getMessage(), 69420);
|
||||||
}
|
}
|
||||||
ray($e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1386,8 +1370,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($destination_ids->contains($this->destination->id)) {
|
if ($destination_ids->contains($this->destination->id)) {
|
||||||
ray('Same destination found in additional destinations. Skipping.');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($destination_ids as $destination_id) {
|
foreach ($destination_ids as $destination_id) {
|
||||||
@@ -1854,7 +1836,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
$custom_compose = convert_docker_run_to_compose($this->application->custom_docker_run_options);
|
$custom_compose = convertDockerRunToCompose($this->application->custom_docker_run_options);
|
||||||
if ((bool) $this->application->settings->is_consistent_container_name_enabled) {
|
if ((bool) $this->application->settings->is_consistent_container_name_enabled) {
|
||||||
if (! $this->application->settings->custom_internal_name) {
|
if (! $this->application->settings->custom_internal_name) {
|
||||||
$docker_compose['services'][$this->application->uuid] = $docker_compose['services'][$this->container_name];
|
$docker_compose['services'][$this->application->uuid] = $docker_compose['services'][$this->container_name];
|
||||||
@@ -2449,7 +2431,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
|
|
||||||
if ($this->application->build_pack !== 'dockercompose') {
|
if ($this->application->build_pack !== 'dockercompose') {
|
||||||
$code = $exception->getCode();
|
$code = $exception->getCode();
|
||||||
ray($code);
|
|
||||||
if ($code !== 69420) {
|
if ($code !== 69420) {
|
||||||
// 69420 means failed to push the image to the registry, so we don't need to remove the new version as it is the currently running one
|
// 69420 means failed to push the image to the registry, so we don't need to remove the new version as it is the currently running one
|
||||||
if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) {
|
if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) {
|
||||||
|
@@ -31,8 +31,6 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ($this->application->is_public_repository()) {
|
if ($this->application->is_public_repository()) {
|
||||||
ray('Public repository. Skipping comment update.');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->status === ProcessStatus::CLOSED) {
|
if ($this->status === ProcessStatus::CLOSED) {
|
||||||
@@ -53,16 +51,12 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
$this->body .= '[Open Build Logs]('.$this->build_logs_url.")\n\n\n";
|
$this->body .= '[Open Build Logs]('.$this->build_logs_url.")\n\n\n";
|
||||||
$this->body .= 'Last updated at: '.now()->toDateTimeString().' CET';
|
$this->body .= 'Last updated at: '.now()->toDateTimeString().' CET';
|
||||||
|
|
||||||
ray('Updating comment', $this->body);
|
|
||||||
if ($this->preview->pull_request_issue_comment_id) {
|
if ($this->preview->pull_request_issue_comment_id) {
|
||||||
$this->update_comment();
|
$this->update_comment();
|
||||||
} else {
|
} else {
|
||||||
$this->create_comment();
|
$this->create_comment();
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e);
|
|
||||||
|
|
||||||
return $e;
|
return $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +67,6 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
'body' => $this->body,
|
'body' => $this->body,
|
||||||
], throwError: false);
|
], throwError: false);
|
||||||
if (data_get($data, 'message') === 'Not Found') {
|
if (data_get($data, 'message') === 'Not Found') {
|
||||||
ray('Comment not found. Creating new one.');
|
|
||||||
$this->create_comment();
|
$this->create_comment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
52
app/Jobs/CheckAndStartSentinelJob.php
Normal file
52
app/Jobs/CheckAndStartSentinelJob.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Actions\Server\StartSentinel;
|
||||||
|
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;
|
||||||
|
|
||||||
|
class CheckAndStartSentinelJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $timeout = 120;
|
||||||
|
|
||||||
|
public function __construct(public Server $server) {}
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
$latestVersion = get_latest_sentinel_version();
|
||||||
|
|
||||||
|
// Check if sentinel is running
|
||||||
|
$sentinelFound = instant_remote_process(['docker inspect coolify-sentinel'], $this->server, false);
|
||||||
|
$sentinelFoundJson = json_decode($sentinelFound, true);
|
||||||
|
$sentinelStatus = data_get($sentinelFoundJson, '0.State.Status', 'exited');
|
||||||
|
if ($sentinelStatus !== 'running') {
|
||||||
|
StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If sentinel is running, check if it needs an update
|
||||||
|
$runningVersion = instant_remote_process(['docker exec coolify-sentinel sh -c "curl http://127.0.0.1:8888/api/version"'], $this->server, false);
|
||||||
|
if (empty($runningVersion)) {
|
||||||
|
$runningVersion = '0.0.0';
|
||||||
|
}
|
||||||
|
if ($latestVersion === '0.0.0' && $runningVersion === '0.0.0') {
|
||||||
|
StartSentinel::run(server: $this->server, restart: true, latestVersion: 'latest');
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (version_compare($runningVersion, $latestVersion, '<')) {
|
||||||
|
StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
app/Jobs/CheckHelperImageJob.php
Normal file
39
app/Jobs/CheckHelperImageJob.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
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\Facades\Http;
|
||||||
|
|
||||||
|
class CheckHelperImageJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $timeout = 1000;
|
||||||
|
|
||||||
|
public function __construct() {}
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
|
||||||
|
if ($response->successful()) {
|
||||||
|
$versions = $response->json();
|
||||||
|
$settings = instanceSettings();
|
||||||
|
$latest_version = data_get($versions, 'coolify.helper.version');
|
||||||
|
$current_version = $settings->helper_version;
|
||||||
|
if (version_compare($latest_version, $current_version, '>')) {
|
||||||
|
$settings->update(['helper_version' => $latest_version]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
send_internal_notification('CheckHelperImageJob failed with: '.$e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -22,7 +22,6 @@ class CheckResaleLicenseJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
CheckResaleLicense::run();
|
CheckResaleLicense::run();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
send_internal_notification('CheckResaleLicenseJob failed with: '.$e->getMessage());
|
send_internal_notification('CheckResaleLicenseJob failed with: '.$e->getMessage());
|
||||||
ray($e);
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,18 +20,15 @@ class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, S
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
ray('Cleaning up helper containers on '.$this->server->name);
|
|
||||||
$containers = instant_remote_process(['docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image | contains("ghcr.io/coollabsio/coolify-helper")))\''], $this->server, false);
|
$containers = instant_remote_process(['docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image | contains("ghcr.io/coollabsio/coolify-helper")))\''], $this->server, false);
|
||||||
$containerIds = collect(json_decode($containers))->pluck('ID');
|
$containerIds = collect(json_decode($containers))->pluck('ID');
|
||||||
if ($containerIds->count() > 0) {
|
if ($containerIds->count() > 0) {
|
||||||
foreach ($containerIds as $containerId) {
|
foreach ($containerIds as $containerId) {
|
||||||
ray('Removing container '.$containerId);
|
|
||||||
instant_remote_process(['docker container rm -f '.$containerId], $this->server, false);
|
instant_remote_process(['docker container rm -f '.$containerId], $this->server, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
send_internal_notification('CleanupHelperContainersJob failed with error: '.$e->getMessage());
|
send_internal_notification('CleanupHelperContainersJob failed with error: '.$e->getMessage());
|
||||||
ray($e->getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user