2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -4,5 +4,5 @@ contact_links:
|
|||||||
url: https://coollabs.io/discord
|
url: https://coollabs.io/discord
|
||||||
about: Reach out to us on Discord.
|
about: Reach out to us on Discord.
|
||||||
- name: 🙋♂️ Feature Requests
|
- name: 🙋♂️ Feature Requests
|
||||||
url: https://github.com/coollabsio/coolify/discussions/categories/feature-requests-ideas
|
url: https://github.com/coollabsio/coolify/discussions/categories/new-features
|
||||||
about: All feature requests will be discussed here.
|
about: All feature requests will be discussed here.
|
||||||
|
81
.github/workflows/pr-build.yml
vendored
Normal file
81
.github/workflows/pr-build.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
name: PR Build (v4)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
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.event.number }}
|
||||||
|
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.event.number }}-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.event.number }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.number }}
|
||||||
|
- uses: sarisia/actions-status-discord@v1
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
|
@@ -31,15 +31,13 @@ class StopApplication
|
|||||||
} else {
|
} else {
|
||||||
$containers = getCurrentApplicationContainerStatus($server, $application->id, 0);
|
$containers = getCurrentApplicationContainerStatus($server, $application->id, 0);
|
||||||
}
|
}
|
||||||
ray($containers);
|
|
||||||
if ($containers->count() > 0) {
|
if ($containers->count() > 0) {
|
||||||
foreach ($containers as $container) {
|
foreach ($containers as $container) {
|
||||||
$containerName = data_get($container, 'Names');
|
$containerName = data_get($container, 'Names');
|
||||||
if ($containerName) {
|
if ($containerName) {
|
||||||
instant_remote_process(
|
instant_remote_process(command: ["docker stop --time=30 $containerName"], server: $server, throwError: false);
|
||||||
["docker rm -f {$containerName}"],
|
instant_remote_process(command: ["docker rm $containerName"], server: $server, throwError: false);
|
||||||
$server
|
instant_remote_process(command: ["docker rm -f {$containerName}"], server: $server, throwError: false);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,10 +22,11 @@ class StopDatabase
|
|||||||
if (! $server->isFunctional()) {
|
if (! $server->isFunctional()) {
|
||||||
return 'Server is not functional';
|
return 'Server is not functional';
|
||||||
}
|
}
|
||||||
instant_remote_process(
|
|
||||||
["docker rm -f {$database->uuid}"],
|
instant_remote_process(command: ["docker stop --time=30 $database->uuid"], server: $server, throwError: false);
|
||||||
$server
|
instant_remote_process(command: ["docker rm $database->uuid"], server: $server, throwError: false);
|
||||||
);
|
instant_remote_process(command: ["docker rm -f $database->uuid"], server: $server, throwError: false);
|
||||||
|
|
||||||
if ($database->is_public) {
|
if ($database->is_public) {
|
||||||
StopDatabaseProxy::run($database);
|
StopDatabaseProxy::run($database);
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ use App\Models\ServiceDatabase;
|
|||||||
use App\Notifications\Container\ContainerRestarted;
|
use App\Notifications\Container\ContainerRestarted;
|
||||||
use App\Notifications\Container\ContainerStopped;
|
use App\Notifications\Container\ContainerStopped;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class GetContainersStatus
|
class GetContainersStatus
|
||||||
@@ -20,13 +21,16 @@ class GetContainersStatus
|
|||||||
|
|
||||||
public $applications;
|
public $applications;
|
||||||
|
|
||||||
|
public ?Collection $containers;
|
||||||
|
|
||||||
|
public ?Collection $containerReplicates;
|
||||||
|
|
||||||
public $server;
|
public $server;
|
||||||
|
|
||||||
public function handle(Server $server)
|
public function handle(Server $server, ?Collection $containers = null, ?Collection $containerReplicates = null)
|
||||||
{
|
{
|
||||||
// if (isDev()) {
|
$this->containers = $containers;
|
||||||
// $server = Server::find(0);
|
$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 ready.';
|
||||||
@@ -66,322 +70,312 @@ class GetContainersStatus
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sentinel()
|
// private function sentinel()
|
||||||
{
|
// {
|
||||||
try {
|
// try {
|
||||||
$containers = $this->server->getContainers();
|
// $this->containers = $this->server->getContainersWithSentinel();
|
||||||
if ($containers->count() === 0) {
|
// if ($this->containers->count() === 0) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
$databases = $this->server->databases();
|
// $databases = $this->server->databases();
|
||||||
$services = $this->server->services()->get();
|
// $services = $this->server->services()->get();
|
||||||
$previews = $this->server->previews();
|
// $previews = $this->server->previews();
|
||||||
$foundApplications = [];
|
// $foundApplications = [];
|
||||||
$foundApplicationPreviews = [];
|
// $foundApplicationPreviews = [];
|
||||||
$foundDatabases = [];
|
// $foundDatabases = [];
|
||||||
$foundServices = [];
|
// $foundServices = [];
|
||||||
|
|
||||||
foreach ($containers as $container) {
|
// foreach ($this->containers as $container) {
|
||||||
$labels = Arr::undot(data_get($container, 'labels'));
|
// $labels = Arr::undot(data_get($container, 'labels'));
|
||||||
$containerStatus = data_get($container, 'state');
|
// $containerStatus = data_get($container, 'state');
|
||||||
$containerHealth = data_get($container, 'health_status', 'unhealthy');
|
// $containerHealth = data_get($container, 'health_status', 'unhealthy');
|
||||||
$containerStatus = "$containerStatus ($containerHealth)";
|
// $containerStatus = "$containerStatus ($containerHealth)";
|
||||||
$applicationId = data_get($labels, 'coolify.applicationId');
|
// $applicationId = data_get($labels, 'coolify.applicationId');
|
||||||
if ($applicationId) {
|
// if ($applicationId) {
|
||||||
$pullRequestId = data_get($labels, 'coolify.pullRequestId');
|
// $pullRequestId = data_get($labels, 'coolify.pullRequestId');
|
||||||
if ($pullRequestId) {
|
// if ($pullRequestId) {
|
||||||
if (str($applicationId)->contains('-')) {
|
// if (str($applicationId)->contains('-')) {
|
||||||
$applicationId = str($applicationId)->before('-');
|
// $applicationId = str($applicationId)->before('-');
|
||||||
}
|
// }
|
||||||
$preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
// $preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
||||||
if ($preview) {
|
// if ($preview) {
|
||||||
$foundApplicationPreviews[] = $preview->id;
|
// $foundApplicationPreviews[] = $preview->id;
|
||||||
$statusFromDb = $preview->status;
|
// $statusFromDb = $preview->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
// if ($statusFromDb !== $containerStatus) {
|
||||||
$preview->update(['status' => $containerStatus]);
|
// $preview->update(['status' => $containerStatus]);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
//Notify user that this container should not be there.
|
// //Notify user that this container should not be there.
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
$application = $this->applications->where('id', $applicationId)->first();
|
// $application = $this->applications->where('id', $applicationId)->first();
|
||||||
if ($application) {
|
// if ($application) {
|
||||||
$foundApplications[] = $application->id;
|
// $foundApplications[] = $application->id;
|
||||||
$statusFromDb = $application->status;
|
// $statusFromDb = $application->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
// if ($statusFromDb !== $containerStatus) {
|
||||||
$application->update(['status' => $containerStatus]);
|
// $application->update(['status' => $containerStatus]);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
//Notify user that this container should not be there.
|
// //Notify user that this container should not be there.
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
$uuid = data_get($labels, 'com.docker.compose.service');
|
// $uuid = data_get($labels, 'com.docker.compose.service');
|
||||||
$type = data_get($labels, 'coolify.type');
|
// $type = data_get($labels, 'coolify.type');
|
||||||
if ($uuid) {
|
// if ($uuid) {
|
||||||
if ($type === 'service') {
|
// if ($type === 'service') {
|
||||||
$database_id = data_get($labels, 'coolify.service.subId');
|
// $database_id = data_get($labels, 'coolify.service.subId');
|
||||||
if ($database_id) {
|
// if ($database_id) {
|
||||||
$service_db = ServiceDatabase::where('id', $database_id)->first();
|
// $service_db = ServiceDatabase::where('id', $database_id)->first();
|
||||||
if ($service_db) {
|
// if ($service_db) {
|
||||||
$uuid = $service_db->service->uuid;
|
// $uuid = $service_db->service->uuid;
|
||||||
$isPublic = data_get($service_db, 'is_public');
|
// $isPublic = data_get($service_db, 'is_public');
|
||||||
if ($isPublic) {
|
// if ($isPublic) {
|
||||||
$foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) {
|
// $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||||
if ($this->server->isSwarm()) {
|
// if ($this->server->isSwarm()) {
|
||||||
// TODO: fix this with sentinel
|
// // TODO: fix this with sentinel
|
||||||
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
// return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||||
} else {
|
// } else {
|
||||||
return data_get($value, 'name') === "$uuid-proxy";
|
// return data_get($value, 'name') === "$uuid-proxy";
|
||||||
}
|
// }
|
||||||
})->first();
|
// })->first();
|
||||||
if (! $foundTcpProxy) {
|
// if (! $foundTcpProxy) {
|
||||||
StartDatabaseProxy::run($service_db);
|
// StartDatabaseProxy::run($service_db);
|
||||||
// $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
|
// // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
$database = $databases->where('uuid', $uuid)->first();
|
// $database = $databases->where('uuid', $uuid)->first();
|
||||||
if ($database) {
|
// if ($database) {
|
||||||
$isPublic = data_get($database, 'is_public');
|
// $isPublic = data_get($database, 'is_public');
|
||||||
$foundDatabases[] = $database->id;
|
// $foundDatabases[] = $database->id;
|
||||||
$statusFromDb = $database->status;
|
// $statusFromDb = $database->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
// if ($statusFromDb !== $containerStatus) {
|
||||||
$database->update(['status' => $containerStatus]);
|
// $database->update(['status' => $containerStatus]);
|
||||||
}
|
// }
|
||||||
if ($isPublic) {
|
// if ($isPublic) {
|
||||||
$foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) {
|
// $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||||
if ($this->server->isSwarm()) {
|
// if ($this->server->isSwarm()) {
|
||||||
// TODO: fix this with sentinel
|
// // TODO: fix this with sentinel
|
||||||
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
// return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||||
} else {
|
// } else {
|
||||||
return data_get($value, 'name') === "$uuid-proxy";
|
// return data_get($value, 'name') === "$uuid-proxy";
|
||||||
}
|
// }
|
||||||
})->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 {
|
||||||
// Notify user that this container should not be there.
|
// // Notify user that this container should not be there.
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if (data_get($container, 'name') === 'coolify-db') {
|
// if (data_get($container, 'name') === 'coolify-db') {
|
||||||
$foundDatabases[] = 0;
|
// $foundDatabases[] = 0;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$serviceLabelId = data_get($labels, 'coolify.serviceId');
|
// $serviceLabelId = data_get($labels, 'coolify.serviceId');
|
||||||
if ($serviceLabelId) {
|
// if ($serviceLabelId) {
|
||||||
$subType = data_get($labels, 'coolify.service.subType');
|
// $subType = data_get($labels, 'coolify.service.subType');
|
||||||
$subId = data_get($labels, 'coolify.service.subId');
|
// $subId = data_get($labels, 'coolify.service.subId');
|
||||||
$service = $services->where('id', $serviceLabelId)->first();
|
// $service = $services->where('id', $serviceLabelId)->first();
|
||||||
if (! $service) {
|
// if (! $service) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
if ($subType === 'application') {
|
// if ($subType === 'application') {
|
||||||
$service = $service->applications()->where('id', $subId)->first();
|
// $service = $service->applications()->where('id', $subId)->first();
|
||||||
} else {
|
// } else {
|
||||||
$service = $service->databases()->where('id', $subId)->first();
|
// $service = $service->databases()->where('id', $subId)->first();
|
||||||
}
|
// }
|
||||||
if ($service) {
|
// if ($service) {
|
||||||
$foundServices[] = "$service->id-$service->name";
|
// $foundServices[] = "$service->id-$service->name";
|
||||||
$statusFromDb = $service->status;
|
// $statusFromDb = $service->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
// if ($statusFromDb !== $containerStatus) {
|
||||||
// ray('Updating status: ' . $containerStatus);
|
// // ray('Updating status: ' . $containerStatus);
|
||||||
$service->update(['status' => $containerStatus]);
|
// $service->update(['status' => $containerStatus]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$exitedServices = collect([]);
|
// $exitedServices = collect([]);
|
||||||
foreach ($services as $service) {
|
// foreach ($services as $service) {
|
||||||
$apps = $service->applications()->get();
|
// $apps = $service->applications()->get();
|
||||||
$dbs = $service->databases()->get();
|
// $dbs = $service->databases()->get();
|
||||||
foreach ($apps as $app) {
|
// foreach ($apps as $app) {
|
||||||
if (in_array("$app->id-$app->name", $foundServices)) {
|
// if (in_array("$app->id-$app->name", $foundServices)) {
|
||||||
continue;
|
// continue;
|
||||||
} else {
|
// } else {
|
||||||
$exitedServices->push($app);
|
// $exitedServices->push($app);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
foreach ($dbs as $db) {
|
// foreach ($dbs as $db) {
|
||||||
if (in_array("$db->id-$db->name", $foundServices)) {
|
// if (in_array("$db->id-$db->name", $foundServices)) {
|
||||||
continue;
|
// continue;
|
||||||
} else {
|
// } else {
|
||||||
$exitedServices->push($db);
|
// $exitedServices->push($db);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$exitedServices = $exitedServices->unique('id');
|
// $exitedServices = $exitedServices->unique('id');
|
||||||
foreach ($exitedServices as $exitedService) {
|
// foreach ($exitedServices as $exitedService) {
|
||||||
if (str($exitedService->status)->startsWith('exited')) {
|
// if (str($exitedService->status)->startsWith('exited')) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
$name = data_get($exitedService, 'name');
|
// $name = data_get($exitedService, 'name');
|
||||||
$fqdn = data_get($exitedService, 'fqdn');
|
// $fqdn = data_get($exitedService, 'fqdn');
|
||||||
if ($name) {
|
// if ($name) {
|
||||||
if ($fqdn) {
|
// if ($fqdn) {
|
||||||
$containerName = "$name, available at $fqdn";
|
// $containerName = "$name, available at $fqdn";
|
||||||
} else {
|
// } else {
|
||||||
$containerName = $name;
|
// $containerName = $name;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if ($fqdn) {
|
// if ($fqdn) {
|
||||||
$containerName = $fqdn;
|
// $containerName = $fqdn;
|
||||||
} else {
|
// } else {
|
||||||
$containerName = null;
|
// $containerName = null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$projectUuid = data_get($service, 'environment.project.uuid');
|
// $projectUuid = data_get($service, 'environment.project.uuid');
|
||||||
$serviceUuid = data_get($service, 'uuid');
|
// $serviceUuid = data_get($service, 'uuid');
|
||||||
$environmentName = data_get($service, 'environment.name');
|
// $environmentName = data_get($service, 'environment.name');
|
||||||
|
|
||||||
if ($projectUuid && $serviceUuid && $environmentName) {
|
// if ($projectUuid && $serviceUuid && $environmentName) {
|
||||||
$url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/service/'.$serviceUuid;
|
// $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/service/'.$serviceUuid;
|
||||||
} else {
|
// } else {
|
||||||
$url = null;
|
// $url = null;
|
||||||
}
|
// }
|
||||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
// // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
$exitedService->update(['status' => 'exited']);
|
// $exitedService->update(['status' => 'exited']);
|
||||||
}
|
// }
|
||||||
|
|
||||||
$notRunningApplications = $this->applications->pluck('id')->diff($foundApplications);
|
// $notRunningApplications = $this->applications->pluck('id')->diff($foundApplications);
|
||||||
foreach ($notRunningApplications as $applicationId) {
|
// foreach ($notRunningApplications as $applicationId) {
|
||||||
$application = $this->applications->where('id', $applicationId)->first();
|
// $application = $this->applications->where('id', $applicationId)->first();
|
||||||
if (str($application->status)->startsWith('exited')) {
|
// if (str($application->status)->startsWith('exited')) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
$application->update(['status' => 'exited']);
|
// $application->update(['status' => 'exited']);
|
||||||
|
|
||||||
$name = data_get($application, 'name');
|
// $name = data_get($application, 'name');
|
||||||
$fqdn = data_get($application, 'fqdn');
|
// $fqdn = data_get($application, 'fqdn');
|
||||||
|
|
||||||
$containerName = $name ? "$name ($fqdn)" : $fqdn;
|
// $containerName = $name ? "$name ($fqdn)" : $fqdn;
|
||||||
|
|
||||||
$projectUuid = data_get($application, 'environment.project.uuid');
|
// $projectUuid = data_get($application, 'environment.project.uuid');
|
||||||
$applicationUuid = data_get($application, 'uuid');
|
// $applicationUuid = data_get($application, 'uuid');
|
||||||
$environment = data_get($application, 'environment.name');
|
// $environment = data_get($application, 'environment.name');
|
||||||
|
|
||||||
if ($projectUuid && $applicationUuid && $environment) {
|
// if ($projectUuid && $applicationUuid && $environment) {
|
||||||
$url = base_url().'/project/'.$projectUuid.'/'.$environment.'/application/'.$applicationUuid;
|
// $url = base_url().'/project/'.$projectUuid.'/'.$environment.'/application/'.$applicationUuid;
|
||||||
} else {
|
// } else {
|
||||||
$url = null;
|
// $url = null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
// // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
}
|
// }
|
||||||
$notRunningApplicationPreviews = $previews->pluck('id')->diff($foundApplicationPreviews);
|
// $notRunningApplicationPreviews = $previews->pluck('id')->diff($foundApplicationPreviews);
|
||||||
foreach ($notRunningApplicationPreviews as $previewId) {
|
// foreach ($notRunningApplicationPreviews as $previewId) {
|
||||||
$preview = $previews->where('id', $previewId)->first();
|
// $preview = $previews->where('id', $previewId)->first();
|
||||||
if (str($preview->status)->startsWith('exited')) {
|
// if (str($preview->status)->startsWith('exited')) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
$preview->update(['status' => 'exited']);
|
// $preview->update(['status' => 'exited']);
|
||||||
|
|
||||||
$name = data_get($preview, 'name');
|
// $name = data_get($preview, 'name');
|
||||||
$fqdn = data_get($preview, 'fqdn');
|
// $fqdn = data_get($preview, 'fqdn');
|
||||||
|
|
||||||
$containerName = $name ? "$name ($fqdn)" : $fqdn;
|
// $containerName = $name ? "$name ($fqdn)" : $fqdn;
|
||||||
|
|
||||||
$projectUuid = data_get($preview, 'application.environment.project.uuid');
|
// $projectUuid = data_get($preview, 'application.environment.project.uuid');
|
||||||
$environmentName = data_get($preview, 'application.environment.name');
|
// $environmentName = data_get($preview, 'application.environment.name');
|
||||||
$applicationUuid = data_get($preview, 'application.uuid');
|
// $applicationUuid = data_get($preview, 'application.uuid');
|
||||||
|
|
||||||
if ($projectUuid && $applicationUuid && $environmentName) {
|
// if ($projectUuid && $applicationUuid && $environmentName) {
|
||||||
$url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/application/'.$applicationUuid;
|
// $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/application/'.$applicationUuid;
|
||||||
} else {
|
// } else {
|
||||||
$url = null;
|
// $url = null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
// // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
}
|
// }
|
||||||
$notRunningDatabases = $databases->pluck('id')->diff($foundDatabases);
|
// $notRunningDatabases = $databases->pluck('id')->diff($foundDatabases);
|
||||||
foreach ($notRunningDatabases as $database) {
|
// foreach ($notRunningDatabases as $database) {
|
||||||
$database = $databases->where('id', $database)->first();
|
// $database = $databases->where('id', $database)->first();
|
||||||
if (str($database->status)->startsWith('exited')) {
|
// if (str($database->status)->startsWith('exited')) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
$database->update(['status' => 'exited']);
|
// $database->update(['status' => 'exited']);
|
||||||
|
|
||||||
$name = data_get($database, 'name');
|
// $name = data_get($database, 'name');
|
||||||
$fqdn = data_get($database, 'fqdn');
|
// $fqdn = data_get($database, 'fqdn');
|
||||||
|
|
||||||
$containerName = $name;
|
// $containerName = $name;
|
||||||
|
|
||||||
$projectUuid = data_get($database, 'environment.project.uuid');
|
// $projectUuid = data_get($database, 'environment.project.uuid');
|
||||||
$environmentName = data_get($database, 'environment.name');
|
// $environmentName = data_get($database, 'environment.name');
|
||||||
$databaseUuid = data_get($database, 'uuid');
|
// $databaseUuid = data_get($database, 'uuid');
|
||||||
|
|
||||||
if ($projectUuid && $databaseUuid && $environmentName) {
|
// if ($projectUuid && $databaseUuid && $environmentName) {
|
||||||
$url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid;
|
// $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid;
|
||||||
} else {
|
// } else {
|
||||||
$url = null;
|
// $url = null;
|
||||||
}
|
// }
|
||||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
// // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Check if proxy is running
|
// // Check if proxy is running
|
||||||
$this->server->proxyType();
|
// $this->server->proxyType();
|
||||||
$foundProxyContainer = $containers->filter(function ($value, $key) {
|
// $foundProxyContainer = $this->containers->filter(function ($value, $key) {
|
||||||
if ($this->server->isSwarm()) {
|
// if ($this->server->isSwarm()) {
|
||||||
// TODO: fix this with sentinel
|
// // TODO: fix this with sentinel
|
||||||
return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';
|
// return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';
|
||||||
} else {
|
// } else {
|
||||||
return data_get($value, 'name') === 'coolify-proxy';
|
// return data_get($value, 'name') === 'coolify-proxy';
|
||||||
}
|
// }
|
||||||
})->first();
|
// })->first();
|
||||||
if (! $foundProxyContainer) {
|
// if (! $foundProxyContainer) {
|
||||||
try {
|
// try {
|
||||||
$shouldStart = CheckProxy::run($this->server);
|
// $shouldStart = CheckProxy::run($this->server);
|
||||||
if ($shouldStart) {
|
// if ($shouldStart) {
|
||||||
StartProxy::run($this->server, false);
|
// StartProxy::run($this->server, false);
|
||||||
$this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
|
// $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
|
||||||
}
|
// }
|
||||||
} catch (\Throwable $e) {
|
// } catch (\Throwable $e) {
|
||||||
ray($e);
|
// ray($e);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
$this->server->proxy->status = data_get($foundProxyContainer, 'state');
|
// $this->server->proxy->status = data_get($foundProxyContainer, 'state');
|
||||||
$this->server->save();
|
// $this->server->save();
|
||||||
$connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
|
// $connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
|
||||||
instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
|
// instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
|
||||||
}
|
// }
|
||||||
} catch (\Exception $e) {
|
// } catch (\Exception $e) {
|
||||||
// send_internal_notification("ContainerStatusJob failed on ({$this->server->id}) with: " . $e->getMessage());
|
// // send_internal_notification("ContainerStatusJob failed on ({$this->server->id}) with: " . $e->getMessage());
|
||||||
ray($e->getMessage());
|
// ray($e->getMessage());
|
||||||
|
|
||||||
return handleError($e);
|
// return handleError($e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private function old_way()
|
private function old_way()
|
||||||
{
|
{
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->containers === null) {
|
||||||
$containers = instant_remote_process(["docker service inspect $(docker service ls -q) --format '{{json .}}'"], $this->server, false);
|
['containers' => $this->containers,'containerReplicates' => $this->containerReplicates] = $this->server->getContainers();
|
||||||
$containerReplicates = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false);
|
|
||||||
} else {
|
|
||||||
// Precheck for containers
|
|
||||||
$containers = instant_remote_process(['docker container ls -q'], $this->server, false);
|
|
||||||
if (! $containers) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server, false);
|
|
||||||
$containerReplicates = null;
|
|
||||||
}
|
}
|
||||||
if (is_null($containers)) {
|
|
||||||
|
if (is_null($this->containers)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$containers = format_docker_command_output_to_json($containers);
|
if ($this->containerReplicates) {
|
||||||
if ($containerReplicates) {
|
foreach ($this->containerReplicates as $containerReplica) {
|
||||||
$containerReplicates = format_docker_command_output_to_json($containerReplicates);
|
|
||||||
foreach ($containerReplicates as $containerReplica) {
|
|
||||||
$name = data_get($containerReplica, 'Name');
|
$name = data_get($containerReplica, 'Name');
|
||||||
$containers = $containers->map(function ($container) use ($name, $containerReplica) {
|
$this->containers = $this->containers->map(function ($container) use ($name, $containerReplica) {
|
||||||
if (data_get($container, 'Spec.Name') === $name) {
|
if (data_get($container, 'Spec.Name') === $name) {
|
||||||
$replicas = data_get($containerReplica, 'Replicas');
|
$replicas = data_get($containerReplica, 'Replicas');
|
||||||
$running = str($replicas)->explode('/')[0];
|
$running = str($replicas)->explode('/')[0];
|
||||||
@@ -407,7 +401,7 @@ class GetContainersStatus
|
|||||||
$foundDatabases = [];
|
$foundDatabases = [];
|
||||||
$foundServices = [];
|
$foundServices = [];
|
||||||
|
|
||||||
foreach ($containers as $container) {
|
foreach ($this->containers as $container) {
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
$labels = data_get($container, 'Spec.Labels');
|
$labels = data_get($container, 'Spec.Labels');
|
||||||
$uuid = data_get($labels, 'coolify.name');
|
$uuid = data_get($labels, 'coolify.name');
|
||||||
@@ -461,7 +455,7 @@ class GetContainersStatus
|
|||||||
if ($uuid) {
|
if ($uuid) {
|
||||||
$isPublic = data_get($service_db, 'is_public');
|
$isPublic = data_get($service_db, 'is_public');
|
||||||
if ($isPublic) {
|
if ($isPublic) {
|
||||||
$foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) {
|
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||||
} else {
|
} else {
|
||||||
@@ -486,7 +480,7 @@ class GetContainersStatus
|
|||||||
$database->update(['status' => $containerStatus]);
|
$database->update(['status' => $containerStatus]);
|
||||||
}
|
}
|
||||||
if ($isPublic) {
|
if ($isPublic) {
|
||||||
$foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) {
|
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||||
} else {
|
} else {
|
||||||
@@ -659,7 +653,7 @@ class GetContainersStatus
|
|||||||
|
|
||||||
// Check if proxy is running
|
// Check if proxy is running
|
||||||
$this->server->proxyType();
|
$this->server->proxyType();
|
||||||
$foundProxyContainer = $containers->filter(function ($value, $key) {
|
$foundProxyContainer = $this->containers->filter(function ($value, $key) {
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';
|
return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';
|
||||||
} else {
|
} else {
|
||||||
|
@@ -11,7 +11,6 @@ class CleanupDocker
|
|||||||
|
|
||||||
public function handle(Server $server, bool $force = true)
|
public function handle(Server $server, bool $force = true)
|
||||||
{
|
{
|
||||||
|
|
||||||
// cleanup docker images, containers, and builder caches
|
// cleanup docker images, containers, and builder caches
|
||||||
if ($force) {
|
if ($force) {
|
||||||
instant_remote_process(['docker image prune -af'], $server, false);
|
instant_remote_process(['docker image prune -af'], $server, false);
|
||||||
@@ -22,15 +21,5 @@ class CleanupDocker
|
|||||||
instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $server, false);
|
instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $server, false);
|
||||||
instant_remote_process(['docker builder prune -f'], $server, false);
|
instant_remote_process(['docker builder prune -f'], $server, false);
|
||||||
}
|
}
|
||||||
// cleanup networks
|
|
||||||
// $networks = collectDockerNetworksByServer($server);
|
|
||||||
// $proxyNetworks = collectProxyDockerNetworksByServer($server);
|
|
||||||
// $diff = $proxyNetworks->diff($networks);
|
|
||||||
// if ($diff->count() > 0) {
|
|
||||||
// $diff->map(function ($network) use ($server) {
|
|
||||||
// instant_remote_process(["docker network disconnect $network coolify-proxy"], $server);
|
|
||||||
// instant_remote_process(["docker network rm $network"], $server);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,12 +24,7 @@ class InstallLogDrain
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if ($type === 'none') {
|
if ($type === 'none') {
|
||||||
$command = [
|
return 'No log drain is enabled.';
|
||||||
"echo 'Stopping old Fluent Bit'",
|
|
||||||
'docker rm -f coolify-log-drain || true',
|
|
||||||
];
|
|
||||||
|
|
||||||
return instant_remote_process($command, $server);
|
|
||||||
} elseif ($type === 'newrelic') {
|
} elseif ($type === 'newrelic') {
|
||||||
if (! $server->settings->is_logdrain_newrelic_enabled) {
|
if (! $server->settings->is_logdrain_newrelic_enabled) {
|
||||||
throw new \Exception('New Relic log drain is not enabled.');
|
throw new \Exception('New Relic log drain is not enabled.');
|
||||||
|
20
app/Actions/Server/StopLogDrain.php
Normal file
20
app/Actions/Server/StopLogDrain.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class StopLogDrain
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(Server $server)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return instant_remote_process(['docker rm -f coolify-log-drain || true'], $server);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -20,7 +20,6 @@ class UpdateCoolify
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$settings = InstanceSettings::get();
|
$settings = InstanceSettings::get();
|
||||||
ray('Running InstanceAutoUpdateJob');
|
|
||||||
$this->server = Server::find(0);
|
$this->server = Server::find(0);
|
||||||
if (! $this->server) {
|
if (! $this->server) {
|
||||||
return;
|
return;
|
||||||
@@ -48,7 +47,6 @@ class UpdateCoolify
|
|||||||
private function update()
|
private function update()
|
||||||
{
|
{
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
ray('Running in dev mode');
|
|
||||||
remote_process([
|
remote_process([
|
||||||
'sleep 10',
|
'sleep 10',
|
||||||
], $this->server);
|
], $this->server);
|
||||||
|
@@ -19,18 +19,21 @@ class StopService
|
|||||||
ray('Stopping service: '.$service->name);
|
ray('Stopping service: '.$service->name);
|
||||||
$applications = $service->applications()->get();
|
$applications = $service->applications()->get();
|
||||||
foreach ($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server, false);
|
instant_remote_process(command: ["docker stop --time=30 {$application->name}-{$service->uuid}"], server: $server, throwError: false);
|
||||||
|
instant_remote_process(command: ["docker rm {$application->name}-{$service->uuid}"], server: $server, throwError: false);
|
||||||
|
instant_remote_process(command: ["docker rm -f {$application->name}-{$service->uuid}"], server: $server, throwError: false);
|
||||||
$application->update(['status' => 'exited']);
|
$application->update(['status' => 'exited']);
|
||||||
}
|
}
|
||||||
$dbs = $service->databases()->get();
|
$dbs = $service->databases()->get();
|
||||||
foreach ($dbs as $db) {
|
foreach ($dbs as $db) {
|
||||||
instant_remote_process(["docker rm -f {$db->name}-{$service->uuid}"], $service->server, false);
|
instant_remote_process(command: ["docker stop --time=30 {$db->name}-{$service->uuid}"], server: $server, throwError: false);
|
||||||
|
instant_remote_process(command: ["docker rm {$db->name}-{$service->uuid}"], server: $server, throwError: false);
|
||||||
|
instant_remote_process(command: ["docker rm -f {$db->name}-{$service->uuid}"], server: $server, throwError: false);
|
||||||
$db->update(['status' => 'exited']);
|
$db->update(['status' => 'exited']);
|
||||||
}
|
}
|
||||||
instant_remote_process(["docker network disconnect {$service->uuid} coolify-proxy"], $service->server);
|
instant_remote_process(["docker network disconnect {$service->uuid} coolify-proxy"], $service->server);
|
||||||
instant_remote_process(["docker network rm {$service->uuid}"], $service->server);
|
instant_remote_process(["docker network rm {$service->uuid}"], $service->server);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
echo $e->getMessage();
|
|
||||||
ray($e->getMessage());
|
ray($e->getMessage());
|
||||||
|
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
|
@@ -18,7 +18,12 @@ class CleanupDatabase extends Command
|
|||||||
} else {
|
} else {
|
||||||
echo "Running database cleanup in dry-run mode...\n";
|
echo "Running database cleanup in dry-run mode...\n";
|
||||||
}
|
}
|
||||||
$keep_days = 60;
|
if (isCloud()) {
|
||||||
|
// Later on we can increase this to 180 days or dynamically set
|
||||||
|
$keep_days = 60;
|
||||||
|
} else {
|
||||||
|
$keep_days = 60;
|
||||||
|
}
|
||||||
echo "Keep days: $keep_days\n";
|
echo "Keep days: $keep_days\n";
|
||||||
// Cleanup failed jobs table
|
// Cleanup failed jobs table
|
||||||
$failed_jobs = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(1));
|
$failed_jobs = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(1));
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Actions\Server\StopSentinel;
|
use App\Actions\Server\StopSentinel;
|
||||||
|
use App\Enums\ActivityTypes;
|
||||||
use App\Enums\ApplicationDeploymentStatus;
|
use App\Enums\ApplicationDeploymentStatus;
|
||||||
use App\Jobs\CleanupHelperContainersJob;
|
use App\Jobs\CleanupHelperContainersJob;
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
@@ -12,22 +13,27 @@ use App\Models\ScheduledDatabaseBackup;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
class Init extends Command
|
class Init extends Command
|
||||||
{
|
{
|
||||||
protected $signature = 'app:init {--full-cleanup} {--cleanup-deployments}';
|
protected $signature = 'app:init {--full-cleanup} {--cleanup-deployments} {--cleanup-proxy-networks}';
|
||||||
|
|
||||||
protected $description = 'Cleanup instance related stuffs';
|
protected $description = 'Cleanup instance related stuffs';
|
||||||
|
|
||||||
|
public $servers = null;
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
$this->servers = Server::all();
|
||||||
$this->alive();
|
$this->alive();
|
||||||
get_public_ips();
|
get_public_ips();
|
||||||
if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
|
if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
|
||||||
$servers = Server::all();
|
foreach ($this->servers as $server) {
|
||||||
foreach ($servers as $server) {
|
if ($server->settings->is_metrics_enabled === true) {
|
||||||
$server->settings->update(['is_metrics_enabled' => false]);
|
$server->settings->update(['is_metrics_enabled' => false]);
|
||||||
|
}
|
||||||
if ($server->isFunctional()) {
|
if ($server->isFunctional()) {
|
||||||
StopSentinel::dispatch($server);
|
StopSentinel::dispatch($server);
|
||||||
}
|
}
|
||||||
@@ -36,7 +42,7 @@ class Init extends Command
|
|||||||
|
|
||||||
$full_cleanup = $this->option('full-cleanup');
|
$full_cleanup = $this->option('full-cleanup');
|
||||||
$cleanup_deployments = $this->option('cleanup-deployments');
|
$cleanup_deployments = $this->option('cleanup-deployments');
|
||||||
|
$cleanup_proxy_networks = $this->option('cleanup-proxy-networks');
|
||||||
$this->replace_slash_in_environment_name();
|
$this->replace_slash_in_environment_name();
|
||||||
if ($cleanup_deployments) {
|
if ($cleanup_deployments) {
|
||||||
echo "Running cleanup deployments.\n";
|
echo "Running cleanup deployments.\n";
|
||||||
@@ -44,17 +50,26 @@ class Init extends Command
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ($cleanup_proxy_networks) {
|
||||||
|
echo "Running cleanup proxy networks.\n";
|
||||||
|
$this->cleanup_unused_network_from_coolify_proxy();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ($full_cleanup) {
|
if ($full_cleanup) {
|
||||||
// Required for falsely deleted coolify db
|
// Required for falsely deleted coolify db
|
||||||
$this->restore_coolify_db_backup();
|
$this->restore_coolify_db_backup();
|
||||||
|
$this->update_traefik_labels();
|
||||||
|
$this->cleanup_unused_network_from_coolify_proxy();
|
||||||
|
$this->cleanup_unnecessary_dynamic_proxy_configuration();
|
||||||
$this->cleanup_in_progress_application_deployments();
|
$this->cleanup_in_progress_application_deployments();
|
||||||
$this->cleanup_stucked_helper_containers();
|
$this->cleanup_stucked_helper_containers();
|
||||||
$this->call('cleanup:queue');
|
$this->call('cleanup:queue');
|
||||||
$this->call('cleanup:stucked-resources');
|
$this->call('cleanup:stucked-resources');
|
||||||
if (! isCloud()) {
|
if (! isCloud()) {
|
||||||
try {
|
try {
|
||||||
$server = Server::find(0)->first();
|
$localhost = $this->servers->where('id', 0)->first();
|
||||||
$server->setupDynamicProxyConfiguration();
|
$localhost->setupDynamicProxyConfiguration();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
|
echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
|
||||||
}
|
}
|
||||||
@@ -68,6 +83,13 @@ class Init extends Command
|
|||||||
$settings->update(['is_auto_update_enabled' => false]);
|
$settings->update(['is_auto_update_enabled' => false]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isCloud()) {
|
||||||
|
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
|
||||||
|
if ($response->successful()) {
|
||||||
|
$services = $response->json();
|
||||||
|
File::put(base_path('templates/service-templates.json'), json_encode($services));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -75,6 +97,79 @@ class Init extends Command
|
|||||||
$this->call('cleanup:stucked-resources');
|
$this->call('cleanup:stucked-resources');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function update_traefik_labels()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Server::where('proxy->type', 'TRAEFIK_V2')->update(['proxy->type' => 'TRAEFIK']);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
echo "Error in updating traefik labels: {$e->getMessage()}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanup_unnecessary_dynamic_proxy_configuration()
|
||||||
|
{
|
||||||
|
if (isCloud()) {
|
||||||
|
foreach ($this->servers as $server) {
|
||||||
|
try {
|
||||||
|
if (! $server->isFunctional()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($server->id === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$file = $server->proxyPath().'/dynamic/coolify.yaml';
|
||||||
|
|
||||||
|
return instant_remote_process([
|
||||||
|
"rm -f $file",
|
||||||
|
], $server, false);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanup_unused_network_from_coolify_proxy()
|
||||||
|
{
|
||||||
|
foreach ($this->servers as $server) {
|
||||||
|
if (! $server->isFunctional()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (! $server->isProxyShouldRun()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
['networks' => $networks, 'allNetworks' => $allNetworks] = collectDockerNetworksByServer($server);
|
||||||
|
$removeNetworks = $allNetworks->diff($networks);
|
||||||
|
$commands = collect();
|
||||||
|
foreach ($removeNetworks as $network) {
|
||||||
|
$out = instant_remote_process(["docker network inspect -f json $network | jq '.[].Containers | if . == {} then null else . end'"], $server, false);
|
||||||
|
if (empty($out)) {
|
||||||
|
$commands->push("docker network disconnect $network coolify-proxy >/dev/null 2>&1 || true");
|
||||||
|
$commands->push("docker network rm $network >/dev/null 2>&1 || true");
|
||||||
|
} else {
|
||||||
|
$data = collect(json_decode($out, true));
|
||||||
|
if ($data->count() === 1) {
|
||||||
|
// If only coolify-proxy itself is connected to that network (it should not be possible, but who knows)
|
||||||
|
$isCoolifyProxyItself = data_get($data->first(), 'Name') === 'coolify-proxy';
|
||||||
|
if ($isCoolifyProxyItself) {
|
||||||
|
$commands->push("docker network disconnect $network coolify-proxy >/dev/null 2>&1 || true");
|
||||||
|
$commands->push("docker network rm $network >/dev/null 2>&1 || true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($commands->isNotEmpty()) {
|
||||||
|
echo "Cleaning up unused networks from coolify proxy\n";
|
||||||
|
remote_process(command: $commands, type: ActivityTypes::INLINE->value, server: $server, ignore_errors: false);
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
echo "Error in cleaning up unused networks from coolify proxy: {$e->getMessage()}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function restore_coolify_db_backup()
|
private function restore_coolify_db_backup()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -102,8 +197,7 @@ class Init extends Command
|
|||||||
|
|
||||||
private function cleanup_stucked_helper_containers()
|
private function cleanup_stucked_helper_containers()
|
||||||
{
|
{
|
||||||
$servers = Server::all();
|
foreach ($this->servers as $server) {
|
||||||
foreach ($servers as $server) {
|
|
||||||
if ($server->isFunctional()) {
|
if ($server->isFunctional()) {
|
||||||
CleanupHelperContainersJob::dispatch($server);
|
CleanupHelperContainersJob::dispatch($server);
|
||||||
}
|
}
|
||||||
@@ -148,7 +242,6 @@ class Init extends Command
|
|||||||
private function cleanup_in_progress_application_deployments()
|
private function cleanup_in_progress_application_deployments()
|
||||||
{
|
{
|
||||||
// Cleanup any failed deployments
|
// Cleanup any failed deployments
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
return;
|
return;
|
||||||
|
@@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
use App\Jobs\CheckLogDrainContainerJob;
|
use App\Jobs\CheckForUpdatesJob;
|
||||||
use App\Jobs\CleanupInstanceStuffsJob;
|
use App\Jobs\CleanupInstanceStuffsJob;
|
||||||
use App\Jobs\ContainerStatusJob;
|
|
||||||
use App\Jobs\DatabaseBackupJob;
|
use App\Jobs\DatabaseBackupJob;
|
||||||
use App\Jobs\DockerCleanupJob;
|
use App\Jobs\DockerCleanupJob;
|
||||||
use App\Jobs\PullCoolifyImageJob;
|
use App\Jobs\PullCoolifyImageJob;
|
||||||
@@ -12,7 +11,9 @@ use App\Jobs\PullHelperImageJob;
|
|||||||
use App\Jobs\PullSentinelImageJob;
|
use App\Jobs\PullSentinelImageJob;
|
||||||
use App\Jobs\PullTemplatesFromCDN;
|
use App\Jobs\PullTemplatesFromCDN;
|
||||||
use App\Jobs\ScheduledTaskJob;
|
use App\Jobs\ScheduledTaskJob;
|
||||||
use App\Jobs\ServerStatusJob;
|
use App\Jobs\ServerCheckJob;
|
||||||
|
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;
|
||||||
@@ -27,25 +28,26 @@ class Kernel extends ConsoleKernel
|
|||||||
protected function schedule(Schedule $schedule): void
|
protected function schedule(Schedule $schedule): void
|
||||||
{
|
{
|
||||||
$this->all_servers = Server::all();
|
$this->all_servers = Server::all();
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
|
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
// 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 PullTemplatesFromCDN)->everyTwoHours()->onOneServer();
|
|
||||||
// Server Jobs
|
// Server Jobs
|
||||||
$this->check_scheduled_backups($schedule);
|
$this->check_scheduled_backups($schedule);
|
||||||
$this->check_resources($schedule);
|
$this->check_resources($schedule);
|
||||||
$this->check_scheduled_backups($schedule);
|
|
||||||
$this->check_scheduled_tasks($schedule);
|
$this->check_scheduled_tasks($schedule);
|
||||||
$schedule->command('uploads:clear')->everyTwoMinutes();
|
$schedule->command('uploads:clear')->everyTwoMinutes();
|
||||||
} else {
|
} else {
|
||||||
// Instance Jobs
|
// Instance Jobs
|
||||||
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||||
$schedule->command('cleanup:unreachable-servers')->daily();
|
$schedule->command('cleanup:unreachable-servers')->daily();
|
||||||
$schedule->job(new PullCoolifyImageJob)->everyTenMinutes()->onOneServer();
|
$schedule->job(new PullCoolifyImageJob)->cron($settings->update_check_frequency)->onOneServer();
|
||||||
$schedule->job(new PullTemplatesFromCDN)->everyThirtyMinutes()->onOneServer();
|
$schedule->job(new PullTemplatesFromCDN)->cron($settings->update_check_frequency)->onOneServer();
|
||||||
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
||||||
// $schedule->job(new CheckResaleLicenseJob)->hourly()->onOneServer();
|
$this->schedule_updates($schedule);
|
||||||
|
|
||||||
// Server Jobs
|
// Server Jobs
|
||||||
$this->check_scheduled_backups($schedule);
|
$this->check_scheduled_backups($schedule);
|
||||||
@@ -60,12 +62,26 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
private function pull_images($schedule)
|
private function pull_images($schedule)
|
||||||
{
|
{
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
$servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
|
$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(new PullSentinelImageJob($server))->everyFiveMinutes()->onOneServer();
|
$schedule->job(new PullSentinelImageJob($server))->cron($settings->update_check_frequency)->onOneServer();
|
||||||
}
|
}
|
||||||
$schedule->job(new PullHelperImageJob($server))->everyFiveMinutes()->onOneServer();
|
$schedule->job(new PullHelperImageJob($server))->cron($settings->update_check_frequency)->onOneServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function schedule_updates($schedule)
|
||||||
|
{
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
|
|
||||||
|
$updateCheckFrequency = $settings->update_check_frequency;
|
||||||
|
$schedule->job(new CheckForUpdatesJob)->cron($updateCheckFrequency)->onOneServer();
|
||||||
|
|
||||||
|
if ($settings->is_auto_update_enabled) {
|
||||||
|
$autoUpdateFrequency = $settings->auto_update_frequency;
|
||||||
|
$schedule->job(new UpdateCoolifyJob)->cron($autoUpdateFrequency)->onOneServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,19 +91,11 @@ class Kernel extends ConsoleKernel
|
|||||||
$servers = $this->all_servers->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended', false)->where('ip', '!=', '1.2.3.4');
|
$servers = $this->all_servers->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended', false)->where('ip', '!=', '1.2.3.4');
|
||||||
$own = Team::find(0)->servers;
|
$own = Team::find(0)->servers;
|
||||||
$servers = $servers->merge($own);
|
$servers = $servers->merge($own);
|
||||||
$containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false);
|
|
||||||
} else {
|
} else {
|
||||||
$servers = $this->all_servers->where('ip', '!=', '1.2.3.4');
|
$servers = $this->all_servers->where('ip', '!=', '1.2.3.4');
|
||||||
$containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false);
|
|
||||||
}
|
|
||||||
foreach ($containerServers as $server) {
|
|
||||||
$schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer();
|
|
||||||
if ($server->isLogDrainEnabled()) {
|
|
||||||
$schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
$schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer();
|
$schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer();
|
||||||
$schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->onOneServer();
|
$schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->onOneServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@ namespace App\Enums;
|
|||||||
enum ProxyTypes: string
|
enum ProxyTypes: string
|
||||||
{
|
{
|
||||||
case NONE = 'NONE';
|
case NONE = 'NONE';
|
||||||
case TRAEFIK_V2 = 'TRAEFIK_V2';
|
case TRAEFIK = 'TRAEFIK';
|
||||||
case NGINX = 'NGINX';
|
case NGINX = 'NGINX';
|
||||||
case CADDY = 'CADDY';
|
case CADDY = 'CADDY';
|
||||||
}
|
}
|
||||||
|
32
app/Events/FileStorageChanged.php
Normal file
32
app/Events/FileStorageChanged.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?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 FileStorageChanged implements ShouldBroadcast
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
public $teamId;
|
||||||
|
|
||||||
|
public function __construct($teamId = null)
|
||||||
|
{
|
||||||
|
ray($teamId);
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
throw new \Exception('Team id is null');
|
||||||
|
}
|
||||||
|
$this->teamId = $teamId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function broadcastOn(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new PrivateChannel("team.{$this->teamId}"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -739,7 +739,7 @@ class ApplicationsController extends Controller
|
|||||||
$application->isConfigurationChanged(true);
|
$application->isConfigurationChanged(true);
|
||||||
|
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -835,7 +835,7 @@ class ApplicationsController extends Controller
|
|||||||
$application->isConfigurationChanged(true);
|
$application->isConfigurationChanged(true);
|
||||||
|
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -927,7 +927,7 @@ class ApplicationsController extends Controller
|
|||||||
$application->isConfigurationChanged(true);
|
$application->isConfigurationChanged(true);
|
||||||
|
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -947,7 +947,7 @@ class ApplicationsController extends Controller
|
|||||||
]));
|
]));
|
||||||
} elseif ($type === 'dockerfile') {
|
} elseif ($type === 'dockerfile') {
|
||||||
if (! $request->has('name')) {
|
if (! $request->has('name')) {
|
||||||
$request->offsetSet('name', 'dockerfile-'.new Cuid2(7));
|
$request->offsetSet('name', 'dockerfile-'.new Cuid2);
|
||||||
}
|
}
|
||||||
$validator = customApiValidator($request->all(), [
|
$validator = customApiValidator($request->all(), [
|
||||||
sharedDataApplications(),
|
sharedDataApplications(),
|
||||||
@@ -1009,7 +1009,7 @@ class ApplicationsController extends Controller
|
|||||||
$application->isConfigurationChanged(true);
|
$application->isConfigurationChanged(true);
|
||||||
|
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -1025,7 +1025,7 @@ class ApplicationsController extends Controller
|
|||||||
]));
|
]));
|
||||||
} elseif ($type === 'dockerimage') {
|
} elseif ($type === 'dockerimage') {
|
||||||
if (! $request->has('name')) {
|
if (! $request->has('name')) {
|
||||||
$request->offsetSet('name', 'docker-image-'.new Cuid2(7));
|
$request->offsetSet('name', 'docker-image-'.new Cuid2);
|
||||||
}
|
}
|
||||||
$validator = customApiValidator($request->all(), [
|
$validator = customApiValidator($request->all(), [
|
||||||
sharedDataApplications(),
|
sharedDataApplications(),
|
||||||
@@ -1067,7 +1067,7 @@ class ApplicationsController extends Controller
|
|||||||
$application->isConfigurationChanged(true);
|
$application->isConfigurationChanged(true);
|
||||||
|
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -1099,7 +1099,7 @@ class ApplicationsController extends Controller
|
|||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
if (! $request->has('name')) {
|
if (! $request->has('name')) {
|
||||||
$request->offsetSet('name', 'service'.new Cuid2(7));
|
$request->offsetSet('name', 'service'.new Cuid2);
|
||||||
}
|
}
|
||||||
$validator = customApiValidator($request->all(), [
|
$validator = customApiValidator($request->all(), [
|
||||||
sharedDataApplications(),
|
sharedDataApplications(),
|
||||||
@@ -1320,7 +1320,7 @@ class ApplicationsController extends Controller
|
|||||||
#[OA\Patch(
|
#[OA\Patch(
|
||||||
summary: 'Update',
|
summary: 'Update',
|
||||||
description: 'Update application by UUID.',
|
description: 'Update application by UUID.',
|
||||||
path: '/applications',
|
path: '/applications/{uuid}',
|
||||||
security: [
|
security: [
|
||||||
['bearerAuth' => []],
|
['bearerAuth' => []],
|
||||||
],
|
],
|
||||||
@@ -2322,7 +2322,7 @@ class ApplicationsController extends Controller
|
|||||||
return response()->json(['message' => 'Application not found.'], 404);
|
return response()->json(['message' => 'Application not found.'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
@@ -2479,7 +2479,7 @@ class ApplicationsController extends Controller
|
|||||||
return response()->json(['message' => 'Application not found.'], 404);
|
return response()->json(['message' => 'Application not found.'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
|
@@ -84,7 +84,7 @@ class DeployController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Deployments'],
|
tags: ['Deployments'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Deployment Uuid', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Deployment Uuid', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
@@ -290,7 +290,7 @@ class DeployController extends Controller
|
|||||||
}
|
}
|
||||||
switch ($resource?->getMorphClass()) {
|
switch ($resource?->getMorphClass()) {
|
||||||
case 'App\Models\Application':
|
case 'App\Models\Application':
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $resource,
|
application: $resource,
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
|
@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Api;
|
|||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
|
|
||||||
#[OA\Info(title: 'Coolify', version: '0.1')]
|
#[OA\Info(title: 'Coolify', version: '0.1')]
|
||||||
#[OA\Server(url: 'https://app.coolify.io/api/v1')]
|
#[OA\Server(url: 'https://app.coolify.io/api/v1', description: 'Coolify Cloud API. Change the host to your own instance if you are self-hosting.')]
|
||||||
#[OA\SecurityScheme(
|
#[OA\SecurityScheme(
|
||||||
type: 'http',
|
type: 'http',
|
||||||
scheme: 'bearer',
|
scheme: 'bearer',
|
||||||
|
@@ -61,7 +61,7 @@ class ProjectController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Projects'],
|
tags: ['Projects'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Project UUID', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Project UUID', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
@@ -107,7 +107,7 @@ class ProjectController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Projects'],
|
tags: ['Projects'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Project UUID', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Project UUID', schema: new OA\Schema(type: 'string')),
|
||||||
new OA\Parameter(name: 'environment_name', in: 'path', required: true, description: 'Environment name', schema: new OA\Schema(type: 'string')),
|
new OA\Parameter(name: 'environment_name', in: 'path', required: true, description: 'Environment name', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
|
@@ -73,7 +73,7 @@ class SecurityController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Private Keys'],
|
tags: ['Private Keys'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key Uuid', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key Uuid', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
@@ -318,7 +318,7 @@ class SecurityController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Private Keys'],
|
tags: ['Private Keys'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key Uuid', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key Uuid', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
|
@@ -105,7 +105,7 @@ class ServersController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Servers'],
|
tags: ['Servers'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
@@ -182,7 +182,7 @@ class ServersController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Servers'],
|
tags: ['Servers'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
@@ -259,7 +259,7 @@ class ServersController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Servers'],
|
tags: ['Servers'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
@@ -525,7 +525,7 @@ class ServersController extends Controller
|
|||||||
'private_key_id' => $privateKey->id,
|
'private_key_id' => $privateKey->id,
|
||||||
'team_id' => $teamId,
|
'team_id' => $teamId,
|
||||||
'proxy' => [
|
'proxy' => [
|
||||||
'type' => ProxyTypes::TRAEFIK_V2->value,
|
'type' => ProxyTypes::TRAEFIK->value,
|
||||||
'status' => ProxyStatus::EXITED->value,
|
'status' => ProxyStatus::EXITED->value,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
@@ -732,7 +732,7 @@ class ServersController extends Controller
|
|||||||
],
|
],
|
||||||
tags: ['Servers'],
|
tags: ['Servers'],
|
||||||
parameters: [
|
parameters: [
|
||||||
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server UUID', schema: new OA\Schema(type: 'integer')),
|
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server UUID', schema: new OA\Schema(type: 'string')),
|
||||||
],
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
|
@@ -413,6 +413,8 @@ class ServicesController extends Controller
|
|||||||
return response()->json(['message' => 'Service not found.'], 404);
|
return response()->json(['message' => 'Service not found.'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$service = $service->load(['applications', 'databases']);
|
||||||
|
|
||||||
return response()->json($this->removeSensitiveData($service));
|
return response()->json($this->removeSensitiveData($service));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -103,7 +103,7 @@ class Bitbucket extends Controller
|
|||||||
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);
|
ray('Deploying '.$application->name.' with branch '.$branch);
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
@@ -127,7 +127,7 @@ 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);
|
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(7);
|
$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) {
|
||||||
if ($application->build_pack === 'dockercompose') {
|
if ($application->build_pack === 'dockercompose') {
|
||||||
|
@@ -123,7 +123,7 @@ class Gitea extends Controller
|
|||||||
$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);
|
ray('Deploying '.$application->name.' with branch '.$branch);
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
@@ -162,7 +162,7 @@ class Gitea extends Controller
|
|||||||
if ($x_gitea_event === 'pull_request') {
|
if ($x_gitea_event === 'pull_request') {
|
||||||
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
||||||
if ($application->isPRDeployable()) {
|
if ($application->isPRDeployable()) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$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) {
|
||||||
if ($application->build_pack === 'dockercompose') {
|
if ($application->build_pack === 'dockercompose') {
|
||||||
|
@@ -128,7 +128,7 @@ class Github extends Controller
|
|||||||
$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);
|
ray('Deploying '.$application->name.' with branch '.$branch);
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
@@ -167,7 +167,7 @@ class Github extends Controller
|
|||||||
if ($x_github_event === 'pull_request') {
|
if ($x_github_event === 'pull_request') {
|
||||||
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
||||||
if ($application->isPRDeployable()) {
|
if ($application->isPRDeployable()) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$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) {
|
||||||
if ($application->build_pack === 'dockercompose') {
|
if ($application->build_pack === 'dockercompose') {
|
||||||
@@ -357,7 +357,7 @@ class Github extends Controller
|
|||||||
$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);
|
ray('Deploying '.$application->name.' with branch '.$branch);
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
@@ -396,7 +396,7 @@ class Github extends Controller
|
|||||||
if ($x_github_event === 'pull_request') {
|
if ($x_github_event === 'pull_request') {
|
||||||
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
||||||
if ($application->isPRDeployable()) {
|
if ($application->isPRDeployable()) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$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) {
|
||||||
ApplicationPreview::create([
|
ApplicationPreview::create([
|
||||||
|
@@ -137,7 +137,7 @@ class Gitlab extends Controller
|
|||||||
$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);
|
ray('Deploying '.$application->name.' with branch '.$branch);
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
@@ -177,7 +177,7 @@ class Gitlab extends Controller
|
|||||||
if ($x_gitlab_event === 'merge_request') {
|
if ($x_gitlab_event === 'merge_request') {
|
||||||
if ($action === 'open' || $action === 'opened' || $action === 'synchronize' || $action === 'reopened' || $action === 'reopen' || $action === 'update') {
|
if ($action === 'open' || $action === 'opened' || $action === 'synchronize' || $action === 'reopened' || $action === 'reopen' || $action === 'update') {
|
||||||
if ($application->isPRDeployable()) {
|
if ($application->isPRDeployable()) {
|
||||||
$deployment_uuid = new Cuid2(7);
|
$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) {
|
||||||
if ($application->build_pack === 'dockercompose') {
|
if ($application->build_pack === 'dockercompose') {
|
||||||
|
@@ -307,14 +307,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// $this->execute_remote_command(
|
|
||||||
// [
|
|
||||||
// "docker image prune -f >/dev/null 2>&1",
|
|
||||||
// "hidden" => true,
|
|
||||||
// "ignore_errors" => true,
|
|
||||||
// ]
|
|
||||||
// );
|
|
||||||
|
|
||||||
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,13 +489,13 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
} else {
|
} else {
|
||||||
$this->write_deployment_configurations();
|
$this->write_deployment_configurations();
|
||||||
$server_workdir = $this->application->workdir();
|
$server_workdir = $this->application->workdir();
|
||||||
|
$this->docker_compose_location = '/docker-compose.yaml';
|
||||||
|
|
||||||
$command = "{$this->coolify_variables} docker compose";
|
$command = "{$this->coolify_variables} docker compose";
|
||||||
if ($this->env_filename) {
|
if ($this->env_filename) {
|
||||||
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
$command .= " --env-file {$server_workdir}/{$this->env_filename}";
|
||||||
}
|
}
|
||||||
$command .= " --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
|
$command .= " --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
|
||||||
|
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
['command' => $command, 'hidden' => true],
|
['command' => $command, 'hidden' => true],
|
||||||
);
|
);
|
||||||
@@ -636,21 +628,26 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$this->server = $this->original_server;
|
$this->server = $this->original_server;
|
||||||
}
|
}
|
||||||
$readme = generate_readme_file($this->application->name, $this->application_deployment_queue->updated_at);
|
$readme = generate_readme_file($this->application->name, $this->application_deployment_queue->updated_at);
|
||||||
|
|
||||||
|
$mainDir = $this->configuration_dir;
|
||||||
|
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
||||||
|
$mainDir = $this->application->workdir();
|
||||||
|
}
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
$composeFileName = "$this->configuration_dir/docker-compose.yaml";
|
$composeFileName = "$mainDir/docker-compose.yaml";
|
||||||
} else {
|
} else {
|
||||||
$composeFileName = "$this->configuration_dir/docker-compose-pr-{$this->pull_request_id}.yaml";
|
$composeFileName = "$mainDir/docker-compose-pr-{$this->pull_request_id}.yaml";
|
||||||
$this->docker_compose_location = "/docker-compose-pr-{$this->pull_request_id}.yaml";
|
$this->docker_compose_location = "/docker-compose-pr-{$this->pull_request_id}.yaml";
|
||||||
}
|
}
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
"mkdir -p $this->configuration_dir",
|
"mkdir -p $mainDir",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"echo '{$this->docker_compose_base64}' | base64 -d | tee $composeFileName > /dev/null",
|
"echo '{$this->docker_compose_base64}' | base64 -d | tee $composeFileName > /dev/null",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"echo '{$readme}' > $this->configuration_dir/README.md",
|
"echo '{$readme}' > $mainDir/README.md",
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
if ($this->use_build_server) {
|
if ($this->use_build_server) {
|
||||||
@@ -874,8 +871,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$envs->push($env->key.'='.$real_value);
|
$envs->push($env->key.'='.$real_value);
|
||||||
}
|
}
|
||||||
// Add PORT if not exists, use the first port as default
|
// Add PORT if not exists, use the first port as default
|
||||||
if ($this->application->environment_variables_preview->where('key', 'PORT')->isEmpty()) {
|
if ($this->build_pack !== 'dockercompose') {
|
||||||
$envs->push("PORT={$ports[0]}");
|
if ($this->application->environment_variables_preview->where('key', 'PORT')->isEmpty()) {
|
||||||
|
$envs->push("PORT={$ports[0]}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Add HOST if not exists
|
// Add HOST if not exists
|
||||||
if ($this->application->environment_variables_preview->where('key', 'HOST')->isEmpty()) {
|
if ($this->application->environment_variables_preview->where('key', 'HOST')->isEmpty()) {
|
||||||
@@ -918,15 +917,16 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$envs->push($env->key.'='.$real_value);
|
$envs->push($env->key.'='.$real_value);
|
||||||
}
|
}
|
||||||
// Add PORT if not exists, use the first port as default
|
// Add PORT if not exists, use the first port as default
|
||||||
if ($this->application->environment_variables->where('key', 'PORT')->isEmpty()) {
|
if ($this->build_pack !== 'dockercompose') {
|
||||||
$envs->push("PORT={$ports[0]}");
|
if ($this->application->environment_variables->where('key', 'PORT')->isEmpty()) {
|
||||||
|
$envs->push("PORT={$ports[0]}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Add HOST if not exists
|
// Add HOST if not exists
|
||||||
if ($this->application->environment_variables->where('key', 'HOST')->isEmpty()) {
|
if ($this->application->environment_variables->where('key', 'HOST')->isEmpty()) {
|
||||||
$envs->push('HOST=0.0.0.0');
|
$envs->push('HOST=0.0.0.0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($envs->isEmpty()) {
|
if ($envs->isEmpty()) {
|
||||||
$this->env_filename = null;
|
$this->env_filename = null;
|
||||||
if ($this->use_build_server) {
|
if ($this->use_build_server) {
|
||||||
@@ -1025,7 +1025,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$this->write_deployment_configurations();
|
$this->write_deployment_configurations();
|
||||||
$this->server = $this->original_server;
|
$this->server = $this->original_server;
|
||||||
}
|
}
|
||||||
if (count($this->application->ports_mappings_array) > 0 || (bool) $this->application->settings->is_consistent_container_name_enabled || isset($this->application->settings->custom_internal_name) || $this->pull_request_id !== 0 || str($this->application->custom_docker_run_options)->contains('--ip') || str($this->application->custom_docker_run_options)->contains('--ip6')) {
|
if (count($this->application->ports_mappings_array) > 0 || (bool) $this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty() || $this->pull_request_id !== 0 || str($this->application->custom_docker_run_options)->contains('--ip') || str($this->application->custom_docker_run_options)->contains('--ip6')) {
|
||||||
$this->application_deployment_queue->addLogEntry('----------------------------------------');
|
$this->application_deployment_queue->addLogEntry('----------------------------------------');
|
||||||
if (count($this->application->ports_mappings_array) > 0) {
|
if (count($this->application->ports_mappings_array) > 0) {
|
||||||
$this->application_deployment_queue->addLogEntry('Application has ports mapped to the host system, rolling update is not supported.');
|
$this->application_deployment_queue->addLogEntry('Application has ports mapped to the host system, rolling update is not supported.');
|
||||||
@@ -2027,27 +2027,43 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
$this->application_deployment_queue->addLogEntry('Building docker image completed.');
|
$this->application_deployment_queue->addLogEntry('Building docker image completed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $timeout in seconds
|
||||||
|
*/
|
||||||
|
private function graceful_shutdown_container(string $containerName, int $timeout = 30)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->execute_remote_command(
|
||||||
|
["docker stop --time=$timeout $containerName", 'hidden' => true, 'ignore_errors' => true],
|
||||||
|
["docker rm $containerName", 'hidden' => true, 'ignore_errors' => true]
|
||||||
|
);
|
||||||
|
} catch (\Exception $error) {
|
||||||
|
// report error if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->execute_remote_command(
|
||||||
|
["docker rm -f $containerName", 'hidden' => true, 'ignore_errors' => true]
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private function stop_running_container(bool $force = false)
|
private function stop_running_container(bool $force = false)
|
||||||
{
|
{
|
||||||
$this->application_deployment_queue->addLogEntry('Removing old containers.');
|
$this->application_deployment_queue->addLogEntry('Removing old containers.');
|
||||||
if ($this->newVersionIsHealthy || $force) {
|
if ($this->newVersionIsHealthy || $force) {
|
||||||
$containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id);
|
if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) {
|
||||||
if ($this->pull_request_id === 0) {
|
$this->graceful_shutdown_container($this->container_name);
|
||||||
$containers = $containers->filter(function ($container) {
|
} else {
|
||||||
return data_get($container, 'Names') !== $this->container_name && data_get($container, 'Names') !== $this->container_name.'-pr-'.$this->pull_request_id;
|
$containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id);
|
||||||
|
if ($this->pull_request_id === 0) {
|
||||||
|
$containers = $containers->filter(function ($container) {
|
||||||
|
return data_get($container, 'Names') !== $this->container_name && data_get($container, 'Names') !== $this->container_name.'-pr-'.$this->pull_request_id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$containers->each(function ($container) {
|
||||||
|
$this->graceful_shutdown_container(data_get($container, 'Names'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$containers->each(function ($container) {
|
|
||||||
$containerName = data_get($container, 'Names');
|
|
||||||
$this->execute_remote_command(
|
|
||||||
["docker rm -f $containerName >/dev/null 2>&1", 'hidden' => true, 'ignore_errors' => true],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if ($this->application->settings->is_consistent_container_name_enabled || isset($this->application->settings->custom_internal_name)) {
|
|
||||||
$this->execute_remote_command(
|
|
||||||
["docker rm -f $this->container_name >/dev/null 2>&1", 'hidden' => true, 'ignore_errors' => true],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if ($this->application->dockerfile || $this->application->build_pack === 'dockerfile' || $this->application->build_pack === 'dockerimage') {
|
if ($this->application->dockerfile || $this->application->build_pack === 'dockerfile' || $this->application->build_pack === 'dockerimage') {
|
||||||
$this->application_deployment_queue->addLogEntry('----------------------------------------');
|
$this->application_deployment_queue->addLogEntry('----------------------------------------');
|
||||||
@@ -2058,9 +2074,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
$this->application_deployment_queue->update([
|
$this->application_deployment_queue->update([
|
||||||
'status' => ApplicationDeploymentStatus::FAILED->value,
|
'status' => ApplicationDeploymentStatus::FAILED->value,
|
||||||
]);
|
]);
|
||||||
$this->execute_remote_command(
|
$this->graceful_shutdown_container($this->container_name);
|
||||||
["docker rm -f $this->container_name >/dev/null 2>&1", 'hidden' => true, 'ignore_errors' => true],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2235,7 +2249,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
ray($code);
|
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 || isset($this->application->settings->custom_internal_name)) {
|
if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) {
|
||||||
// do not remove already running container
|
// do not remove already running container
|
||||||
} else {
|
} else {
|
||||||
$this->application_deployment_queue->addLogEntry('Deployment failed. Removing the new version of your application.', 'stderr');
|
$this->application_deployment_queue->addLogEntry('Deployment failed. Removing the new version of your application.', 'stderr');
|
||||||
|
42
app/Jobs/CheckForUpdatesJob.php
Normal file
42
app/Jobs/CheckForUpdatesJob.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
|
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 CheckForUpdatesJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (isDev() || isCloud()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
|
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
|
||||||
|
if ($response->successful()) {
|
||||||
|
$versions = $response->json();
|
||||||
|
$latest_version = data_get($versions, 'coolify.v4.version');
|
||||||
|
$current_version = config('version');
|
||||||
|
|
||||||
|
if (version_compare($latest_version, $current_version, '>')) {
|
||||||
|
// New version available
|
||||||
|
$settings->update(['new_version_available' => true]);
|
||||||
|
} else {
|
||||||
|
$settings->update(['new_version_available' => false]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// Consider implementing a notification to administrators
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -90,6 +90,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
BackupCreated::dispatch($this->team->id);
|
BackupCreated::dispatch($this->team->id);
|
||||||
|
|
||||||
// Check if team is exists
|
// Check if team is exists
|
||||||
if (is_null($this->team)) {
|
if (is_null($this->team)) {
|
||||||
$this->backup->update(['status' => 'failed']);
|
$this->backup->update(['status' => 'failed']);
|
||||||
@@ -476,7 +477,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
} else {
|
} else {
|
||||||
$network = $this->database->destination->network;
|
$network = $this->database->destination->network;
|
||||||
}
|
}
|
||||||
$commands[] = "docker run --pull=always -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $this->backup_location:$this->backup_location:ro ghcr.io/coollabsio/coolify-helper";
|
$commands[] = "docker run -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $this->backup_location:$this->backup_location:ro ghcr.io/coollabsio/coolify-helper";
|
||||||
$commands[] = "docker exec backup-of-{$this->backup->uuid} mc config host add temporary {$endpoint} $key $secret";
|
$commands[] = "docker exec backup-of-{$this->backup->uuid} mc config host add temporary {$endpoint} $key $secret";
|
||||||
$commands[] = "docker exec backup-of-{$this->backup->uuid} mc cp $this->backup_location temporary/$bucket{$this->backup_dir}/";
|
$commands[] = "docker exec backup-of-{$this->backup->uuid} mc cp $this->backup_location temporary/$bucket{$this->backup_dir}/";
|
||||||
instant_remote_process($commands, $this->server);
|
instant_remote_process($commands, $this->server);
|
||||||
|
@@ -26,17 +26,6 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// $isInprogress = false;
|
|
||||||
// $this->server->applications()->each(function ($application) use (&$isInprogress) {
|
|
||||||
// if ($application->isDeploymentInprogress()) {
|
|
||||||
// $isInprogress = true;
|
|
||||||
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// if ($isInprogress) {
|
|
||||||
// throw new RuntimeException('DockerCleanupJob: ApplicationDeploymentQueue is not empty, skipping...');
|
|
||||||
// }
|
|
||||||
if (! $this->server->isFunctional()) {
|
if (! $this->server->isFunctional()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -48,6 +37,12 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->usageBefore = $this->server->getDiskUsage();
|
$this->usageBefore = $this->server->getDiskUsage();
|
||||||
|
if (str($this->usageBefore)->isEmpty() || $this->usageBefore === null || $this->usageBefore === 0) {
|
||||||
|
Log::info('DockerCleanupJob force cleanup on '.$this->server->name);
|
||||||
|
CleanupDocker::run(server: $this->server, force: true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) {
|
if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) {
|
||||||
CleanupDocker::run(server: $this->server, force: false);
|
CleanupDocker::run(server: $this->server, force: false);
|
||||||
$usageAfter = $this->server->getDiskUsage();
|
$usageAfter = $this->server->getDiskUsage();
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
@@ -16,16 +17,13 @@ class PullCoolifyImageJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
public $timeout = 1000;
|
|
||||||
|
|
||||||
public function __construct() {}
|
|
||||||
|
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (isDev() || isCloud()) {
|
if (isDev() || isCloud()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
$server = Server::findOrFail(0);
|
$server = Server::findOrFail(0);
|
||||||
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
|
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
|
||||||
if ($response->successful()) {
|
if ($response->successful()) {
|
||||||
@@ -35,7 +33,6 @@ class PullCoolifyImageJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$latest_version = get_latest_version_of_coolify();
|
$latest_version = get_latest_version_of_coolify();
|
||||||
instant_remote_process(["docker pull -q ghcr.io/coollabsio/coolify:{$latest_version}"], $server, false);
|
instant_remote_process(["docker pull -q ghcr.io/coollabsio/coolify:{$latest_version}"], $server, false);
|
||||||
|
|
||||||
$settings = \App\Models\InstanceSettings::get();
|
|
||||||
$current_version = config('version');
|
$current_version = config('version');
|
||||||
if (! $settings->is_auto_update_enabled) {
|
if (! $settings->is_auto_update_enabled) {
|
||||||
return;
|
return;
|
||||||
@@ -46,10 +43,6 @@ class PullCoolifyImageJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
if (version_compare($latest_version, $current_version, '<')) {
|
if (version_compare($latest_version, $current_version, '<')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instant_remote_process([
|
|
||||||
'curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh',
|
|
||||||
"bash /data/coolify/source/upgrade.sh $latest_version",
|
|
||||||
], $server);
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
@@ -22,15 +22,16 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (! isDev()) {
|
if (isDev() || isCloud()) {
|
||||||
ray('PullTemplatesAndVersions service-templates');
|
return;
|
||||||
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
|
}
|
||||||
if ($response->successful()) {
|
ray('PullTemplatesAndVersions service-templates');
|
||||||
$services = $response->json();
|
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
|
||||||
File::put(base_path('templates/service-templates.json'), json_encode($services));
|
if ($response->successful()) {
|
||||||
} else {
|
$services = $response->json();
|
||||||
send_internal_notification('PullTemplatesAndVersions failed with: '.$response->status().' '.$response->body());
|
File::put(base_path('templates/service-templates.json'), json_encode($services));
|
||||||
}
|
} else {
|
||||||
|
send_internal_notification('PullTemplatesAndVersions failed with: '.$response->status().' '.$response->body());
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
send_internal_notification('PullTemplatesAndVersions failed with: '.$e->getMessage());
|
send_internal_notification('PullTemplatesAndVersions failed with: '.$e->getMessage());
|
||||||
|
440
app/Jobs/ServerCheckJob.php
Normal file
440
app/Jobs/ServerCheckJob.php
Normal file
@@ -0,0 +1,440 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Actions\Database\StartDatabaseProxy;
|
||||||
|
use App\Actions\Docker\GetContainersStatus;
|
||||||
|
use App\Actions\Proxy\CheckProxy;
|
||||||
|
use App\Actions\Proxy\StartProxy;
|
||||||
|
use App\Actions\Server\InstallLogDrain;
|
||||||
|
use App\Models\ApplicationPreview;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\ServiceDatabase;
|
||||||
|
use App\Notifications\Container\ContainerRestarted;
|
||||||
|
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\Middleware\WithoutOverlapping;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $tries = 3;
|
||||||
|
|
||||||
|
public $containers;
|
||||||
|
|
||||||
|
public $applications;
|
||||||
|
|
||||||
|
public $databases;
|
||||||
|
|
||||||
|
public $services;
|
||||||
|
|
||||||
|
public $previews;
|
||||||
|
|
||||||
|
public function backoff(): int
|
||||||
|
{
|
||||||
|
return isDev() ? 1 : 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(public Server $server) {}
|
||||||
|
|
||||||
|
public function middleware(): array
|
||||||
|
{
|
||||||
|
return [(new WithoutOverlapping($this->server->uuid))];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uniqueId(): int
|
||||||
|
{
|
||||||
|
return $this->server->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->applications = $this->server->applications();
|
||||||
|
$this->databases = $this->server->databases();
|
||||||
|
$this->services = $this->server->services()->get();
|
||||||
|
$this->previews = $this->server->previews();
|
||||||
|
|
||||||
|
$up = $this->serverStatus();
|
||||||
|
if (! $up) {
|
||||||
|
ray('Server is not reachable.');
|
||||||
|
|
||||||
|
return 'Server is not reachable.';
|
||||||
|
}
|
||||||
|
if (! $this->server->isFunctional()) {
|
||||||
|
ray('Server is not ready.');
|
||||||
|
|
||||||
|
return 'Server is not ready.';
|
||||||
|
}
|
||||||
|
if (! $this->server->isSwarmWorker() && ! $this->server->isBuildServer()) {
|
||||||
|
['containers' => $this->containers, 'containerReplicates' => $containerReplicates] = $this->server->getContainers();
|
||||||
|
if (is_null($this->containers)) {
|
||||||
|
return 'No containers found.';
|
||||||
|
}
|
||||||
|
GetContainersStatus::run($this->server, $this->containers, $containerReplicates);
|
||||||
|
$this->checkLogDrainContainer();
|
||||||
|
$this->checkSentinel();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ray($e->getMessage());
|
||||||
|
|
||||||
|
return handleError($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkSentinel()
|
||||||
|
{
|
||||||
|
if ($this->server->isSentinelEnabled()) {
|
||||||
|
$sentinelContainerFound = $this->containers->filter(function ($value, $key) {
|
||||||
|
return data_get($value, 'Name') === '/coolify-sentinel';
|
||||||
|
})->first();
|
||||||
|
if ($sentinelContainerFound) {
|
||||||
|
$status = data_get($sentinelContainerFound, 'State.Status');
|
||||||
|
if ($status !== 'running') {
|
||||||
|
PullSentinelImageJob::dispatch($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function serverStatus()
|
||||||
|
{
|
||||||
|
['uptime' => $uptime] = $this->server->validateConnection();
|
||||||
|
if ($uptime) {
|
||||||
|
if ($this->server->unreachable_notification_sent === true) {
|
||||||
|
$this->server->update(['unreachable_notification_sent' => false]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// $this->server->team?->notify(new Unreachable($this->server));
|
||||||
|
foreach ($this->applications as $application) {
|
||||||
|
$application->update(['status' => 'exited']);
|
||||||
|
}
|
||||||
|
foreach ($this->databases as $database) {
|
||||||
|
$database->update(['status' => 'exited']);
|
||||||
|
}
|
||||||
|
foreach ($this->services as $service) {
|
||||||
|
$apps = $service->applications()->get();
|
||||||
|
$dbs = $service->databases()->get();
|
||||||
|
foreach ($apps as $app) {
|
||||||
|
$app->update(['status' => 'exited']);
|
||||||
|
}
|
||||||
|
foreach ($dbs as $db) {
|
||||||
|
$db->update(['status' => 'exited']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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') {
|
||||||
|
InstallLogDrain::dispatch($this->server);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
InstallLogDrain::dispatch($this->server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function containerStatus()
|
||||||
|
{
|
||||||
|
|
||||||
|
$foundApplications = [];
|
||||||
|
$foundApplicationPreviews = [];
|
||||||
|
$foundDatabases = [];
|
||||||
|
$foundServices = [];
|
||||||
|
|
||||||
|
foreach ($this->containers as $container) {
|
||||||
|
if ($this->server->isSwarm()) {
|
||||||
|
$labels = data_get($container, 'Spec.Labels');
|
||||||
|
$uuid = data_get($labels, 'coolify.name');
|
||||||
|
} else {
|
||||||
|
$labels = data_get($container, 'Config.Labels');
|
||||||
|
}
|
||||||
|
$containerStatus = data_get($container, 'State.Status');
|
||||||
|
$containerHealth = data_get($container, 'State.Health.Status', 'unhealthy');
|
||||||
|
$containerStatus = "$containerStatus ($containerHealth)";
|
||||||
|
$labels = Arr::undot(format_docker_labels_to_json($labels));
|
||||||
|
$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 = data_get($service_db, 'service.uuid');
|
||||||
|
if ($uuid) {
|
||||||
|
$isPublic = data_get($service_db, 'is_public');
|
||||||
|
if ($isPublic) {
|
||||||
|
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||||
|
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_db);
|
||||||
|
// $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$database = $this->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()) {
|
||||||
|
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 = $this->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 ($this->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 = $this->previews->pluck('id')->diff($foundApplicationPreviews);
|
||||||
|
foreach ($notRunningApplicationPreviews as $previewId) {
|
||||||
|
$preview = $this->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 = $this->databases->pluck('id')->diff($foundDatabases);
|
||||||
|
foreach ($notRunningDatabases as $database) {
|
||||||
|
$database = $this->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()) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
app/Jobs/UpdateCoolifyJob.php
Normal file
51
app/Jobs/UpdateCoolifyJob.php
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Actions\Server\UpdateCoolify;
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class UpdateCoolifyJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $timeout = 600;
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
CheckForUpdatesJob::dispatchSync();
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
|
if (! $settings->new_version_available) {
|
||||||
|
Log::info('No new version available. Skipping update.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$server = Server::findOrFail(0);
|
||||||
|
if (! $server) {
|
||||||
|
Log::error('Server not found. Cannot proceed with update.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('Starting Coolify update process...');
|
||||||
|
UpdateCoolify::run(false); // false means it's not a manual update
|
||||||
|
|
||||||
|
$settings->update(['new_version_available' => false]);
|
||||||
|
Log::info('Coolify update completed successfully.');
|
||||||
|
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Log::error('UpdateCoolifyJob failed: '.$e->getMessage());
|
||||||
|
// Consider implementing a notification to administrators
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -179,7 +179,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
public function getProxyType()
|
public function getProxyType()
|
||||||
{
|
{
|
||||||
// Set Default Proxy Type
|
// Set Default Proxy Type
|
||||||
$this->selectProxy(ProxyTypes::TRAEFIK_V2->value);
|
$this->selectProxy(ProxyTypes::TRAEFIK->value);
|
||||||
// $proxyTypeSet = $this->createdServer->proxy->type;
|
// $proxyTypeSet = $this->createdServer->proxy->type;
|
||||||
// if (!$proxyTypeSet) {
|
// if (!$proxyTypeSet) {
|
||||||
// $this->currentState = 'select-proxy';
|
// $this->currentState = 'select-proxy';
|
||||||
|
@@ -52,7 +52,7 @@ class Docker extends Component
|
|||||||
if (request()->query('network_name')) {
|
if (request()->query('network_name')) {
|
||||||
$this->network = request()->query('network_name');
|
$this->network = request()->query('network_name');
|
||||||
} else {
|
} else {
|
||||||
$this->network = new Cuid2(7);
|
$this->network = new Cuid2;
|
||||||
}
|
}
|
||||||
if ($this->servers->count() > 0) {
|
if ($this->servers->count() > 0) {
|
||||||
$this->name = str("{$this->servers->first()->name}-{$this->network}")->kebab();
|
$this->name = str("{$this->servers->first()->name}-{$this->network}")->kebab();
|
||||||
|
@@ -39,7 +39,7 @@ class MonacoEditor extends Component
|
|||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
if (is_null($this->id)) {
|
if (is_null($this->id)) {
|
||||||
$this->id = new Cuid2(7);
|
$this->id = new Cuid2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->name)) {
|
if (is_null($this->name)) {
|
||||||
|
35
app/Livewire/NavbarDeleteTeam.php
Normal file
35
app/Livewire/NavbarDeleteTeam.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class NavbarDeleteTeam extends Component
|
||||||
|
{
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$currentTeam = currentTeam();
|
||||||
|
$currentTeam->delete();
|
||||||
|
|
||||||
|
$currentTeam->members->each(function ($user) use ($currentTeam) {
|
||||||
|
if ($user->id === auth()->user()->id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$user->teams()->detach($currentTeam);
|
||||||
|
$session = DB::table('sessions')->where('user_id', $user->id)->first();
|
||||||
|
if ($session) {
|
||||||
|
DB::table('sessions')->where('id', $session->id)->delete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
refreshSession();
|
||||||
|
|
||||||
|
return redirect()->route('team.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.navbar-delete-team');
|
||||||
|
}
|
||||||
|
}
|
@@ -91,11 +91,25 @@ class Advanced extends Component
|
|||||||
|
|
||||||
public function saveCustomName()
|
public function saveCustomName()
|
||||||
{
|
{
|
||||||
if (isset($this->application->settings->custom_internal_name)) {
|
if (str($this->application->settings->custom_internal_name)->isNotEmpty()) {
|
||||||
$this->application->settings->custom_internal_name = str($this->application->settings->custom_internal_name)->slug()->value();
|
$this->application->settings->custom_internal_name = str($this->application->settings->custom_internal_name)->slug()->value();
|
||||||
} else {
|
} else {
|
||||||
$this->application->settings->custom_internal_name = null;
|
$this->application->settings->custom_internal_name = null;
|
||||||
}
|
}
|
||||||
|
$customInternalName = $this->application->settings->custom_internal_name;
|
||||||
|
$server = $this->application->destination->server;
|
||||||
|
$allApplications = $server->applications();
|
||||||
|
|
||||||
|
$foundSameInternalName = $allApplications->filter(function ($application) {
|
||||||
|
return $application->id !== $this->application->id && $application->settings->custom_internal_name === $this->application->settings->custom_internal_name;
|
||||||
|
});
|
||||||
|
if ($foundSameInternalName->isNotEmpty()) {
|
||||||
|
$this->dispatch('error', 'This custom container name is already in use by another application on this server.');
|
||||||
|
$this->application->settings->custom_internal_name = $customInternalName;
|
||||||
|
$this->application->settings->refresh();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
$this->application->settings->save();
|
$this->application->settings->save();
|
||||||
$this->dispatch('success', 'Custom name saved.');
|
$this->dispatch('success', 'Custom name saved.');
|
||||||
}
|
}
|
||||||
|
@@ -214,7 +214,7 @@ class General extends Component
|
|||||||
}
|
}
|
||||||
$this->dispatch('success', 'Docker compose file loaded.');
|
$this->dispatch('success', 'Docker compose file loaded.');
|
||||||
$this->dispatch('compose_loaded');
|
$this->dispatch('compose_loaded');
|
||||||
$this->dispatch('refresh_storages');
|
$this->dispatch('refreshStorages');
|
||||||
$this->dispatch('refreshEnvs');
|
$this->dispatch('refreshEnvs');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->application->docker_compose_location = $this->initialDockerComposeLocation;
|
$this->application->docker_compose_location = $this->initialDockerComposeLocation;
|
||||||
@@ -228,7 +228,7 @@ class General extends Component
|
|||||||
|
|
||||||
public function generateDomain(string $serviceName)
|
public function generateDomain(string $serviceName)
|
||||||
{
|
{
|
||||||
$uuid = new Cuid2(7);
|
$uuid = new Cuid2;
|
||||||
$domain = generateFqdn($this->application->destination->server, $uuid);
|
$domain = generateFqdn($this->application->destination->server, $uuid);
|
||||||
$this->parsedServiceDomains[$serviceName]['domain'] = $domain;
|
$this->parsedServiceDomains[$serviceName]['domain'] = $domain;
|
||||||
$this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
|
$this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
|
||||||
|
@@ -5,8 +5,6 @@ namespace App\Livewire\Project\Application;
|
|||||||
use App\Actions\Application\StopApplication;
|
use App\Actions\Application\StopApplication;
|
||||||
use App\Actions\Docker\GetContainersStatus;
|
use App\Actions\Docker\GetContainersStatus;
|
||||||
use App\Events\ApplicationStatusChanged;
|
use App\Events\ApplicationStatusChanged;
|
||||||
use App\Jobs\ContainerStatusJob;
|
|
||||||
use App\Jobs\ServerStatusJob;
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
@@ -46,11 +44,7 @@ class Heading extends Component
|
|||||||
{
|
{
|
||||||
if ($this->application->destination->server->isFunctional()) {
|
if ($this->application->destination->server->isFunctional()) {
|
||||||
GetContainersStatus::dispatch($this->application->destination->server)->onQueue('high');
|
GetContainersStatus::dispatch($this->application->destination->server)->onQueue('high');
|
||||||
// dispatch(new ContainerStatusJob($this->application->destination->server));
|
|
||||||
} else {
|
|
||||||
dispatch(new ServerStatusJob($this->application->destination->server));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($showNotification) {
|
if ($showNotification) {
|
||||||
$this->dispatch('success', 'Success', 'Application status updated.');
|
$this->dispatch('success', 'Success', 'Application status updated.');
|
||||||
}
|
}
|
||||||
@@ -102,7 +96,7 @@ class Heading extends Component
|
|||||||
|
|
||||||
protected function setDeploymentUuid()
|
protected function setDeploymentUuid()
|
||||||
{
|
{
|
||||||
$this->deploymentUuid = new Cuid2(7);
|
$this->deploymentUuid = new Cuid2;
|
||||||
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
|
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -85,7 +85,7 @@ class Previews extends Component
|
|||||||
$template = $this->application->preview_url_template;
|
$template = $this->application->preview_url_template;
|
||||||
$host = $url->getHost();
|
$host = $url->getHost();
|
||||||
$schema = $url->getScheme();
|
$schema = $url->getScheme();
|
||||||
$random = new Cuid2(7);
|
$random = new Cuid2;
|
||||||
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
||||||
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
||||||
$preview_fqdn = str_replace('{{pr_id}}', $preview->pull_request_id, $preview_fqdn);
|
$preview_fqdn = str_replace('{{pr_id}}', $preview->pull_request_id, $preview_fqdn);
|
||||||
@@ -170,7 +170,7 @@ class Previews extends Component
|
|||||||
|
|
||||||
protected function setDeploymentUuid()
|
protected function setDeploymentUuid()
|
||||||
{
|
{
|
||||||
$this->deployment_uuid = new Cuid2(7);
|
$this->deployment_uuid = new Cuid2;
|
||||||
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
|
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ class PreviewsCompose extends Component
|
|||||||
$template = $this->preview->application->preview_url_template;
|
$template = $this->preview->application->preview_url_template;
|
||||||
$host = $url->getHost();
|
$host = $url->getHost();
|
||||||
$schema = $url->getScheme();
|
$schema = $url->getScheme();
|
||||||
$random = new Cuid2(7);
|
$random = new Cuid2;
|
||||||
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
||||||
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
||||||
$preview_fqdn = str_replace('{{pr_id}}', $this->preview->pull_request_id, $preview_fqdn);
|
$preview_fqdn = str_replace('{{pr_id}}', $this->preview->pull_request_id, $preview_fqdn);
|
||||||
|
@@ -23,7 +23,7 @@ class Rollback extends Component
|
|||||||
|
|
||||||
public function rollbackImage($commit)
|
public function rollbackImage($commit)
|
||||||
{
|
{
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $this->application,
|
application: $this->application,
|
||||||
|
@@ -47,7 +47,7 @@ class CloneMe extends Component
|
|||||||
$this->environment = $this->project->environments->where('name', $this->environment_name)->first();
|
$this->environment = $this->project->environments->where('name', $this->environment_name)->first();
|
||||||
$this->project_id = $this->project->id;
|
$this->project_id = $this->project->id;
|
||||||
$this->servers = currentTeam()->servers;
|
$this->servers = currentTeam()->servers;
|
||||||
$this->newName = str($this->project->name.'-clone-'.(string) new Cuid2(7))->slug();
|
$this->newName = str($this->project->name.'-clone-'.(string) new Cuid2)->slug();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
@@ -106,7 +106,7 @@ class CloneMe extends Component
|
|||||||
$databases = $this->environment->databases();
|
$databases = $this->environment->databases();
|
||||||
$services = $this->environment->services;
|
$services = $this->environment->services;
|
||||||
foreach ($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
$uuid = (string) new Cuid2(7);
|
$uuid = (string) new Cuid2;
|
||||||
$newApplication = $application->replicate()->fill([
|
$newApplication = $application->replicate()->fill([
|
||||||
'uuid' => $uuid,
|
'uuid' => $uuid,
|
||||||
'fqdn' => generateFqdn($this->server, $uuid),
|
'fqdn' => generateFqdn($this->server, $uuid),
|
||||||
@@ -133,7 +133,7 @@ class CloneMe extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($databases as $database) {
|
foreach ($databases as $database) {
|
||||||
$uuid = (string) new Cuid2(7);
|
$uuid = (string) new Cuid2;
|
||||||
$newDatabase = $database->replicate()->fill([
|
$newDatabase = $database->replicate()->fill([
|
||||||
'uuid' => $uuid,
|
'uuid' => $uuid,
|
||||||
'status' => 'exited',
|
'status' => 'exited',
|
||||||
@@ -161,7 +161,7 @@ class CloneMe extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($services as $service) {
|
foreach ($services as $service) {
|
||||||
$uuid = (string) new Cuid2(7);
|
$uuid = (string) new Cuid2;
|
||||||
$newService = $service->replicate()->fill([
|
$newService = $service->replicate()->fill([
|
||||||
'uuid' => $uuid,
|
'uuid' => $uuid,
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $environment->id,
|
||||||
|
@@ -48,7 +48,7 @@ class DockerImage extends Component
|
|||||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
||||||
ray($image, $tag);
|
ray($image, $tag);
|
||||||
$application = Application::create([
|
$application = Application::create([
|
||||||
'name' => 'docker-image-'.new Cuid2(7),
|
'name' => 'docker-image-'.new Cuid2,
|
||||||
'repository_project_id' => 0,
|
'repository_project_id' => 0,
|
||||||
'git_repository' => 'coollabsio/coolify',
|
'git_repository' => 'coollabsio/coolify',
|
||||||
'git_branch' => 'main',
|
'git_branch' => 'main',
|
||||||
|
@@ -53,7 +53,7 @@ CMD ["nginx", "-g", "daemon off;"]
|
|||||||
$port = 80;
|
$port = 80;
|
||||||
}
|
}
|
||||||
$application = Application::create([
|
$application = Application::create([
|
||||||
'name' => 'dockerfile-'.new Cuid2(7),
|
'name' => 'dockerfile-'.new Cuid2,
|
||||||
'repository_project_id' => 0,
|
'repository_project_id' => 0,
|
||||||
'git_repository' => 'coollabsio/coolify',
|
'git_repository' => 'coollabsio/coolify',
|
||||||
'git_branch' => 'main',
|
'git_branch' => 'main',
|
||||||
|
@@ -25,7 +25,6 @@ class Configuration extends Component
|
|||||||
return [
|
return [
|
||||||
"echo-private:user.{$userId},ServiceStatusChanged" => 'check_status',
|
"echo-private:user.{$userId},ServiceStatusChanged" => 'check_status',
|
||||||
'check_status',
|
'check_status',
|
||||||
'refresh' => '$refresh',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +75,7 @@ class Configuration extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
GetContainersStatus::run($this->service->server);
|
GetContainersStatus::run($this->service->server);
|
||||||
// dispatch_sync(new ContainerStatusJob($this->service->server));
|
$this->dispatch('$refresh');
|
||||||
$this->dispatch('refresh')->self();
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,8 @@ class FileStorage extends Component
|
|||||||
|
|
||||||
public ?string $workdir = null;
|
public ?string $workdir = null;
|
||||||
|
|
||||||
|
public bool $permanently_delete = true;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'fileStorage.is_directory' => 'required',
|
'fileStorage.is_directory' => 'required',
|
||||||
'fileStorage.fs_path' => 'required',
|
'fileStorage.fs_path' => 'required',
|
||||||
@@ -56,7 +58,7 @@ class FileStorage extends Component
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->dispatch('refresh_storages');
|
$this->dispatch('refreshStorages');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,20 +73,27 @@ class FileStorage extends Component
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->dispatch('refresh_storages');
|
$this->dispatch('refreshStorages');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->fileStorage->deleteStorageOnServer();
|
$message = 'File deleted.';
|
||||||
|
if ($this->fileStorage->is_directory) {
|
||||||
|
$message = 'Directory deleted.';
|
||||||
|
}
|
||||||
|
if ($this->permanently_delete) {
|
||||||
|
$message = 'Directory deleted from the server.';
|
||||||
|
$this->fileStorage->deleteStorageOnServer();
|
||||||
|
}
|
||||||
$this->fileStorage->delete();
|
$this->fileStorage->delete();
|
||||||
$this->dispatch('success', 'File deleted.');
|
$this->dispatch('success', $message);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->dispatch('refresh_storages');
|
$this->dispatch('refreshStorages');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,6 +49,11 @@ class Navbar extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function check_status_without_notification()
|
||||||
|
{
|
||||||
|
$this->dispatch('check_status');
|
||||||
|
}
|
||||||
|
|
||||||
public function check_status()
|
public function check_status()
|
||||||
{
|
{
|
||||||
$this->dispatch('check_status');
|
$this->dispatch('check_status');
|
||||||
@@ -63,6 +68,8 @@ class Navbar extends Component
|
|||||||
public function checkDeployments()
|
public function checkDeployments()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
// TODO: This is a temporary solution. We need to refactor this.
|
||||||
|
// We need to delete null bytes somehow.
|
||||||
$activity = Activity::where('properties->type_uuid', $this->service->uuid)->latest()->first();
|
$activity = Activity::where('properties->type_uuid', $this->service->uuid)->latest()->first();
|
||||||
$status = data_get($activity, 'properties.status');
|
$status = data_get($activity, 'properties.status');
|
||||||
if ($status === 'queued' || $status === 'in_progress') {
|
if ($status === 'queued' || $status === 'in_progress') {
|
||||||
@@ -70,7 +77,7 @@ class Navbar extends Component
|
|||||||
} else {
|
} else {
|
||||||
$this->isDeploymentProgress = false;
|
$this->isDeploymentProgress = false;
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->isDeploymentProgress = false;
|
$this->isDeploymentProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,14 +9,36 @@ class Storage extends Component
|
|||||||
{
|
{
|
||||||
public $resource;
|
public $resource;
|
||||||
|
|
||||||
|
public $fileStorage;
|
||||||
|
|
||||||
public function getListeners()
|
public function getListeners()
|
||||||
{
|
{
|
||||||
|
$teamId = auth()->user()->currentTeam()->id;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
"echo-private:team.{$teamId},FileStorageChanged" => 'refreshStoragesFromEvent',
|
||||||
|
'refreshStorages',
|
||||||
'addNewVolume',
|
'addNewVolume',
|
||||||
'refresh_storages' => '$refresh',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->refreshStorages();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refreshStoragesFromEvent()
|
||||||
|
{
|
||||||
|
$this->refreshStorages();
|
||||||
|
$this->dispatch('warning', 'File storage changed. Usually it means that the file / directory is already defined on the server, so Coolify set it up for you properly on the UI.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refreshStorages()
|
||||||
|
{
|
||||||
|
$this->fileStorage = $this->resource->fileStorages()->get();
|
||||||
|
$this->dispatch('$refresh');
|
||||||
|
}
|
||||||
|
|
||||||
public function addNewVolume($data)
|
public function addNewVolume($data)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -30,7 +52,7 @@ class Storage extends Component
|
|||||||
$this->resource->refresh();
|
$this->resource->refresh();
|
||||||
$this->dispatch('success', 'Storage added successfully');
|
$this->dispatch('success', 'Storage added successfully');
|
||||||
$this->dispatch('clearAddStorage');
|
$this->dispatch('clearAddStorage');
|
||||||
$this->dispatch('refresh_storages');
|
$this->dispatch('refreshStorages');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ class Danger extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->modalId = new Cuid2(7);
|
$this->modalId = new Cuid2;
|
||||||
$parameters = get_route_parameters();
|
$parameters = get_route_parameters();
|
||||||
$this->projectUuid = data_get($parameters, 'project_uuid');
|
$this->projectUuid = data_get($parameters, 'project_uuid');
|
||||||
$this->environmentName = data_get($parameters, 'environment_name');
|
$this->environmentName = data_get($parameters, 'environment_name');
|
||||||
|
@@ -67,7 +67,7 @@ class Destination extends Component
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2;
|
||||||
$server = Server::find($server_id);
|
$server = Server::find($server_id);
|
||||||
$destination = StandaloneDocker::find($network_id);
|
$destination = StandaloneDocker::find($network_id);
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
|
@@ -48,14 +48,14 @@ class Add extends Component
|
|||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
if (str($this->value)->startsWith('{{') && str($this->value)->endsWith('}}')) {
|
// if (str($this->value)->startsWith('{{') && str($this->value)->endsWith('}}')) {
|
||||||
$type = str($this->value)->after('{{')->before('.')->value;
|
// $type = str($this->value)->after('{{')->before('.')->value;
|
||||||
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
// if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||||
$this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
// $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$this->dispatch('saveKey', [
|
$this->dispatch('saveKey', [
|
||||||
'key' => $this->key,
|
'key' => $this->key,
|
||||||
'value' => $this->value,
|
'value' => $this->value,
|
||||||
|
@@ -39,7 +39,7 @@ class All extends Component
|
|||||||
if (str($this->resourceClass)->contains($resourceWithPreviews) && ! $simpleDockerfile) {
|
if (str($this->resourceClass)->contains($resourceWithPreviews) && ! $simpleDockerfile) {
|
||||||
$this->showPreview = true;
|
$this->showPreview = true;
|
||||||
}
|
}
|
||||||
$this->modalId = new Cuid2(7);
|
$this->modalId = new Cuid2;
|
||||||
$this->sortMe();
|
$this->sortMe();
|
||||||
$this->getDevView();
|
$this->getDevView();
|
||||||
}
|
}
|
||||||
@@ -125,14 +125,14 @@ class All extends Component
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$found->value = $variable;
|
$found->value = $variable;
|
||||||
if (str($found->value)->startsWith('{{') && str($found->value)->endsWith('}}')) {
|
// if (str($found->value)->startsWith('{{') && str($found->value)->endsWith('}}')) {
|
||||||
$type = str($found->value)->after('{{')->before('.')->value;
|
// $type = str($found->value)->after('{{')->before('.')->value;
|
||||||
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
// if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||||
$this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
// $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$found->save();
|
$found->save();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -140,14 +140,14 @@ class All extends Component
|
|||||||
$environment = new EnvironmentVariable;
|
$environment = new EnvironmentVariable;
|
||||||
$environment->key = $key;
|
$environment->key = $key;
|
||||||
$environment->value = $variable;
|
$environment->value = $variable;
|
||||||
if (str($environment->value)->startsWith('{{') && str($environment->value)->endsWith('}}')) {
|
// if (str($environment->value)->startsWith('{{') && str($environment->value)->endsWith('}}')) {
|
||||||
$type = str($environment->value)->after('{{')->before('.')->value;
|
// $type = str($environment->value)->after('{{')->before('.')->value;
|
||||||
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
// if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||||
$this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
// $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$environment->is_build_time = false;
|
$environment->is_build_time = false;
|
||||||
$environment->is_multiline = false;
|
$environment->is_multiline = false;
|
||||||
$environment->is_preview = $isPreview ? true : false;
|
$environment->is_preview = $isPreview ? true : false;
|
||||||
|
@@ -58,7 +58,7 @@ class Show extends Component
|
|||||||
if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') {
|
if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') {
|
||||||
$this->isSharedVariable = true;
|
$this->isSharedVariable = true;
|
||||||
}
|
}
|
||||||
$this->modalId = new Cuid2(7);
|
$this->modalId = new Cuid2;
|
||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
$this->checkEnvs();
|
$this->checkEnvs();
|
||||||
}
|
}
|
||||||
@@ -108,14 +108,14 @@ class Show extends Component
|
|||||||
} else {
|
} else {
|
||||||
$this->validate();
|
$this->validate();
|
||||||
}
|
}
|
||||||
if (str($this->env->value)->startsWith('{{') && str($this->env->value)->endsWith('}}')) {
|
// if (str($this->env->value)->startsWith('{{') && str($this->env->value)->endsWith('}}')) {
|
||||||
$type = str($this->env->value)->after('{{')->before('.')->value;
|
// $type = str($this->env->value)->after('{{')->before('.')->value;
|
||||||
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
// if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||||
$this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
// $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$this->serialize();
|
$this->serialize();
|
||||||
$this->env->save();
|
$this->env->save();
|
||||||
$this->dispatch('success', 'Environment variable updated.');
|
$this->dispatch('success', 'Environment variable updated.');
|
||||||
|
@@ -39,7 +39,7 @@ class ResourceOperations extends Component
|
|||||||
if (! $new_destination) {
|
if (! $new_destination) {
|
||||||
return $this->addError('destination_id', 'Destination not found.');
|
return $this->addError('destination_id', 'Destination not found.');
|
||||||
}
|
}
|
||||||
$uuid = (string) new Cuid2(7);
|
$uuid = (string) new Cuid2;
|
||||||
$server = $new_destination->server;
|
$server = $new_destination->server;
|
||||||
if ($this->resource->getMorphClass() === 'App\Models\Application') {
|
if ($this->resource->getMorphClass() === 'App\Models\Application') {
|
||||||
$new_resource = $this->resource->replicate()->fill([
|
$new_resource = $this->resource->replicate()->fill([
|
||||||
@@ -87,7 +87,7 @@ class ResourceOperations extends Component
|
|||||||
$this->resource->getMorphClass() === 'App\Models\StandaloneDragonfly' ||
|
$this->resource->getMorphClass() === 'App\Models\StandaloneDragonfly' ||
|
||||||
$this->resource->getMorphClass() === 'App\Models\StandaloneClickhouse'
|
$this->resource->getMorphClass() === 'App\Models\StandaloneClickhouse'
|
||||||
) {
|
) {
|
||||||
$uuid = (string) new Cuid2(7);
|
$uuid = (string) new Cuid2;
|
||||||
$new_resource = $this->resource->replicate()->fill([
|
$new_resource = $this->resource->replicate()->fill([
|
||||||
'uuid' => $uuid,
|
'uuid' => $uuid,
|
||||||
'name' => $this->resource->name.'-clone-'.$uuid,
|
'name' => $this->resource->name.'-clone-'.$uuid,
|
||||||
@@ -121,7 +121,7 @@ class ResourceOperations extends Component
|
|||||||
|
|
||||||
return redirect()->to($route);
|
return redirect()->to($route);
|
||||||
} elseif ($this->resource->type() === 'service') {
|
} elseif ($this->resource->type() === 'service') {
|
||||||
$uuid = (string) new Cuid2(7);
|
$uuid = (string) new Cuid2;
|
||||||
$new_resource = $this->resource->replicate()->fill([
|
$new_resource = $this->resource->replicate()->fill([
|
||||||
'uuid' => $uuid,
|
'uuid' => $uuid,
|
||||||
'name' => $this->resource->name.'-clone-'.$uuid,
|
'name' => $this->resource->name.'-clone-'.$uuid,
|
||||||
|
@@ -47,7 +47,7 @@ class Show extends Component
|
|||||||
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->modalId = new Cuid2(7);
|
$this->modalId = new Cuid2;
|
||||||
$this->task = ModelsScheduledTask::where('uuid', request()->route('task_uuid'))->first();
|
$this->task = ModelsScheduledTask::where('uuid', request()->route('task_uuid'))->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,7 +54,11 @@ class Add extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->file_storage_directory_source = application_configuration_dir()."/{$this->resource->uuid}";
|
if (str($this->resource->getMorphClass())->contains('Standalone')) {
|
||||||
|
$this->file_storage_directory_source = database_configuration_dir()."/{$this->resource->uuid}";
|
||||||
|
} else {
|
||||||
|
$this->file_storage_directory_source = application_configuration_dir()."/{$this->resource->uuid}";
|
||||||
|
}
|
||||||
$this->uuid = $this->resource->uuid;
|
$this->uuid = $this->resource->uuid;
|
||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
if (data_get($this->parameters, 'application_uuid')) {
|
if (data_get($this->parameters, 'application_uuid')) {
|
||||||
@@ -92,7 +96,7 @@ class Add extends Component
|
|||||||
'resource_type' => get_class($this->resource),
|
'resource_type' => get_class($this->resource),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
$this->dispatch('refresh_storages');
|
$this->dispatch('refreshStorages');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
@@ -119,7 +123,7 @@ class Add extends Component
|
|||||||
'resource_type' => get_class($this->resource),
|
'resource_type' => get_class($this->resource),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
$this->dispatch('refresh_storages');
|
$this->dispatch('refreshStorages');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
@@ -8,5 +8,5 @@ class All extends Component
|
|||||||
{
|
{
|
||||||
public $resource;
|
public $resource;
|
||||||
|
|
||||||
protected $listeners = ['refresh_storages' => '$refresh'];
|
protected $listeners = ['refreshStorages' => '$refresh'];
|
||||||
}
|
}
|
||||||
|
@@ -39,6 +39,6 @@ class Show extends Component
|
|||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
$this->storage->delete();
|
$this->storage->delete();
|
||||||
$this->dispatch('refresh_storages');
|
$this->dispatch('refreshStorages');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Livewire\Server;
|
namespace App\Livewire\Server;
|
||||||
|
|
||||||
use App\Actions\Server\InstallLogDrain;
|
use App\Actions\Server\InstallLogDrain;
|
||||||
|
use App\Actions\Server\StopLogDrain;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
@@ -132,6 +133,9 @@ class LogDrains extends Component
|
|||||||
'is_logdrain_axiom_enabled' => false,
|
'is_logdrain_axiom_enabled' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
if (! $this->server->isLogDrainEnabled()) {
|
||||||
|
StopLogDrain::dispatch($this->server);
|
||||||
|
}
|
||||||
$this->server->settings->save();
|
$this->server->settings->save();
|
||||||
$this->dispatch('success', 'Settings saved.');
|
$this->dispatch('success', 'Settings saved.');
|
||||||
|
|
||||||
|
@@ -104,7 +104,7 @@ class ByIp extends Component
|
|||||||
'private_key_id' => $this->private_key_id,
|
'private_key_id' => $this->private_key_id,
|
||||||
'proxy' => [
|
'proxy' => [
|
||||||
// set default proxy type to traefik v2
|
// set default proxy type to traefik v2
|
||||||
'type' => ProxyTypes::TRAEFIK_V2->value,
|
'type' => ProxyTypes::TRAEFIK->value,
|
||||||
'status' => ProxyStatus::EXITED->value,
|
'status' => ProxyStatus::EXITED->value,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@@ -20,6 +20,10 @@ class Proxy extends Component
|
|||||||
|
|
||||||
protected $listeners = ['proxyStatusUpdated', 'saveConfiguration' => 'submit'];
|
protected $listeners = ['proxyStatusUpdated', 'saveConfiguration' => 'submit'];
|
||||||
|
|
||||||
|
protected $rules = [
|
||||||
|
'server.settings.generate_exact_labels' => 'required|boolean',
|
||||||
|
];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->selectedProxy = $this->server->proxyType();
|
$this->selectedProxy = $this->server->proxyType();
|
||||||
@@ -31,13 +35,13 @@ class Proxy extends Component
|
|||||||
$this->dispatch('refresh')->self();
|
$this->dispatch('refresh')->self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function change_proxy()
|
public function changeProxy()
|
||||||
{
|
{
|
||||||
$this->server->proxy = null;
|
$this->server->proxy = null;
|
||||||
$this->server->save();
|
$this->server->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function select_proxy($proxy_type)
|
public function selectProxy($proxy_type)
|
||||||
{
|
{
|
||||||
$this->server->proxy->set('status', 'exited');
|
$this->server->proxy->set('status', 'exited');
|
||||||
$this->server->proxy->set('type', $proxy_type);
|
$this->server->proxy->set('type', $proxy_type);
|
||||||
@@ -49,6 +53,17 @@ class Proxy extends Component
|
|||||||
$this->dispatch('proxyStatusUpdated');
|
$this->dispatch('proxyStatusUpdated');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->validate();
|
||||||
|
$this->server->settings->save();
|
||||||
|
$this->dispatch('success', 'Settings saved.');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@@ -21,7 +21,6 @@ class DynamicConfigurations extends Component
|
|||||||
return [
|
return [
|
||||||
"echo-private:team.{$teamId},ProxyStatusChanged" => 'loadDynamicConfigurations',
|
"echo-private:team.{$teamId},ProxyStatusChanged" => 'loadDynamicConfigurations',
|
||||||
'loadDynamicConfigurations',
|
'loadDynamicConfigurations',
|
||||||
'refresh' => '$refresh',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +41,7 @@ class DynamicConfigurations extends Component
|
|||||||
$contents[$without_extension] = instant_remote_process(["cat {$proxy_path}/dynamic/{$file}"], $this->server);
|
$contents[$without_extension] = instant_remote_process(["cat {$proxy_path}/dynamic/{$file}"], $this->server);
|
||||||
}
|
}
|
||||||
$this->contents = $contents;
|
$this->contents = $contents;
|
||||||
$this->dispatch('refresh');
|
$this->dispatch('$refresh');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Server\Proxy;
|
namespace App\Livewire\Server\Proxy;
|
||||||
|
|
||||||
|
use App\Enums\ProxyTypes;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
@@ -45,7 +46,7 @@ class NewDynamicConfiguration extends Component
|
|||||||
return redirect()->route('server.index');
|
return redirect()->route('server.index');
|
||||||
}
|
}
|
||||||
$proxy_type = $this->server->proxyType();
|
$proxy_type = $this->server->proxyType();
|
||||||
if ($proxy_type === 'TRAEFIK_V2') {
|
if ($proxy_type === ProxyTypes::TRAEFIK->value) {
|
||||||
if (! str($this->fileName)->endsWith('.yaml') && ! str($this->fileName)->endsWith('.yml')) {
|
if (! str($this->fileName)->endsWith('.yaml') && ! str($this->fileName)->endsWith('.yml')) {
|
||||||
$this->fileName = "{$this->fileName}.yaml";
|
$this->fileName = "{$this->fileName}.yaml";
|
||||||
}
|
}
|
||||||
@@ -69,7 +70,7 @@ class NewDynamicConfiguration extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($proxy_type === 'TRAEFIK_V2') {
|
if ($proxy_type === ProxyTypes::TRAEFIK->value) {
|
||||||
$yaml = Yaml::parse($this->value);
|
$yaml = Yaml::parse($this->value);
|
||||||
$yaml = Yaml::dump($yaml, 10, 2);
|
$yaml = Yaml::dump($yaml, 10, 2);
|
||||||
$this->value = $yaml;
|
$this->value = $yaml;
|
||||||
|
@@ -1,111 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Livewire\Settings;
|
|
||||||
|
|
||||||
use App\Models\InstanceSettings as ModelsInstanceSettings;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Configuration extends Component
|
|
||||||
{
|
|
||||||
public ModelsInstanceSettings $settings;
|
|
||||||
|
|
||||||
public bool $do_not_track;
|
|
||||||
|
|
||||||
public bool $is_auto_update_enabled;
|
|
||||||
|
|
||||||
public bool $is_registration_enabled;
|
|
||||||
|
|
||||||
public bool $is_dns_validation_enabled;
|
|
||||||
|
|
||||||
public bool $is_api_enabled;
|
|
||||||
|
|
||||||
protected string $dynamic_config_path = '/data/coolify/proxy/dynamic';
|
|
||||||
|
|
||||||
protected Server $server;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'settings.fqdn' => 'nullable',
|
|
||||||
'settings.resale_license' => 'nullable',
|
|
||||||
'settings.public_port_min' => 'required',
|
|
||||||
'settings.public_port_max' => 'required',
|
|
||||||
'settings.custom_dns_servers' => 'nullable',
|
|
||||||
'settings.instance_name' => 'nullable',
|
|
||||||
'settings.allowed_ips' => 'nullable',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'settings.fqdn' => 'FQDN',
|
|
||||||
'settings.resale_license' => 'Resale License',
|
|
||||||
'settings.public_port_min' => 'Public port min',
|
|
||||||
'settings.public_port_max' => 'Public port max',
|
|
||||||
'settings.custom_dns_servers' => 'Custom DNS servers',
|
|
||||||
'settings.allowed_ips' => 'Allowed IPs',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->do_not_track = $this->settings->do_not_track;
|
|
||||||
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
|
|
||||||
$this->is_registration_enabled = $this->settings->is_registration_enabled;
|
|
||||||
$this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
|
|
||||||
$this->is_api_enabled = $this->settings->is_api_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
$this->settings->do_not_track = $this->do_not_track;
|
|
||||||
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
|
|
||||||
$this->settings->is_registration_enabled = $this->is_registration_enabled;
|
|
||||||
$this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
|
|
||||||
$this->settings->is_api_enabled = $this->is_api_enabled;
|
|
||||||
$this->settings->save();
|
|
||||||
$this->dispatch('success', 'Settings updated!');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$error_show = false;
|
|
||||||
$this->server = Server::findOrFail(0);
|
|
||||||
$this->resetErrorBag();
|
|
||||||
if ($this->settings->public_port_min > $this->settings->public_port_max) {
|
|
||||||
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->validate();
|
|
||||||
|
|
||||||
if ($this->settings->is_dns_validation_enabled && $this->settings->fqdn) {
|
|
||||||
if (! validate_dns_entry($this->settings->fqdn, $this->server)) {
|
|
||||||
$this->dispatch('error', "Validating DNS failed.<br><br>Make sure you have added the DNS records correctly.<br><br>{$this->settings->fqdn}->{$this->server->ip}<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
|
|
||||||
$error_show = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($this->settings->fqdn) {
|
|
||||||
check_domain_usage(domain: $this->settings->fqdn);
|
|
||||||
}
|
|
||||||
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->replaceEnd(',', '')->trim();
|
|
||||||
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
|
|
||||||
return str($dns)->trim()->lower();
|
|
||||||
});
|
|
||||||
$this->settings->custom_dns_servers = $this->settings->custom_dns_servers->unique();
|
|
||||||
$this->settings->custom_dns_servers = $this->settings->custom_dns_servers->implode(',');
|
|
||||||
|
|
||||||
$this->settings->allowed_ips = str($this->settings->allowed_ips)->replaceEnd(',', '')->trim();
|
|
||||||
$this->settings->allowed_ips = str($this->settings->allowed_ips)->trim()->explode(',')->map(function ($ip) {
|
|
||||||
return str($ip)->trim();
|
|
||||||
});
|
|
||||||
$this->settings->allowed_ips = $this->settings->allowed_ips->unique();
|
|
||||||
$this->settings->allowed_ips = $this->settings->allowed_ips->implode(',');
|
|
||||||
|
|
||||||
$this->settings->save();
|
|
||||||
$this->server->setupDynamicProxyConfiguration();
|
|
||||||
if (! $error_show) {
|
|
||||||
$this->dispatch('success', 'Instance settings updated successfully!');
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,39 +2,170 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Settings;
|
namespace App\Livewire\Settings;
|
||||||
|
|
||||||
|
use App\Jobs\CheckForUpdatesJob;
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\S3Storage;
|
use App\Models\Server;
|
||||||
use App\Models\StandalonePostgresql;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
public InstanceSettings $settings;
|
public InstanceSettings $settings;
|
||||||
|
|
||||||
public StandalonePostgresql $database;
|
public bool $do_not_track;
|
||||||
|
|
||||||
public $s3s;
|
public bool $is_auto_update_enabled;
|
||||||
|
|
||||||
|
public bool $is_registration_enabled;
|
||||||
|
|
||||||
|
public bool $is_dns_validation_enabled;
|
||||||
|
|
||||||
|
public bool $is_api_enabled;
|
||||||
|
|
||||||
|
public string $auto_update_frequency;
|
||||||
|
|
||||||
|
public string $update_check_frequency;
|
||||||
|
|
||||||
|
protected string $dynamic_config_path = '/data/coolify/proxy/dynamic';
|
||||||
|
|
||||||
|
protected Server $server;
|
||||||
|
|
||||||
|
protected $rules = [
|
||||||
|
'settings.fqdn' => 'nullable',
|
||||||
|
'settings.resale_license' => 'nullable',
|
||||||
|
'settings.public_port_min' => 'required',
|
||||||
|
'settings.public_port_max' => 'required',
|
||||||
|
'settings.custom_dns_servers' => 'nullable',
|
||||||
|
'settings.instance_name' => 'nullable',
|
||||||
|
'settings.allowed_ips' => 'nullable',
|
||||||
|
'settings.is_auto_update_enabled' => 'boolean',
|
||||||
|
'auto_update_frequency' => 'string',
|
||||||
|
'update_check_frequency' => 'string',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $validationAttributes = [
|
||||||
|
'settings.fqdn' => 'FQDN',
|
||||||
|
'settings.resale_license' => 'Resale License',
|
||||||
|
'settings.public_port_min' => 'Public port min',
|
||||||
|
'settings.public_port_max' => 'Public port max',
|
||||||
|
'settings.custom_dns_servers' => 'Custom DNS servers',
|
||||||
|
'settings.allowed_ips' => 'Allowed IPs',
|
||||||
|
'settings.is_auto_update_enabled' => 'Auto Update Enabled',
|
||||||
|
'auto_update_frequency' => 'Auto Update Frequency',
|
||||||
|
'update_check_frequency' => 'Update Check Frequency',
|
||||||
|
];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
if (isInstanceAdmin()) {
|
if (isInstanceAdmin()) {
|
||||||
$settings = \App\Models\InstanceSettings::get();
|
$this->settings = InstanceSettings::get();
|
||||||
$database = StandalonePostgresql::whereName('coolify-db')->first();
|
$this->do_not_track = $this->settings->do_not_track;
|
||||||
$s3s = S3Storage::whereTeamId(0)->get() ?? [];
|
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
|
||||||
if ($database) {
|
$this->is_registration_enabled = $this->settings->is_registration_enabled;
|
||||||
if ($database->status !== 'running') {
|
$this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
|
||||||
$database->status = 'running';
|
$this->is_api_enabled = $this->settings->is_api_enabled;
|
||||||
$database->save();
|
$this->auto_update_frequency = $this->settings->auto_update_frequency;
|
||||||
}
|
$this->update_check_frequency = $this->settings->update_check_frequency;
|
||||||
$this->database = $database;
|
|
||||||
}
|
|
||||||
$this->settings = $settings;
|
|
||||||
$this->s3s = $s3s;
|
|
||||||
} else {
|
} else {
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
|
$this->settings->do_not_track = $this->do_not_track;
|
||||||
|
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
|
||||||
|
$this->settings->is_registration_enabled = $this->is_registration_enabled;
|
||||||
|
$this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
|
||||||
|
$this->settings->is_api_enabled = $this->is_api_enabled;
|
||||||
|
$this->settings->auto_update_frequency = $this->auto_update_frequency;
|
||||||
|
$this->settings->update_check_frequency = $this->update_check_frequency;
|
||||||
|
$this->settings->save();
|
||||||
|
$this->dispatch('success', 'Settings updated!');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$error_show = false;
|
||||||
|
$this->server = Server::findOrFail(0);
|
||||||
|
$this->resetErrorBag();
|
||||||
|
if ($this->settings->public_port_min > $this->settings->public_port_max) {
|
||||||
|
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
if ($this->is_auto_update_enabled && ! validate_cron_expression($this->auto_update_frequency)) {
|
||||||
|
$this->dispatch('error', 'Invalid Cron / Human expression for Auto Update Frequency.');
|
||||||
|
if (empty($this->auto_update_frequency)) {
|
||||||
|
$this->auto_update_frequency = '0 0 * * *';
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! validate_cron_expression($this->update_check_frequency)) {
|
||||||
|
$this->dispatch('error', 'Invalid Cron / Human expression for Update Check Frequency.');
|
||||||
|
if (empty($this->update_check_frequency)) {
|
||||||
|
$this->update_check_frequency = '0 * * * *';
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->settings->is_dns_validation_enabled && $this->settings->fqdn) {
|
||||||
|
if (! validate_dns_entry($this->settings->fqdn, $this->server)) {
|
||||||
|
$this->dispatch('error', "Validating DNS failed.<br><br>Make sure you have added the DNS records correctly.<br><br>{$this->settings->fqdn}->{$this->server->ip}<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
|
||||||
|
$error_show = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($this->settings->fqdn) {
|
||||||
|
check_domain_usage(domain: $this->settings->fqdn);
|
||||||
|
}
|
||||||
|
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->replaceEnd(',', '')->trim();
|
||||||
|
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
|
||||||
|
return str($dns)->trim()->lower();
|
||||||
|
});
|
||||||
|
$this->settings->custom_dns_servers = $this->settings->custom_dns_servers->unique();
|
||||||
|
$this->settings->custom_dns_servers = $this->settings->custom_dns_servers->implode(',');
|
||||||
|
|
||||||
|
$this->settings->allowed_ips = str($this->settings->allowed_ips)->replaceEnd(',', '')->trim();
|
||||||
|
$this->settings->allowed_ips = str($this->settings->allowed_ips)->trim()->explode(',')->map(function ($ip) {
|
||||||
|
return str($ip)->trim();
|
||||||
|
});
|
||||||
|
$this->settings->allowed_ips = $this->settings->allowed_ips->unique();
|
||||||
|
$this->settings->allowed_ips = $this->settings->allowed_ips->implode(',');
|
||||||
|
|
||||||
|
$this->settings->do_not_track = $this->do_not_track;
|
||||||
|
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
|
||||||
|
$this->settings->is_registration_enabled = $this->is_registration_enabled;
|
||||||
|
$this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
|
||||||
|
$this->settings->is_api_enabled = $this->is_api_enabled;
|
||||||
|
$this->settings->auto_update_frequency = $this->auto_update_frequency;
|
||||||
|
$this->settings->update_check_frequency = $this->update_check_frequency;
|
||||||
|
$this->settings->save();
|
||||||
|
$this->server->setupDynamicProxyConfiguration();
|
||||||
|
if (! $error_show) {
|
||||||
|
$this->dispatch('success', 'Instance settings updated successfully!');
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkManually()
|
||||||
|
{
|
||||||
|
CheckForUpdatesJob::dispatchSync();
|
||||||
|
$this->dispatch('updateAvailable');
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
|
if ($settings->new_version_available) {
|
||||||
|
$this->dispatch('success', 'New version available!');
|
||||||
|
} else {
|
||||||
|
$this->dispatch('success', 'No new version available.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.settings.index');
|
return view('livewire.settings.index');
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Livewire\Settings;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use App\Jobs\DatabaseBackupJob;
|
use App\Jobs\DatabaseBackupJob;
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
@@ -10,7 +10,7 @@ use App\Models\Server;
|
|||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Backup extends Component
|
class SettingsBackup extends Component
|
||||||
{
|
{
|
||||||
public InstanceSettings $settings;
|
public InstanceSettings $settings;
|
||||||
|
|
||||||
@@ -41,8 +41,24 @@ class Backup extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->backup = $this->database?->scheduledBackups->first() ?? null;
|
if (isInstanceAdmin()) {
|
||||||
$this->executions = $this->backup?->executions ?? [];
|
$settings = InstanceSettings::get();
|
||||||
|
$database = StandalonePostgresql::whereName('coolify-db')->first();
|
||||||
|
$s3s = S3Storage::whereTeamId(0)->get() ?? [];
|
||||||
|
if ($database) {
|
||||||
|
if ($database->status !== 'running') {
|
||||||
|
$database->status = 'running';
|
||||||
|
$database->save();
|
||||||
|
}
|
||||||
|
$this->database = $database;
|
||||||
|
}
|
||||||
|
$this->settings = $settings;
|
||||||
|
$this->s3s = $s3s;
|
||||||
|
$this->backup = $this->database?->scheduledBackups?->first() ?? null;
|
||||||
|
$this->executions = $this->backup?->executions ?? [];
|
||||||
|
} else {
|
||||||
|
return redirect()->route('dashboard');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add_coolify_database()
|
public function add_coolify_database()
|
@@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Livewire\Settings;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Notifications\TransactionalEmails\Test;
|
use App\Notifications\TransactionalEmails\Test;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Email extends Component
|
class SettingsEmail extends Component
|
||||||
{
|
{
|
||||||
public InstanceSettings $settings;
|
public InstanceSettings $settings;
|
||||||
|
|
||||||
@@ -42,7 +42,13 @@ class Email extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->emails = auth()->user()->email;
|
if (isInstanceAdmin()) {
|
||||||
|
$this->settings = InstanceSettings::get();
|
||||||
|
$this->emails = auth()->user()->email;
|
||||||
|
} else {
|
||||||
|
return redirect()->route('dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submitFromFields()
|
public function submitFromFields()
|
@@ -1,11 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Livewire\Settings;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use App\Models\OauthSetting;
|
use App\Models\OauthSetting;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Auth extends Component
|
class SettingsOauth extends Component
|
||||||
{
|
{
|
||||||
public $oauth_settings_map;
|
public $oauth_settings_map;
|
||||||
|
|
@@ -3,6 +3,8 @@
|
|||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use App\Actions\Server\UpdateCoolify;
|
use App\Actions\Server\UpdateCoolify;
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Upgrade extends Component
|
class Upgrade extends Component
|
||||||
@@ -15,14 +17,23 @@ class Upgrade extends Component
|
|||||||
|
|
||||||
public string $latestVersion = '';
|
public string $latestVersion = '';
|
||||||
|
|
||||||
|
protected $listeners = ['updateAvailable' => 'checkUpdate'];
|
||||||
|
|
||||||
public function checkUpdate()
|
public function checkUpdate()
|
||||||
{
|
{
|
||||||
$this->latestVersion = get_latest_version_of_coolify();
|
try {
|
||||||
$currentVersion = config('version');
|
$settings = InstanceSettings::get();
|
||||||
version_compare($currentVersion, $this->latestVersion, '<') ? $this->isUpgradeAvailable = true : $this->isUpgradeAvailable = false;
|
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
|
||||||
if (isDev()) {
|
if ($response->successful()) {
|
||||||
$this->isUpgradeAvailable = true;
|
$versions = $response->json();
|
||||||
|
$this->latestVersion = data_get($versions, 'coolify.v4.version');
|
||||||
|
}
|
||||||
|
$this->isUpgradeAvailable = $settings->new_version_available;
|
||||||
|
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upgrade()
|
public function upgrade()
|
||||||
|
@@ -104,6 +104,8 @@ class Application extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
protected $appends = ['server_status'];
|
||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::saving(function ($application) {
|
static::saving(function ($application) {
|
||||||
@@ -232,12 +234,24 @@ class Application extends BaseModel
|
|||||||
public function failedTaskLink($task_uuid)
|
public function failedTaskLink($task_uuid)
|
||||||
{
|
{
|
||||||
if (data_get($this, 'environment.project.uuid')) {
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
return route('project.application.scheduled-tasks', [
|
$route = route('project.application.scheduled-tasks', [
|
||||||
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'environment_name' => data_get($this, 'environment.name'),
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
'application_uuid' => data_get($this, 'uuid'),
|
'application_uuid' => data_get($this, 'uuid'),
|
||||||
'task_uuid' => $task_uuid,
|
'task_uuid' => $task_uuid,
|
||||||
]);
|
]);
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
|
if (data_get($settings, 'fqdn')) {
|
||||||
|
$url = Url::fromString($route);
|
||||||
|
$url = $url->withPort(null);
|
||||||
|
$fqdn = data_get($settings, 'fqdn');
|
||||||
|
$fqdn = str_replace(['http://', 'https://'], '', $fqdn);
|
||||||
|
$url = $url->withHost($fqdn);
|
||||||
|
|
||||||
|
return $url->__toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $route;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -275,12 +289,20 @@ class Application extends BaseModel
|
|||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
get: function () {
|
get: function () {
|
||||||
if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) {
|
if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) {
|
||||||
|
if (str($this->git_repository)->contains('bitbucket')) {
|
||||||
|
return "{$this->source->html_url}/{$this->git_repository}/src/{$this->git_branch}";
|
||||||
|
}
|
||||||
|
|
||||||
return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}";
|
return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}";
|
||||||
}
|
}
|
||||||
// Convert the SSH URL to HTTPS URL
|
// Convert the SSH URL to HTTPS URL
|
||||||
if (strpos($this->git_repository, 'git@') === 0) {
|
if (strpos($this->git_repository, 'git@') === 0) {
|
||||||
$git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
|
$git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
|
||||||
|
|
||||||
|
if (str($this->git_repository)->contains('bitbucket')) {
|
||||||
|
return "https://{$git_repository}/src/{$this->git_branch}";
|
||||||
|
}
|
||||||
|
|
||||||
return "https://{$git_repository}/tree/{$this->git_branch}";
|
return "https://{$git_repository}/tree/{$this->git_branch}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,6 +453,11 @@ class Application extends BaseModel
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isRunning()
|
||||||
|
{
|
||||||
|
return (bool) str($this->status)->startsWith('running');
|
||||||
|
}
|
||||||
|
|
||||||
public function isExited()
|
public function isExited()
|
||||||
{
|
{
|
||||||
return (bool) str($this->status)->startsWith('exited');
|
return (bool) str($this->status)->startsWith('exited');
|
||||||
@@ -441,6 +468,28 @@ class Application extends BaseModel
|
|||||||
return $this->getRawOriginal('status');
|
return $this->getRawOriginal('status');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
if ($this->additional_servers->count() === 0) {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
} else {
|
||||||
|
$additional_servers_status = $this->additional_servers->pluck('pivot.status');
|
||||||
|
$main_server_status = $this->destination->server->isFunctional();
|
||||||
|
foreach ($additional_servers_status as $status) {
|
||||||
|
$server_status = str($status)->before(':')->value();
|
||||||
|
if ($main_server_status !== $server_status) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function status(): Attribute
|
public function status(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
@@ -1270,7 +1319,7 @@ class Application extends BaseModel
|
|||||||
$template = $this->preview_url_template;
|
$template = $this->preview_url_template;
|
||||||
$host = $url->getHost();
|
$host = $url->getHost();
|
||||||
$schema = $url->getScheme();
|
$schema = $url->getScheme();
|
||||||
$random = new Cuid2(7);
|
$random = new Cuid2;
|
||||||
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
||||||
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
||||||
$preview_fqdn = str_replace('{{pr_id}}', $pull_request_id, $preview_fqdn);
|
$preview_fqdn = str_replace('{{pr_id}}', $pull_request_id, $preview_fqdn);
|
||||||
|
@@ -35,6 +35,11 @@ class ApplicationPreview extends BaseModel
|
|||||||
return self::where('application_id', $application_id)->where('pull_request_id', $pull_request_id)->firstOrFail();
|
return self::where('application_id', $application_id)->where('pull_request_id', $pull_request_id)->firstOrFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isRunning()
|
||||||
|
{
|
||||||
|
return (bool) str($this->status)->startsWith('running');
|
||||||
|
}
|
||||||
|
|
||||||
public function application()
|
public function application()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Application::class);
|
return $this->belongsTo(Application::class);
|
||||||
@@ -49,7 +54,7 @@ class ApplicationPreview extends BaseModel
|
|||||||
$template = $this->application->preview_url_template;
|
$template = $this->application->preview_url_template;
|
||||||
$host = $url->getHost();
|
$host = $url->getHost();
|
||||||
$schema = $url->getScheme();
|
$schema = $url->getScheme();
|
||||||
$random = new Cuid2(7);
|
$random = new Cuid2;
|
||||||
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
||||||
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
||||||
$preview_fqdn = str_replace('{{pr_id}}', $this->pull_request_id, $preview_fqdn);
|
$preview_fqdn = str_replace('{{pr_id}}', $this->pull_request_id, $preview_fqdn);
|
||||||
|
@@ -14,7 +14,7 @@ abstract class BaseModel extends Model
|
|||||||
static::creating(function (Model $model) {
|
static::creating(function (Model $model) {
|
||||||
// Generate a UUID if one isn't set
|
// Generate a UUID if one isn't set
|
||||||
if (! $model->uuid) {
|
if (! $model->uuid) {
|
||||||
$model->uuid = (string) new Cuid2(7);
|
$model->uuid = (string) new Cuid2;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,6 @@ namespace App\Models;
|
|||||||
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
@@ -200,28 +199,33 @@ class EnvironmentVariable extends Model
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$environment_variable = trim($environment_variable);
|
$environment_variable = trim($environment_variable);
|
||||||
$type = str($environment_variable)->after('{{')->before('.')->value;
|
$sharedEnvsFound = str($environment_variable)->matchAll('/{{(.*?)}}/');
|
||||||
if (str($environment_variable)->startsWith('{{'.$type) && str($environment_variable)->endsWith('}}')) {
|
if ($sharedEnvsFound->isEmpty()) {
|
||||||
$variable = Str::after($environment_variable, "{$type}.");
|
return $environment_variable;
|
||||||
$variable = Str::before($variable, '}}');
|
}
|
||||||
$variable = str($variable)->trim()->value;
|
foreach ($sharedEnvsFound as $sharedEnv) {
|
||||||
|
$type = str($sharedEnv)->match('/(.*?)\./');
|
||||||
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||||
return $variable;
|
continue;
|
||||||
}
|
}
|
||||||
if ($type === 'environment') {
|
$variable = str($sharedEnv)->match('/\.(.*)/');
|
||||||
|
if ($type->value() === 'environment') {
|
||||||
$id = $resource->environment->id;
|
$id = $resource->environment->id;
|
||||||
} elseif ($type === 'project') {
|
} elseif ($type->value() === 'project') {
|
||||||
$id = $resource->environment->project->id;
|
$id = $resource->environment->project->id;
|
||||||
} else {
|
} elseif ($type->value() === 'team') {
|
||||||
$id = $resource->team()->id;
|
$id = $resource->team()->id;
|
||||||
}
|
}
|
||||||
|
if (is_null($id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$environment_variable_found = SharedEnvironmentVariable::where('type', $type)->where('key', $variable)->where('team_id', $resource->team()->id)->where("{$type}_id", $id)->first();
|
$environment_variable_found = SharedEnvironmentVariable::where('type', $type)->where('key', $variable)->where('team_id', $resource->team()->id)->where("{$type}_id", $id)->first();
|
||||||
if ($environment_variable_found) {
|
if ($environment_variable_found) {
|
||||||
return $environment_variable_found;
|
$environment_variable = str($environment_variable)->replace("{{{$sharedEnv}}}", $environment_variable_found->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $environment_variable;
|
return str($environment_variable)->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function get_environment_variables(?string $environment_variable = null): ?string
|
private function get_environment_variables(?string $environment_variable = null): ?string
|
||||||
|
@@ -18,6 +18,9 @@ class InstanceSettings extends Model implements SendsEmail
|
|||||||
'resale_license' => 'encrypted',
|
'resale_license' => 'encrypted',
|
||||||
'smtp_password' => 'encrypted',
|
'smtp_password' => 'encrypted',
|
||||||
'allowed_ip_ranges' => 'array',
|
'allowed_ip_ranges' => 'array',
|
||||||
|
'is_auto_update_enabled' => 'boolean',
|
||||||
|
'auto_update_frequency' => 'string',
|
||||||
|
'update_check_frequency' => 'string',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function fqdn(): Attribute
|
public function fqdn(): Attribute
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Events\FileStorageChanged;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
|
||||||
class LocalFileVolume extends BaseModel
|
class LocalFileVolume extends BaseModel
|
||||||
@@ -33,16 +34,23 @@ class LocalFileVolume extends BaseModel
|
|||||||
$workdir = $this->resource->workdir();
|
$workdir = $this->resource->workdir();
|
||||||
$server = $this->resource->destination->server;
|
$server = $this->resource->destination->server;
|
||||||
}
|
}
|
||||||
$commands = collect([
|
$commands = collect([]);
|
||||||
"cd $workdir",
|
|
||||||
]);
|
|
||||||
$fs_path = data_get($this, 'fs_path');
|
$fs_path = data_get($this, 'fs_path');
|
||||||
|
$isFile = instant_remote_process(["test -f $fs_path && echo OK || echo NOK"], $server);
|
||||||
|
$isDir = instant_remote_process(["test -d $fs_path && echo OK || echo NOK"], $server);
|
||||||
if ($fs_path && $fs_path != '/' && $fs_path != '.' && $fs_path != '..') {
|
if ($fs_path && $fs_path != '/' && $fs_path != '.' && $fs_path != '..') {
|
||||||
$commands->push("rm -rf $fs_path");
|
ray($isFile, $isDir);
|
||||||
}
|
if ($isFile === 'OK') {
|
||||||
ray($commands);
|
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
||||||
|
|
||||||
return instant_remote_process($commands, $server);
|
} elseif ($isDir === 'OK') {
|
||||||
|
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
||||||
|
$commands->push("rmdir $fs_path > /dev/null 2>&1 || true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($commands->count() > 0) {
|
||||||
|
return instant_remote_process($commands, $server);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveStorageOnServer()
|
public function saveStorageOnServer()
|
||||||
@@ -55,13 +63,10 @@ class LocalFileVolume extends BaseModel
|
|||||||
$workdir = $this->resource->workdir();
|
$workdir = $this->resource->workdir();
|
||||||
$server = $this->resource->destination->server;
|
$server = $this->resource->destination->server;
|
||||||
}
|
}
|
||||||
$commands = collect([
|
$commands = collect([]);
|
||||||
"mkdir -p $workdir > /dev/null 2>&1 || true",
|
if ($this->is_directory) {
|
||||||
"cd $workdir",
|
|
||||||
]);
|
|
||||||
$is_directory = $this->is_directory;
|
|
||||||
if ($is_directory) {
|
|
||||||
$commands->push("mkdir -p $this->fs_path > /dev/null 2>&1 || true");
|
$commands->push("mkdir -p $this->fs_path > /dev/null 2>&1 || true");
|
||||||
|
$commands->push("cd $workdir");
|
||||||
}
|
}
|
||||||
if (str($this->fs_path)->startsWith('.') || str($this->fs_path)->startsWith('/') || str($this->fs_path)->startsWith('~')) {
|
if (str($this->fs_path)->startsWith('.') || str($this->fs_path)->startsWith('/') || str($this->fs_path)->startsWith('~')) {
|
||||||
$parent_dir = str($this->fs_path)->beforeLast('/');
|
$parent_dir = str($this->fs_path)->beforeLast('/');
|
||||||
@@ -79,8 +84,11 @@ class LocalFileVolume extends BaseModel
|
|||||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||||
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
||||||
|
$content = instant_remote_process(["cat $path"], $server, false);
|
||||||
$fileVolume->is_directory = false;
|
$fileVolume->is_directory = false;
|
||||||
|
$fileVolume->content = $content;
|
||||||
$fileVolume->save();
|
$fileVolume->save();
|
||||||
|
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
||||||
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
||||||
} elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
|
} elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
|
||||||
$fileVolume->is_directory = true;
|
$fileVolume->is_directory = true;
|
||||||
|
@@ -5,6 +5,7 @@ namespace App\Models;
|
|||||||
use App\Actions\Server\InstallDocker;
|
use App\Actions\Server\InstallDocker;
|
||||||
use App\Enums\ProxyTypes;
|
use App\Enums\ProxyTypes;
|
||||||
use App\Jobs\PullSentinelImageJob;
|
use App\Jobs\PullSentinelImageJob;
|
||||||
|
use App\Notifications\Server\Revived;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -150,7 +151,7 @@ class Server extends BaseModel
|
|||||||
$dynamic_conf_path = $this->proxyPath().'/dynamic';
|
$dynamic_conf_path = $this->proxyPath().'/dynamic';
|
||||||
$proxy_type = $this->proxyType();
|
$proxy_type = $this->proxyType();
|
||||||
$redirect_url = $this->proxy->redirect_url;
|
$redirect_url = $this->proxy->redirect_url;
|
||||||
if ($proxy_type === 'TRAEFIK_V2') {
|
if ($proxy_type === ProxyTypes::TRAEFIK->value) {
|
||||||
$default_redirect_file = "$dynamic_conf_path/default_redirect_404.yaml";
|
$default_redirect_file = "$dynamic_conf_path/default_redirect_404.yaml";
|
||||||
} elseif ($proxy_type === 'CADDY') {
|
} elseif ($proxy_type === 'CADDY') {
|
||||||
$default_redirect_file = "$dynamic_conf_path/default_redirect_404.caddy";
|
$default_redirect_file = "$dynamic_conf_path/default_redirect_404.caddy";
|
||||||
@@ -180,7 +181,7 @@ respond 404
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($proxy_type === 'TRAEFIK_V2') {
|
if ($proxy_type === ProxyTypes::TRAEFIK->value) {
|
||||||
$dynamic_conf = [
|
$dynamic_conf = [
|
||||||
'http' => [
|
'http' => [
|
||||||
'routers' => [
|
'routers' => [
|
||||||
@@ -254,7 +255,7 @@ respond 404
|
|||||||
{
|
{
|
||||||
$settings = \App\Models\InstanceSettings::get();
|
$settings = \App\Models\InstanceSettings::get();
|
||||||
$dynamic_config_path = $this->proxyPath().'/dynamic';
|
$dynamic_config_path = $this->proxyPath().'/dynamic';
|
||||||
if ($this->proxyType() === 'TRAEFIK_V2') {
|
if ($this->proxyType() === ProxyTypes::TRAEFIK->value) {
|
||||||
$file = "$dynamic_config_path/coolify.yaml";
|
$file = "$dynamic_config_path/coolify.yaml";
|
||||||
if (empty($settings->fqdn) || (isCloud() && $this->id !== 0) || ! $this->isLocalhost()) {
|
if (empty($settings->fqdn) || (isCloud() && $this->id !== 0) || ! $this->isLocalhost()) {
|
||||||
instant_remote_process([
|
instant_remote_process([
|
||||||
@@ -402,7 +403,7 @@ $schema://$host {
|
|||||||
// TODO: should use /traefik for already exisiting configurations?
|
// TODO: should use /traefik for already exisiting configurations?
|
||||||
// Should move everything except /caddy and /nginx to /traefik
|
// Should move everything except /caddy and /nginx to /traefik
|
||||||
// The code needs to be modified as well, so maybe it does not worth it
|
// The code needs to be modified as well, so maybe it does not worth it
|
||||||
if ($proxyType === ProxyTypes::TRAEFIK_V2->value) {
|
if ($proxyType === ProxyTypes::TRAEFIK->value) {
|
||||||
$proxy_path = $proxy_path;
|
$proxy_path = $proxy_path;
|
||||||
} elseif ($proxyType === ProxyTypes::CADDY->value) {
|
} elseif ($proxyType === ProxyTypes::CADDY->value) {
|
||||||
$proxy_path = $proxy_path.'/caddy';
|
$proxy_path = $proxy_path.'/caddy';
|
||||||
@@ -420,7 +421,7 @@ $schema://$host {
|
|||||||
// return $proxyType;
|
// return $proxyType;
|
||||||
// }
|
// }
|
||||||
// if (is_null($proxyType)) {
|
// if (is_null($proxyType)) {
|
||||||
// $this->proxy->type = ProxyTypes::TRAEFIK_V2->value;
|
// $this->proxy->type = ProxyTypes::TRAEFIK->value;
|
||||||
// $this->proxy->status = ProxyStatus::EXITED->value;
|
// $this->proxy->status = ProxyStatus::EXITED->value;
|
||||||
// $this->save();
|
// $this->save();
|
||||||
// }
|
// }
|
||||||
@@ -677,7 +678,49 @@ $schema://$host {
|
|||||||
return instant_remote_process(["docker start $id"], $this);
|
return instant_remote_process(["docker start $id"], $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContainers(): Collection
|
public function getContainers()
|
||||||
|
{
|
||||||
|
$containers = collect([]);
|
||||||
|
$containerReplicates = collect([]);
|
||||||
|
if ($this->isSwarm()) {
|
||||||
|
$containers = instant_remote_process(["docker service inspect $(docker service ls -q) --format '{{json .}}'"], $this, false);
|
||||||
|
$containers = format_docker_command_output_to_json($containers);
|
||||||
|
$containerReplicates = instant_remote_process(["docker service ls --format '{{json .}}'"], $this, false);
|
||||||
|
if ($containerReplicates) {
|
||||||
|
$containerReplicates = format_docker_command_output_to_json($containerReplicates);
|
||||||
|
foreach ($containerReplicates as $containerReplica) {
|
||||||
|
$name = data_get($containerReplica, 'Name');
|
||||||
|
$containers = $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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this, false);
|
||||||
|
$containers = format_docker_command_output_to_json($containers);
|
||||||
|
$containerReplicates = collect([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'containers' => $containers ?? collect([]),
|
||||||
|
'containerReplicates' => $containerReplicates ?? collect([]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContainersWithSentinel(): Collection
|
||||||
{
|
{
|
||||||
$sentinel_found = instant_remote_process(['docker inspect coolify-sentinel'], $this, false);
|
$sentinel_found = instant_remote_process(['docker inspect coolify-sentinel'], $this, false);
|
||||||
$sentinel_found = json_decode($sentinel_found, true);
|
$sentinel_found = json_decode($sentinel_found, true);
|
||||||
@@ -690,21 +733,6 @@ $schema://$host {
|
|||||||
$containers = data_get(json_decode($containers, true), 'containers', []);
|
$containers = data_get(json_decode($containers, true), 'containers', []);
|
||||||
|
|
||||||
return collect($containers);
|
return collect($containers);
|
||||||
} else {
|
|
||||||
if ($this->isSwarm()) {
|
|
||||||
$containers = instant_remote_process(["docker service inspect $(docker service ls -q) --format '{{json .}}'"], $this, false);
|
|
||||||
} else {
|
|
||||||
$containers = instant_remote_process(['docker container ls -q'], $this, false);
|
|
||||||
if (! $containers) {
|
|
||||||
return collect([]);
|
|
||||||
}
|
|
||||||
$containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this, false);
|
|
||||||
}
|
|
||||||
if (is_null($containers)) {
|
|
||||||
return collect([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return format_docker_command_output_to_json($containers);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
|
use Spatie\Url\Url;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
#[OA\Schema(
|
#[OA\Schema(
|
||||||
@@ -38,6 +40,8 @@ class Service extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
protected $appends = ['server_status'];
|
||||||
|
|
||||||
public function isConfigurationChanged(bool $save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$domains = $this->applications()->get()->pluck('fqdn')->sort()->toArray();
|
$domains = $this->applications()->get()->pluck('fqdn')->sort()->toArray();
|
||||||
@@ -76,6 +80,20 @@ class Service extends BaseModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRunning()
|
||||||
|
{
|
||||||
|
return (bool) str($this->status())->contains('running');
|
||||||
|
}
|
||||||
|
|
||||||
public function isExited()
|
public function isExited()
|
||||||
{
|
{
|
||||||
return (bool) str($this->status())->contains('exited');
|
return (bool) str($this->status())->contains('exited');
|
||||||
@@ -575,6 +593,30 @@ class Service extends BaseModel
|
|||||||
|
|
||||||
$fields->put('Vaultwarden', $data);
|
$fields->put('Vaultwarden', $data);
|
||||||
break;
|
break;
|
||||||
|
case str($image)->contains('gitlab/gitlab'):
|
||||||
|
$password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_GITLAB')->first();
|
||||||
|
$data = collect([]);
|
||||||
|
if ($password) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Root Password' => [
|
||||||
|
'key' => data_get($password, 'key'),
|
||||||
|
'value' => data_get($password, 'value'),
|
||||||
|
'rules' => 'required',
|
||||||
|
'isPassword' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$data = $data->merge([
|
||||||
|
'Root User' => [
|
||||||
|
'key' => 'N/A',
|
||||||
|
'value' => 'root',
|
||||||
|
'rules' => 'required',
|
||||||
|
'isPassword' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$fields->put('GitLab', $data->toArray());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$databases = $this->databases()->get();
|
$databases = $this->databases()->get();
|
||||||
@@ -764,12 +806,24 @@ class Service extends BaseModel
|
|||||||
public function failedTaskLink($task_uuid)
|
public function failedTaskLink($task_uuid)
|
||||||
{
|
{
|
||||||
if (data_get($this, 'environment.project.uuid')) {
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
return route('project.service.scheduled-tasks', [
|
$route = route('project.service.scheduled-tasks', [
|
||||||
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'environment_name' => data_get($this, 'environment.name'),
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
'service_uuid' => data_get($this, 'uuid'),
|
'service_uuid' => data_get($this, 'uuid'),
|
||||||
'task_uuid' => $task_uuid,
|
'task_uuid' => $task_uuid,
|
||||||
]);
|
]);
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
|
if (data_get($settings, 'fqdn')) {
|
||||||
|
$url = Url::fromString($route);
|
||||||
|
$url = $url->withPort(null);
|
||||||
|
$fqdn = data_get($settings, 'fqdn');
|
||||||
|
$fqdn = str_replace(['http://', 'https://'], '', $fqdn);
|
||||||
|
$url = $url->withHost($fqdn);
|
||||||
|
|
||||||
|
return $url->__toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $route;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@@ -14,7 +14,7 @@ class StandaloneClickhouse extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $appends = ['internal_db_url', 'external_db_url', 'database_type'];
|
protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'clickhouse_password' => 'encrypted',
|
'clickhouse_password' => 'encrypted',
|
||||||
@@ -40,6 +40,15 @@ class StandaloneClickhouse extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function isConfigurationChanged(bool $save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$newConfigHash = $this->image.$this->ports_mappings;
|
$newConfigHash = $this->image.$this->ports_mappings;
|
||||||
|
@@ -14,7 +14,7 @@ class StandaloneDragonfly extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $appends = ['internal_db_url', 'external_db_url', 'database_type'];
|
protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'dragonfly_password' => 'encrypted',
|
'dragonfly_password' => 'encrypted',
|
||||||
@@ -40,6 +40,15 @@ class StandaloneDragonfly extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function isConfigurationChanged(bool $save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$newConfigHash = $this->image.$this->ports_mappings;
|
$newConfigHash = $this->image.$this->ports_mappings;
|
||||||
|
@@ -14,7 +14,7 @@ class StandaloneKeydb extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $appends = ['internal_db_url', 'external_db_url'];
|
protected $appends = ['internal_db_url', 'external_db_url', 'server_status'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'keydb_password' => 'encrypted',
|
'keydb_password' => 'encrypted',
|
||||||
@@ -40,6 +40,15 @@ class StandaloneKeydb extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function isConfigurationChanged(bool $save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$newConfigHash = $this->image.$this->ports_mappings.$this->keydb_conf;
|
$newConfigHash = $this->image.$this->ports_mappings.$this->keydb_conf;
|
||||||
|
@@ -14,7 +14,7 @@ class StandaloneMariadb extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $appends = ['internal_db_url', 'external_db_url', 'database_type'];
|
protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'mariadb_password' => 'encrypted',
|
'mariadb_password' => 'encrypted',
|
||||||
@@ -40,6 +40,15 @@ class StandaloneMariadb extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function isConfigurationChanged(bool $save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$newConfigHash = $this->image.$this->ports_mappings.$this->mariadb_conf;
|
$newConfigHash = $this->image.$this->ports_mappings.$this->mariadb_conf;
|
||||||
|
@@ -14,7 +14,7 @@ class StandaloneMongodb extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $appends = ['internal_db_url', 'external_db_url', 'database_type'];
|
protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status'];
|
||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
@@ -44,6 +44,15 @@ class StandaloneMongodb extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function isConfigurationChanged(bool $save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$newConfigHash = $this->image.$this->ports_mappings.$this->mongo_conf;
|
$newConfigHash = $this->image.$this->ports_mappings.$this->mongo_conf;
|
||||||
|
@@ -14,7 +14,7 @@ class StandaloneMysql extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $appends = ['internal_db_url', 'external_db_url', 'database_type'];
|
protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'mysql_password' => 'encrypted',
|
'mysql_password' => 'encrypted',
|
||||||
@@ -41,6 +41,15 @@ class StandaloneMysql extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function isConfigurationChanged(bool $save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$newConfigHash = $this->image.$this->ports_mappings.$this->mysql_conf;
|
$newConfigHash = $this->image.$this->ports_mappings.$this->mysql_conf;
|
||||||
|
@@ -14,7 +14,7 @@ class StandalonePostgresql extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $appends = ['internal_db_url', 'external_db_url', 'database_type'];
|
protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'init_scripts' => 'array',
|
'init_scripts' => 'array',
|
||||||
@@ -46,6 +46,15 @@ class StandalonePostgresql extends BaseModel
|
|||||||
return database_configuration_dir()."/{$this->uuid}";
|
return database_configuration_dir()."/{$this->uuid}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function delete_configurations()
|
public function delete_configurations()
|
||||||
{
|
{
|
||||||
$server = data_get($this, 'destination.server');
|
$server = data_get($this, 'destination.server');
|
||||||
|
@@ -14,7 +14,7 @@ class StandaloneRedis extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $appends = ['internal_db_url', 'external_db_url', 'database_type'];
|
protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status'];
|
||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
@@ -36,6 +36,15 @@ class StandaloneRedis extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serverStatus(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->destination->server->isFunctional();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function isConfigurationChanged(bool $save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$newConfigHash = $this->image.$this->ports_mappings.$this->redis_conf;
|
$newConfigHash = $this->image.$this->ports_mappings.$this->redis_conf;
|
||||||
|
@@ -180,6 +180,10 @@ class User extends Authenticatable implements SendsEmail
|
|||||||
{
|
{
|
||||||
$found_root_team = auth()->user()->teams->filter(function ($team) {
|
$found_root_team = auth()->user()->teams->filter(function ($team) {
|
||||||
if ($team->id == 0) {
|
if ($team->id == 0) {
|
||||||
|
if (! auth()->user()->isAdmin()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,6 +12,7 @@ use Illuminate\Bus\Queueable;
|
|||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
|
|
||||||
class Revived extends Notification implements ShouldQueue
|
class Revived extends Notification implements ShouldQueue
|
||||||
{
|
{
|
||||||
@@ -44,8 +45,20 @@ class Revived extends Notification implements ShouldQueue
|
|||||||
if ($isTelegramEnabled) {
|
if ($isTelegramEnabled) {
|
||||||
$channels[] = TelegramChannel::class;
|
$channels[] = TelegramChannel::class;
|
||||||
}
|
}
|
||||||
|
$executed = RateLimiter::attempt(
|
||||||
|
'notification-server-revived-'.$this->server->uuid,
|
||||||
|
1,
|
||||||
|
function () use ($channels) {
|
||||||
|
return $channels;
|
||||||
|
},
|
||||||
|
7200,
|
||||||
|
);
|
||||||
|
|
||||||
return $channels;
|
if (! $executed) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $executed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
|
@@ -10,6 +10,7 @@ use Illuminate\Bus\Queueable;
|
|||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
|
|
||||||
class Unreachable extends Notification implements ShouldQueue
|
class Unreachable extends Notification implements ShouldQueue
|
||||||
{
|
{
|
||||||
@@ -35,8 +36,20 @@ class Unreachable extends Notification implements ShouldQueue
|
|||||||
if ($isTelegramEnabled) {
|
if ($isTelegramEnabled) {
|
||||||
$channels[] = TelegramChannel::class;
|
$channels[] = TelegramChannel::class;
|
||||||
}
|
}
|
||||||
|
$executed = RateLimiter::attempt(
|
||||||
|
'notification-server-unreachable-'.$this->server->uuid,
|
||||||
|
1,
|
||||||
|
function () use ($channels) {
|
||||||
|
return $channels;
|
||||||
|
},
|
||||||
|
7200,
|
||||||
|
);
|
||||||
|
|
||||||
return $channels;
|
if (! $executed) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $executed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
|
@@ -44,6 +44,8 @@ class FortifyServiceProvider extends ServiceProvider
|
|||||||
{
|
{
|
||||||
Fortify::createUsersUsing(CreateNewUser::class);
|
Fortify::createUsersUsing(CreateNewUser::class);
|
||||||
Fortify::registerView(function () {
|
Fortify::registerView(function () {
|
||||||
|
$isFirstUser = User::count() === 0;
|
||||||
|
|
||||||
$settings = \App\Models\InstanceSettings::get();
|
$settings = \App\Models\InstanceSettings::get();
|
||||||
if (! $settings->is_registration_enabled) {
|
if (! $settings->is_registration_enabled) {
|
||||||
return redirect()->route('login');
|
return redirect()->route('login');
|
||||||
@@ -51,7 +53,9 @@ class FortifyServiceProvider extends ServiceProvider
|
|||||||
if (config('coolify.waitlist')) {
|
if (config('coolify.waitlist')) {
|
||||||
return redirect()->route('waitlist.index');
|
return redirect()->route('waitlist.index');
|
||||||
} else {
|
} else {
|
||||||
return view('auth.register');
|
return view('auth.register', [
|
||||||
|
'isFirstUser' => $isFirstUser,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -30,7 +30,7 @@ class Datalist extends Component
|
|||||||
public function render(): View|Closure|string
|
public function render(): View|Closure|string
|
||||||
{
|
{
|
||||||
if (is_null($this->id)) {
|
if (is_null($this->id)) {
|
||||||
$this->id = new Cuid2(7);
|
$this->id = new Cuid2;
|
||||||
}
|
}
|
||||||
if (is_null($this->name)) {
|
if (is_null($this->name)) {
|
||||||
$this->name = $this->id;
|
$this->name = $this->id;
|
||||||
|
@@ -27,7 +27,7 @@ class Input extends Component
|
|||||||
public function render(): View|Closure|string
|
public function render(): View|Closure|string
|
||||||
{
|
{
|
||||||
if (is_null($this->id)) {
|
if (is_null($this->id)) {
|
||||||
$this->id = new Cuid2(7);
|
$this->id = new Cuid2;
|
||||||
}
|
}
|
||||||
if (is_null($this->name)) {
|
if (is_null($this->name)) {
|
||||||
$this->name = $this->id;
|
$this->name = $this->id;
|
||||||
|
@@ -30,7 +30,7 @@ class Select extends Component
|
|||||||
public function render(): View|Closure|string
|
public function render(): View|Closure|string
|
||||||
{
|
{
|
||||||
if (is_null($this->id)) {
|
if (is_null($this->id)) {
|
||||||
$this->id = new Cuid2(7);
|
$this->id = new Cuid2;
|
||||||
}
|
}
|
||||||
if (is_null($this->name)) {
|
if (is_null($this->name)) {
|
||||||
$this->name = $this->id;
|
$this->name = $this->id;
|
||||||
|
@@ -41,7 +41,7 @@ class Textarea extends Component
|
|||||||
public function render(): View|Closure|string
|
public function render(): View|Closure|string
|
||||||
{
|
{
|
||||||
if (is_null($this->id)) {
|
if (is_null($this->id)) {
|
||||||
$this->id = new Cuid2(7);
|
$this->id = new Cuid2;
|
||||||
}
|
}
|
||||||
if (is_null($this->name)) {
|
if (is_null($this->name)) {
|
||||||
$this->name = $this->id;
|
$this->name = $this->id;
|
||||||
|
@@ -14,7 +14,7 @@ use Visus\Cuid2\Cuid2;
|
|||||||
|
|
||||||
function generate_database_name(string $type): string
|
function generate_database_name(string $type): string
|
||||||
{
|
{
|
||||||
$cuid = new Cuid2(7);
|
$cuid = new Cuid2;
|
||||||
|
|
||||||
return $type.'-database-'.$cuid;
|
return $type.'-database-'.$cuid;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Enums\ProxyTypes;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
@@ -338,7 +339,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
|||||||
foreach ($domains as $loop => $domain) {
|
foreach ($domains as $loop => $domain) {
|
||||||
try {
|
try {
|
||||||
if ($generate_unique_uuid) {
|
if ($generate_unique_uuid) {
|
||||||
$uuid = new Cuid2(7);
|
$uuid = new Cuid2;
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = Url::fromString($domain);
|
$url = Url::fromString($domain);
|
||||||
@@ -539,26 +540,55 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
|||||||
if ($pull_request_id === 0) {
|
if ($pull_request_id === 0) {
|
||||||
if ($application->fqdn) {
|
if ($application->fqdn) {
|
||||||
$domains = str(data_get($application, 'fqdn'))->explode(',');
|
$domains = str(data_get($application, 'fqdn'))->explode(',');
|
||||||
$labels = $labels->merge(fqdnLabelsForTraefik(
|
$shouldGenerateLabelsExactly = $application->destination->server->settings->generate_exact_labels;
|
||||||
uuid: $appUuid,
|
if ($shouldGenerateLabelsExactly) {
|
||||||
domains: $domains,
|
switch ($application->destination->server->proxyType()) {
|
||||||
onlyPort: $onlyPort,
|
case ProxyTypes::TRAEFIK->value:
|
||||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
$labels = $labels->merge(fqdnLabelsForTraefik(
|
||||||
is_gzip_enabled: $application->isGzipEnabled(),
|
uuid: $appUuid,
|
||||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
domains: $domains,
|
||||||
redirect_direction: $application->redirect
|
onlyPort: $onlyPort,
|
||||||
));
|
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||||
// Add Caddy labels
|
is_gzip_enabled: $application->isGzipEnabled(),
|
||||||
$labels = $labels->merge(fqdnLabelsForCaddy(
|
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||||
network: $application->destination->network,
|
redirect_direction: $application->redirect
|
||||||
uuid: $appUuid,
|
));
|
||||||
domains: $domains,
|
break;
|
||||||
onlyPort: $onlyPort,
|
case ProxyTypes::CADDY->value:
|
||||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
$labels = $labels->merge(fqdnLabelsForCaddy(
|
||||||
is_gzip_enabled: $application->isGzipEnabled(),
|
network: $application->destination->network,
|
||||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
uuid: $appUuid,
|
||||||
redirect_direction: $application->redirect
|
domains: $domains,
|
||||||
));
|
onlyPort: $onlyPort,
|
||||||
|
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||||
|
is_gzip_enabled: $application->isGzipEnabled(),
|
||||||
|
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||||
|
redirect_direction: $application->redirect
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$labels = $labels->merge(fqdnLabelsForTraefik(
|
||||||
|
uuid: $appUuid,
|
||||||
|
domains: $domains,
|
||||||
|
onlyPort: $onlyPort,
|
||||||
|
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||||
|
is_gzip_enabled: $application->isGzipEnabled(),
|
||||||
|
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||||
|
redirect_direction: $application->redirect
|
||||||
|
));
|
||||||
|
$labels = $labels->merge(fqdnLabelsForCaddy(
|
||||||
|
network: $application->destination->network,
|
||||||
|
uuid: $appUuid,
|
||||||
|
domains: $domains,
|
||||||
|
onlyPort: $onlyPort,
|
||||||
|
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||||
|
is_gzip_enabled: $application->isGzipEnabled(),
|
||||||
|
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||||
|
redirect_direction: $application->redirect
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (data_get($preview, 'fqdn')) {
|
if (data_get($preview, 'fqdn')) {
|
||||||
@@ -566,24 +596,50 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
|||||||
} else {
|
} else {
|
||||||
$domains = collect([]);
|
$domains = collect([]);
|
||||||
}
|
}
|
||||||
$labels = $labels->merge(fqdnLabelsForTraefik(
|
$shouldGenerateLabelsExactly = $application->destination->server->settings->generate_exact_labels;
|
||||||
uuid: $appUuid,
|
if ($shouldGenerateLabelsExactly) {
|
||||||
domains: $domains,
|
switch ($application->destination->server->proxyType()) {
|
||||||
onlyPort: $onlyPort,
|
case ProxyTypes::TRAEFIK->value:
|
||||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
$labels = $labels->merge(fqdnLabelsForTraefik(
|
||||||
is_gzip_enabled: $application->isGzipEnabled(),
|
uuid: $appUuid,
|
||||||
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
domains: $domains,
|
||||||
));
|
onlyPort: $onlyPort,
|
||||||
// Add Caddy labels
|
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||||
$labels = $labels->merge(fqdnLabelsForCaddy(
|
is_gzip_enabled: $application->isGzipEnabled(),
|
||||||
network: $application->destination->network,
|
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
||||||
uuid: $appUuid,
|
));
|
||||||
domains: $domains,
|
break;
|
||||||
onlyPort: $onlyPort,
|
case ProxyTypes::CADDY->value:
|
||||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
$labels = $labels->merge(fqdnLabelsForCaddy(
|
||||||
is_gzip_enabled: $application->isGzipEnabled(),
|
network: $application->destination->network,
|
||||||
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
uuid: $appUuid,
|
||||||
));
|
domains: $domains,
|
||||||
|
onlyPort: $onlyPort,
|
||||||
|
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||||
|
is_gzip_enabled: $application->isGzipEnabled(),
|
||||||
|
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$labels = $labels->merge(fqdnLabelsForTraefik(
|
||||||
|
uuid: $appUuid,
|
||||||
|
domains: $domains,
|
||||||
|
onlyPort: $onlyPort,
|
||||||
|
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||||
|
is_gzip_enabled: $application->isGzipEnabled(),
|
||||||
|
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
||||||
|
));
|
||||||
|
$labels = $labels->merge(fqdnLabelsForCaddy(
|
||||||
|
network: $application->destination->network,
|
||||||
|
uuid: $appUuid,
|
||||||
|
domains: $domains,
|
||||||
|
onlyPort: $onlyPort,
|
||||||
|
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||||
|
is_gzip_enabled: $application->isGzipEnabled(),
|
||||||
|
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@ function collectProxyDockerNetworksByServer(Server $server)
|
|||||||
}
|
}
|
||||||
function collectDockerNetworksByServer(Server $server)
|
function collectDockerNetworksByServer(Server $server)
|
||||||
{
|
{
|
||||||
|
$allNetworks = collect([]);
|
||||||
if ($server->isSwarm()) {
|
if ($server->isSwarm()) {
|
||||||
$networks = collect($server->swarmDockers)->map(function ($docker) {
|
$networks = collect($server->swarmDockers)->map(function ($docker) {
|
||||||
return $docker['network'];
|
return $docker['network'];
|
||||||
@@ -34,18 +35,28 @@ function collectDockerNetworksByServer(Server $server)
|
|||||||
return $docker['network'];
|
return $docker['network'];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
$allNetworks = $allNetworks->merge($networks);
|
||||||
// Service networks
|
// Service networks
|
||||||
foreach ($server->services()->get() as $service) {
|
foreach ($server->services()->get() as $service) {
|
||||||
$networks->push($service->networks());
|
if ($service->isRunning()) {
|
||||||
|
$networks->push($service->networks());
|
||||||
|
}
|
||||||
|
$allNetworks->push($service->networks());
|
||||||
}
|
}
|
||||||
// Docker compose based apps
|
// Docker compose based apps
|
||||||
$docker_compose_apps = $server->dockerComposeBasedApplications();
|
$docker_compose_apps = $server->dockerComposeBasedApplications();
|
||||||
foreach ($docker_compose_apps as $app) {
|
foreach ($docker_compose_apps as $app) {
|
||||||
$networks->push($app->uuid);
|
if ($app->isRunning()) {
|
||||||
|
$networks->push($app->uuid);
|
||||||
|
}
|
||||||
|
$allNetworks->push($app->uuid);
|
||||||
}
|
}
|
||||||
// Docker compose based preview deployments
|
// Docker compose based preview deployments
|
||||||
$docker_compose_previews = $server->dockerComposeBasedPreviewDeployments();
|
$docker_compose_previews = $server->dockerComposeBasedPreviewDeployments();
|
||||||
foreach ($docker_compose_previews as $preview) {
|
foreach ($docker_compose_previews as $preview) {
|
||||||
|
if (! $preview->isRunning()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$pullRequestId = $preview->pull_request_id;
|
$pullRequestId = $preview->pull_request_id;
|
||||||
$applicationId = $preview->application_id;
|
$applicationId = $preview->application_id;
|
||||||
$application = Application::find($applicationId);
|
$application = Application::find($applicationId);
|
||||||
@@ -54,23 +65,30 @@ function collectDockerNetworksByServer(Server $server)
|
|||||||
}
|
}
|
||||||
$network = "{$application->uuid}-{$pullRequestId}";
|
$network = "{$application->uuid}-{$pullRequestId}";
|
||||||
$networks->push($network);
|
$networks->push($network);
|
||||||
|
$allNetworks->push($network);
|
||||||
}
|
}
|
||||||
$networks = collect($networks)->flatten()->unique();
|
$networks = collect($networks)->flatten()->unique();
|
||||||
|
$allNetworks = $allNetworks->flatten()->unique();
|
||||||
if ($server->isSwarm()) {
|
if ($server->isSwarm()) {
|
||||||
if ($networks->count() === 0) {
|
if ($networks->count() === 0) {
|
||||||
$networks = collect(['coolify-overlay']);
|
$networks = collect(['coolify-overlay']);
|
||||||
|
$allNetworks = collect(['coolify-overlay']);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($networks->count() === 0) {
|
if ($networks->count() === 0) {
|
||||||
$networks = collect(['coolify']);
|
$networks = collect(['coolify']);
|
||||||
|
$allNetworks = collect(['coolify']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $networks;
|
return [
|
||||||
|
'networks' => $networks,
|
||||||
|
'allNetworks' => $allNetworks,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
function connectProxyToNetworks(Server $server)
|
function connectProxyToNetworks(Server $server)
|
||||||
{
|
{
|
||||||
$networks = collectDockerNetworksByServer($server);
|
['networks' => $networks] = collectDockerNetworksByServer($server);
|
||||||
if ($server->isSwarm()) {
|
if ($server->isSwarm()) {
|
||||||
$commands = $networks->map(function ($network) {
|
$commands = $networks->map(function ($network) {
|
||||||
return [
|
return [
|
||||||
@@ -118,7 +136,7 @@ function generate_default_proxy_configuration(Server $server)
|
|||||||
'external' => true,
|
'external' => true,
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
if ($proxy_type === 'TRAEFIK_V2') {
|
if ($proxy_type === ProxyTypes::TRAEFIK->value) {
|
||||||
$labels = [
|
$labels = [
|
||||||
'traefik.enable=true',
|
'traefik.enable=true',
|
||||||
'traefik.http.routers.traefik.entrypoints=http',
|
'traefik.http.routers.traefik.entrypoints=http',
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user