mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-23 20:49:29 +00:00
Compare commits
62 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bb6de188c | ||
|
|
61f58fa30f | ||
|
|
026f3fd72d | ||
|
|
9a706d55b4 | ||
|
|
9646969107 | ||
|
|
df433efe62 | ||
|
|
efa7cab3e2 | ||
|
|
a386a1bde5 | ||
|
|
cc1bf023be | ||
|
|
edb06fa233 | ||
|
|
abdb8074b1 | ||
|
|
157da798dd | ||
|
|
9c5501326e | ||
|
|
3ea462efc9 | ||
|
|
f77df5b732 | ||
|
|
b77074fe4e | ||
|
|
a7b7d3fa32 | ||
|
|
f4f3034389 | ||
|
|
4b2ffb456f | ||
|
|
e17ff99c5b | ||
|
|
1cf036bbc6 | ||
|
|
da4c2ee60f | ||
|
|
fcf7c5ddd5 | ||
|
|
27926322e1 | ||
|
|
c735ff545e | ||
|
|
b4f048b028 | ||
|
|
54a57d217f | ||
|
|
cf28490acc | ||
|
|
019670d5d1 | ||
|
|
b07cc500e7 | ||
|
|
82c235d5af | ||
|
|
307e4a6990 | ||
|
|
ddb7af63a6 | ||
|
|
7a429ee5bb | ||
|
|
bb591604ac | ||
|
|
81f7a65dd5 | ||
|
|
4b313bb1c6 | ||
|
|
aba0b2f13c | ||
|
|
9a284e47da | ||
|
|
9f2fbc661a | ||
|
|
949407368e | ||
|
|
93c65f6a79 | ||
|
|
d9fe16a3ee | ||
|
|
adaca4d4e3 | ||
|
|
a6d5f3038c | ||
|
|
4d49132821 | ||
|
|
c287276d0e | ||
|
|
e89868c692 | ||
|
|
f93317cd2e | ||
|
|
8412802f4d | ||
|
|
53c20e1e99 | ||
|
|
3c8c8e20b1 | ||
|
|
49f8abcd79 | ||
|
|
4a4d73b87b | ||
|
|
046eab3776 | ||
|
|
17c0e91a0d | ||
|
|
fe4a0ae166 | ||
|
|
52c84f8d22 | ||
|
|
b22fecb615 | ||
|
|
23b7fc3c54 | ||
|
|
1efb1235b4 | ||
|
|
0924070a13 |
2
.github/workflows/development-build.yml
vendored
2
.github/workflows/development-build.yml
vendored
@@ -52,7 +52,7 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next-aarch64
|
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next-aarch64
|
||||||
merge-manifest:
|
merge-manifest:
|
||||||
runs-on: [self-hosted, x64]
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
|
|||||||
2
.github/workflows/production-build.yml
vendored
2
.github/workflows/production-build.yml
vendored
@@ -10,7 +10,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
amd64:
|
amd64:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [self-hosted, x64]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
|
|||||||
@@ -5,14 +5,12 @@ namespace App\Actions\CoolifyTask;
|
|||||||
use App\Enums\ActivityTypes;
|
use App\Enums\ActivityTypes;
|
||||||
use App\Enums\ProcessStatus;
|
use App\Enums\ProcessStatus;
|
||||||
use App\Jobs\ApplicationDeploymentJob;
|
use App\Jobs\ApplicationDeploymentJob;
|
||||||
|
use App\Models\Server;
|
||||||
use Illuminate\Process\ProcessResult;
|
use Illuminate\Process\ProcessResult;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Process;
|
use Illuminate\Support\Facades\Process;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
|
|
||||||
const TIMEOUT = 3600;
|
|
||||||
const IDLE_TIMEOUT = 3600;
|
|
||||||
|
|
||||||
class RunRemoteProcess
|
class RunRemoteProcess
|
||||||
{
|
{
|
||||||
public Activity $activity;
|
public Activity $activity;
|
||||||
@@ -76,8 +74,7 @@ class RunRemoteProcess
|
|||||||
$this->time_start = hrtime(true);
|
$this->time_start = hrtime(true);
|
||||||
|
|
||||||
$status = ProcessStatus::IN_PROGRESS;
|
$status = ProcessStatus::IN_PROGRESS;
|
||||||
|
$processResult = Process::forever()->run($this->getCommand(), $this->handleOutput(...));
|
||||||
$processResult = Process::timeout(TIMEOUT)->idleTimeout(IDLE_TIMEOUT)->run($this->getCommand(), $this->handleOutput(...));
|
|
||||||
|
|
||||||
if ($this->activity->properties->get('status') === ProcessStatus::ERROR->value) {
|
if ($this->activity->properties->get('status') === ProcessStatus::ERROR->value) {
|
||||||
$status = ProcessStatus::ERROR;
|
$status = ProcessStatus::ERROR;
|
||||||
@@ -98,7 +95,7 @@ class RunRemoteProcess
|
|||||||
]);
|
]);
|
||||||
$this->activity->save();
|
$this->activity->save();
|
||||||
if ($processResult->exitCode() != 0 && !$this->ignore_errors) {
|
if ($processResult->exitCode() != 0 && !$this->ignore_errors) {
|
||||||
throw new \RuntimeException($processResult->errorOutput());
|
throw new \RuntimeException($processResult->errorOutput(), $processResult->exitCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $processResult;
|
return $processResult;
|
||||||
@@ -106,13 +103,11 @@ class RunRemoteProcess
|
|||||||
|
|
||||||
protected function getCommand(): string
|
protected function getCommand(): string
|
||||||
{
|
{
|
||||||
$user = $this->activity->getExtraProperty('user');
|
$server_uuid = $this->activity->getExtraProperty('server_uuid');
|
||||||
$server_ip = $this->activity->getExtraProperty('server_ip');
|
|
||||||
$private_key_location = $this->activity->getExtraProperty('private_key_location');
|
|
||||||
$port = $this->activity->getExtraProperty('port');
|
|
||||||
$command = $this->activity->getExtraProperty('command');
|
$command = $this->activity->getExtraProperty('command');
|
||||||
|
$server = Server::whereUuid($server_uuid)->firstOrFail();
|
||||||
|
|
||||||
return generate_ssh_command($private_key_location, $server_ip, $user, $port, $command);
|
return generateSshCommand($server, $command);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleOutput(string $type, string $output)
|
protected function handleOutput(string $type, string $output)
|
||||||
|
|||||||
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Actions\Proxy;
|
namespace App\Actions\Proxy;
|
||||||
|
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class CheckConfigurationSync
|
class CheckConfiguration
|
||||||
{
|
{
|
||||||
public function __invoke(Server $server, bool $reset = false)
|
use AsAction;
|
||||||
|
public function handle(Server $server, bool $reset = false)
|
||||||
{
|
{
|
||||||
$proxy_path = get_proxy_path();
|
$proxy_path = get_proxy_path();
|
||||||
$proxy_configuration = instant_remote_process([
|
$proxy_configuration = instant_remote_process([
|
||||||
@@ -16,10 +18,7 @@ class CheckConfigurationSync
|
|||||||
|
|
||||||
if ($reset || is_null($proxy_configuration)) {
|
if ($reset || is_null($proxy_configuration)) {
|
||||||
$proxy_configuration = Str::of(generate_default_proxy_configuration($server))->trim()->value;
|
$proxy_configuration = Str::of(generate_default_proxy_configuration($server))->trim()->value;
|
||||||
resolve(SaveConfigurationSync::class)($server, $proxy_configuration);
|
|
||||||
return $proxy_configuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $proxy_configuration;
|
return $proxy_configuration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
27
app/Actions/Proxy/SaveConfiguration.php
Normal file
27
app/Actions/Proxy/SaveConfiguration.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Proxy;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class SaveConfiguration
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(Server $server)
|
||||||
|
{
|
||||||
|
$proxy_settings = CheckConfiguration::run($server, true);
|
||||||
|
$proxy_path = get_proxy_path();
|
||||||
|
$docker_compose_yml_base64 = base64_encode($proxy_settings);
|
||||||
|
|
||||||
|
$server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
||||||
|
$server->save();
|
||||||
|
|
||||||
|
return instant_remote_process([
|
||||||
|
"mkdir -p $proxy_path",
|
||||||
|
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
||||||
|
], $server);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Proxy;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class SaveConfigurationSync
|
|
||||||
{
|
|
||||||
public function __invoke(Server $server, string $configuration)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$proxy_path = get_proxy_path();
|
|
||||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
|
||||||
|
|
||||||
$server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
|
||||||
$server->save();
|
|
||||||
|
|
||||||
instant_remote_process([
|
|
||||||
"mkdir -p $proxy_path",
|
|
||||||
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
|
||||||
], $server);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
ray($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,14 +2,25 @@
|
|||||||
|
|
||||||
namespace App\Actions\Proxy;
|
namespace App\Actions\Proxy;
|
||||||
|
|
||||||
|
use App\Enums\ProxyStatus;
|
||||||
|
use App\Enums\ProxyTypes;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
|
|
||||||
class StartProxy
|
class StartProxy
|
||||||
{
|
{
|
||||||
public function __invoke(Server $server): Activity
|
public function __invoke(Server $server, bool $async = true): Activity|string
|
||||||
{
|
{
|
||||||
|
$proxyType = data_get($server,'proxy.type');
|
||||||
|
if ($proxyType === 'none') {
|
||||||
|
return 'OK';
|
||||||
|
}
|
||||||
|
if (is_null($proxyType)) {
|
||||||
|
$server->proxy->type = ProxyTypes::TRAEFIK_V2->value;
|
||||||
|
$server->proxy->status = ProxyStatus::EXITED->value;
|
||||||
|
$server->save();
|
||||||
|
}
|
||||||
$proxy_path = get_proxy_path();
|
$proxy_path = get_proxy_path();
|
||||||
$networks = collect($server->standaloneDockers)->map(function ($docker) {
|
$networks = collect($server->standaloneDockers)->map(function ($docker) {
|
||||||
return $docker['network'];
|
return $docker['network'];
|
||||||
@@ -21,13 +32,18 @@ class StartProxy
|
|||||||
return "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null 2>&1 || docker network create --attachable $network > /dev/null 2>&1";
|
return "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null 2>&1 || docker network create --attachable $network > /dev/null 2>&1";
|
||||||
});
|
});
|
||||||
|
|
||||||
$configuration = resolve(CheckConfigurationSync::class)($server);
|
$configuration = CheckConfiguration::run($server);
|
||||||
|
if (!$configuration) {
|
||||||
|
throw new \Exception("Configuration is not synced");
|
||||||
|
}
|
||||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
$docker_compose_yml_base64 = base64_encode($configuration);
|
||||||
$server->proxy->last_applied_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
$server->proxy->last_applied_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
||||||
$server->save();
|
$server->save();
|
||||||
|
$commands = [
|
||||||
$activity = remote_process([
|
"command -v lsof >/dev/null || echo '####### Installing lsof...'",
|
||||||
|
"command -v lsof >/dev/null || apt-get update",
|
||||||
|
"command -v lsof >/dev/null || apt install -y lsof",
|
||||||
|
"command -v lsof >/dev/null || command -v fuser >/dev/null || apt install -y psmisc",
|
||||||
"echo '####### Creating required Docker networks...'",
|
"echo '####### Creating required Docker networks...'",
|
||||||
...$create_networks_command,
|
...$create_networks_command,
|
||||||
"cd $proxy_path",
|
"cd $proxy_path",
|
||||||
@@ -35,17 +51,25 @@ class StartProxy
|
|||||||
"echo '####### Pulling docker image...'",
|
"echo '####### Pulling docker image...'",
|
||||||
'docker compose pull',
|
'docker compose pull',
|
||||||
"echo '####### Stopping existing coolify-proxy...'",
|
"echo '####### Stopping existing coolify-proxy...'",
|
||||||
'docker compose down -v --remove-orphans',
|
"docker compose down -v --remove-orphans > /dev/null 2>&1 || true",
|
||||||
"lsof -nt -i:80 | xargs -r kill -9",
|
"command -v fuser >/dev/null || command -v lsof >/dev/null || echo '####### Could not kill existing processes listening on port 80 & 443. Please stop the process holding these ports...'",
|
||||||
"lsof -nt -i:443 | xargs -r kill -9",
|
"command -v lsof >/dev/null && lsof -nt -i:80 | xargs -r kill -9 || true",
|
||||||
|
"command -v lsof >/dev/null && lsof -nt -i:443 | xargs -r kill -9 || true",
|
||||||
|
"command -v fuser >/dev/null && fuser -k 80/tcp || true",
|
||||||
|
"command -v fuser >/dev/null && fuser -k 443/tcp || true",
|
||||||
"systemctl disable nginx > /dev/null 2>&1 || true",
|
"systemctl disable nginx > /dev/null 2>&1 || true",
|
||||||
"systemctl disable apache2 > /dev/null 2>&1 || true",
|
"systemctl disable apache2 > /dev/null 2>&1 || true",
|
||||||
"systemctl disable apache > /dev/null 2>&1 || true",
|
"systemctl disable apache > /dev/null 2>&1 || true",
|
||||||
"echo '####### Starting coolify-proxy...'",
|
"echo '####### Starting coolify-proxy...'",
|
||||||
'docker compose up -d --remove-orphans',
|
'docker compose up -d --remove-orphans',
|
||||||
"echo '####### Proxy installed successfully...'"
|
"echo '####### Proxy installed successfully...'"
|
||||||
], $server);
|
];
|
||||||
|
if (!$async) {
|
||||||
return $activity;
|
instant_remote_process($commands, $server);
|
||||||
|
return 'OK';
|
||||||
|
} else {
|
||||||
|
$activity = remote_process($commands, $server);
|
||||||
|
return $activity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ namespace App\Actions\Server;
|
|||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
use App\Models\Team;
|
|
||||||
|
|
||||||
class InstallDocker
|
class InstallDocker
|
||||||
{
|
{
|
||||||
public function __invoke(Server $server, Team $team)
|
public function __invoke(Server $server, bool $instant = false)
|
||||||
{
|
{
|
||||||
$dockerVersion = '24.0';
|
$dockerVersion = '24.0';
|
||||||
$config = base64_encode('{
|
$config = base64_encode('{
|
||||||
@@ -19,15 +18,16 @@ class InstallDocker
|
|||||||
}
|
}
|
||||||
}');
|
}');
|
||||||
$found = StandaloneDocker::where('server_id', $server->id);
|
$found = StandaloneDocker::where('server_id', $server->id);
|
||||||
if ($found->count() == 0) {
|
if ($found->count() == 0 && $server->id) {
|
||||||
StandaloneDocker::create([
|
StandaloneDocker::create([
|
||||||
'name' => 'coolify',
|
'name' => 'coolify',
|
||||||
'network' => 'coolify',
|
'network' => 'coolify',
|
||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if (isDev()) {
|
|
||||||
return remote_process([
|
if (isDev() && $server->id === 0) {
|
||||||
|
$command = [
|
||||||
"echo '####### Installing Prerequisites...'",
|
"echo '####### Installing Prerequisites...'",
|
||||||
"sleep 1",
|
"sleep 1",
|
||||||
"echo '####### Installing/updating Docker Engine...'",
|
"echo '####### Installing/updating Docker Engine...'",
|
||||||
@@ -35,9 +35,9 @@ class InstallDocker
|
|||||||
"sleep 4",
|
"sleep 4",
|
||||||
"echo '####### Restarting Docker Engine...'",
|
"echo '####### Restarting Docker Engine...'",
|
||||||
"ls -l /tmp"
|
"ls -l /tmp"
|
||||||
], $server);
|
];
|
||||||
} else {
|
} else {
|
||||||
return remote_process([
|
$command = [
|
||||||
"echo '####### Installing Prerequisites...'",
|
"echo '####### Installing Prerequisites...'",
|
||||||
"command -v jq >/dev/null || apt-get update",
|
"command -v jq >/dev/null || apt-get update",
|
||||||
"command -v jq >/dev/null || apt install -y jq",
|
"command -v jq >/dev/null || apt install -y jq",
|
||||||
@@ -53,7 +53,11 @@ class InstallDocker
|
|||||||
"echo '####### Creating default Docker network (coolify)...'",
|
"echo '####### Creating default Docker network (coolify)...'",
|
||||||
"docker network create --attachable coolify >/dev/null 2>&1 || true",
|
"docker network create --attachable coolify >/dev/null 2>&1 || true",
|
||||||
"echo '####### Done!'"
|
"echo '####### Done!'"
|
||||||
], $server);
|
];
|
||||||
}
|
}
|
||||||
|
if ($instant) {
|
||||||
|
return instant_remote_process($command, $server);
|
||||||
|
}
|
||||||
|
return remote_process($command, $server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use Illuminate\Console\Command;
|
|||||||
use Illuminate\Mail\Message;
|
use Illuminate\Mail\Message;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Mail;
|
use Mail;
|
||||||
use Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
use function Laravel\Prompts\confirm;
|
use function Laravel\Prompts\confirm;
|
||||||
use function Laravel\Prompts\select;
|
use function Laravel\Prompts\select;
|
||||||
@@ -62,7 +62,7 @@ class Emails extends Command
|
|||||||
'application-status-changed' => 'Application - Status Changed',
|
'application-status-changed' => 'Application - Status Changed',
|
||||||
'backup-success' => 'Database - Backup Success',
|
'backup-success' => 'Database - Backup Success',
|
||||||
'backup-failed' => 'Database - Backup Failed',
|
'backup-failed' => 'Database - Backup Failed',
|
||||||
'invitation-link' => 'Invitation Link',
|
// 'invitation-link' => 'Invitation Link',
|
||||||
'waitlist-invitation-link' => 'Waitlist Invitation Link',
|
'waitlist-invitation-link' => 'Waitlist Invitation Link',
|
||||||
'waitlist-confirmation' => 'Waitlist Confirmation',
|
'waitlist-confirmation' => 'Waitlist Confirmation',
|
||||||
'realusers-before-trial' => 'REAL - Registered Users Before Trial without Subscription',
|
'realusers-before-trial' => 'REAL - Registered Users Before Trial without Subscription',
|
||||||
@@ -141,20 +141,20 @@ class Emails extends Command
|
|||||||
$this->mail = (new BackupSuccess($backup, $db))->toMail();
|
$this->mail = (new BackupSuccess($backup, $db))->toMail();
|
||||||
$this->sendEmail();
|
$this->sendEmail();
|
||||||
break;
|
break;
|
||||||
case 'invitation-link':
|
// case 'invitation-link':
|
||||||
$user = User::all()->first();
|
// $user = User::all()->first();
|
||||||
$invitation = TeamInvitation::whereEmail($user->email)->first();
|
// $invitation = TeamInvitation::whereEmail($user->email)->first();
|
||||||
if (!$invitation) {
|
// if (!$invitation) {
|
||||||
$invitation = TeamInvitation::create([
|
// $invitation = TeamInvitation::create([
|
||||||
'uuid' => Str::uuid(),
|
// 'uuid' => Str::uuid(),
|
||||||
'email' => $user->email,
|
// 'email' => $user->email,
|
||||||
'team_id' => 1,
|
// 'team_id' => 1,
|
||||||
'link' => 'http://example.com',
|
// 'link' => 'http://example.com',
|
||||||
]);
|
// ]);
|
||||||
}
|
// }
|
||||||
$this->mail = (new InvitationLink($user))->toMail();
|
// $this->mail = (new InvitationLink($user))->toMail();
|
||||||
$this->sendEmail();
|
// $this->sendEmail();
|
||||||
break;
|
// break;
|
||||||
case 'waitlist-invitation-link':
|
case 'waitlist-invitation-link':
|
||||||
$this->mail = new MailMessage();
|
$this->mail = new MailMessage();
|
||||||
$this->mail->view('emails.waitlist-invitation', [
|
$this->mail->view('emails.waitlist-invitation', [
|
||||||
|
|||||||
@@ -2,21 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
use App\Enums\ProxyTypes;
|
|
||||||
use App\Jobs\ApplicationContainerStatusJob;
|
|
||||||
use App\Jobs\CheckResaleLicenseJob;
|
use App\Jobs\CheckResaleLicenseJob;
|
||||||
use App\Jobs\CleanupInstanceStuffsJob;
|
use App\Jobs\CleanupInstanceStuffsJob;
|
||||||
use App\Jobs\DatabaseBackupJob;
|
use App\Jobs\DatabaseBackupJob;
|
||||||
use App\Jobs\DatabaseContainerStatusJob;
|
|
||||||
use App\Jobs\DockerCleanupJob;
|
use App\Jobs\DockerCleanupJob;
|
||||||
use App\Jobs\InstanceAutoUpdateJob;
|
use App\Jobs\InstanceAutoUpdateJob;
|
||||||
use App\Jobs\ProxyContainerStatusJob;
|
use App\Jobs\ContainerStatusJob;
|
||||||
use App\Jobs\ServerDetailsCheckJob;
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\ScheduledDatabaseBackup;
|
use App\Models\ScheduledDatabaseBackup;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandalonePostgresql;
|
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
@@ -25,43 +19,31 @@ class Kernel extends ConsoleKernel
|
|||||||
protected function schedule(Schedule $schedule): void
|
protected function schedule(Schedule $schedule): void
|
||||||
{
|
{
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$schedule->job(new ServerDetailsCheckJob(Server::find(0)))->everyTenMinutes()->onOneServer();
|
// $schedule->job(new ContainerStatusJob(Server::find(0)))->everyTenMinutes()->onOneServer();
|
||||||
// $schedule->command('horizon:snapshot')->everyMinute();
|
// $schedule->command('horizon:snapshot')->everyMinute();
|
||||||
// $schedule->job(new CleanupInstanceStuffsJob)->everyMinute();
|
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
||||||
// $schedule->job(new CheckResaleLicenseJob)->hourly();
|
// $schedule->job(new CheckResaleLicenseJob)->hourly();
|
||||||
// $schedule->job(new DockerCleanupJob)->everyOddHour();
|
// $schedule->job(new DockerCleanupJob)->everyOddHour();
|
||||||
// $this->instance_auto_update($schedule);
|
// $this->instance_auto_update($schedule);
|
||||||
// $this->check_scheduled_backups($schedule);
|
// $this->check_scheduled_backups($schedule);
|
||||||
// $this->check_resources($schedule);
|
$this->check_resources($schedule);
|
||||||
// $this->check_proxies($schedule);
|
|
||||||
} else {
|
} else {
|
||||||
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||||
$schedule->job(new CleanupInstanceStuffsJob)->everyTenMinutes()->onOneServer();
|
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
||||||
$schedule->job(new CheckResaleLicenseJob)->hourly()->onOneServer();
|
$schedule->job(new CheckResaleLicenseJob)->hourly()->onOneServer();
|
||||||
$schedule->job(new DockerCleanupJob)->everyTenMinutes()->onOneServer();
|
$schedule->job(new DockerCleanupJob)->everyTenMinutes()->onOneServer();
|
||||||
$this->instance_auto_update($schedule);
|
$this->instance_auto_update($schedule);
|
||||||
$this->check_scheduled_backups($schedule);
|
$this->check_scheduled_backups($schedule);
|
||||||
$this->check_resources($schedule);
|
$this->check_resources($schedule);
|
||||||
$this->check_proxies($schedule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private function check_proxies($schedule)
|
|
||||||
{
|
|
||||||
$servers = Server::all()->where('settings.is_usable', true)->where('settings.is_reachable', true)->whereNotNull('proxy.type')->where('proxy.type', '!=', ProxyTypes::NONE->value);
|
|
||||||
foreach ($servers as $server) {
|
|
||||||
$schedule->job(new ProxyContainerStatusJob($server))->everyMinute()->onOneServer();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private function check_resources($schedule)
|
private function check_resources($schedule)
|
||||||
{
|
{
|
||||||
$applications = Application::all();
|
$servers = Server::all()->where('settings.is_usable', true)->where('settings.is_reachable', true);
|
||||||
foreach ($applications as $application) {
|
ray($servers);
|
||||||
$schedule->job(new ApplicationContainerStatusJob($application))->everyMinute()->onOneServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
$postgresqls = StandalonePostgresql::all();
|
foreach ($servers as $server) {
|
||||||
foreach ($postgresqls as $postgresql) {
|
$schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer();
|
||||||
$schedule->job(new DatabaseContainerStatusJob($postgresql))->everyMinute()->onOneServer();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private function instance_auto_update($schedule)
|
private function instance_auto_update($schedule)
|
||||||
|
|||||||
@@ -12,11 +12,8 @@ use Spatie\LaravelData\Data;
|
|||||||
class CoolifyTaskArgs extends Data
|
class CoolifyTaskArgs extends Data
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $server_ip,
|
public string $server_uuid,
|
||||||
public string $private_key_location,
|
|
||||||
public string $command,
|
public string $command,
|
||||||
public int $port,
|
|
||||||
public string $user,
|
|
||||||
public string $type,
|
public string $type,
|
||||||
public ?string $type_uuid = null,
|
public ?string $type_uuid = null,
|
||||||
public ?Model $model = null,
|
public ?Model $model = null,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Exceptions;
|
namespace App\Exceptions;
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
|
use App\Models\User;
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
use Sentry\Laravel\Integration;
|
use Sentry\Laravel\Integration;
|
||||||
use Sentry\State\Scope;
|
use Sentry\State\Scope;
|
||||||
@@ -45,16 +46,19 @@ class Handler extends ExceptionHandler
|
|||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
$this->reportable(function (Throwable $e) {
|
$this->reportable(function (Throwable $e) {
|
||||||
|
if (isDev()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$this->settings = InstanceSettings::get();
|
$this->settings = InstanceSettings::get();
|
||||||
if ($this->settings->do_not_track || isDev()) {
|
if ($this->settings->do_not_track) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('sentry')->configureScope(
|
app('sentry')->configureScope(
|
||||||
function (Scope $scope) {
|
function (Scope $scope) {
|
||||||
$scope->setUser(
|
$scope->setUser(
|
||||||
[
|
[
|
||||||
'id' => config('sentry.server_name'),
|
'email' => auth()->user()->email,
|
||||||
'email' => auth()->user()->email
|
'instanceAdmin' => User::find(0)->email
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,21 +3,17 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\Project;
|
|
||||||
use App\Models\S3Storage;
|
use App\Models\S3Storage;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use App\Models\TeamInvitation;
|
use App\Models\TeamInvitation;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Auth;
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
use Illuminate\Routing\Controller as BaseController;
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Str;
|
||||||
use Throwable;
|
|
||||||
use Str;
|
|
||||||
|
|
||||||
|
|
||||||
class Controller extends BaseController
|
class Controller extends BaseController
|
||||||
{
|
{
|
||||||
@@ -35,8 +31,15 @@ class Controller extends BaseController
|
|||||||
return redirect()->route('login');
|
return redirect()->route('login');
|
||||||
}
|
}
|
||||||
if (Hash::check($password, $user->password)) {
|
if (Hash::check($password, $user->password)) {
|
||||||
|
$invitation = TeamInvitation::whereEmail($email);
|
||||||
|
if ($invitation->exists()) {
|
||||||
|
$team = $invitation->first()->team;
|
||||||
|
$user->teams()->attach($team->id, ['role' => $invitation->first()->role]);
|
||||||
|
$invitation->delete();
|
||||||
|
} else {
|
||||||
|
$team = $user->teams()->first();
|
||||||
|
}
|
||||||
Auth::login($user);
|
Auth::login($user);
|
||||||
$team = $user->teams()->first();
|
|
||||||
session(['currentTeam' => $team]);
|
session(['currentTeam' => $team]);
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
@@ -137,24 +140,20 @@ class Controller extends BaseController
|
|||||||
try {
|
try {
|
||||||
$invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();
|
$invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();
|
||||||
$user = User::whereEmail($invitation->email)->firstOrFail();
|
$user = User::whereEmail($invitation->email)->firstOrFail();
|
||||||
if (is_null(auth()->user())) {
|
|
||||||
return redirect()->route('login');
|
|
||||||
}
|
|
||||||
if (auth()->user()->id !== $user->id) {
|
if (auth()->user()->id !== $user->id) {
|
||||||
abort(401);
|
abort(401);
|
||||||
}
|
}
|
||||||
|
$invitationValid = $invitation->isValid();
|
||||||
$createdAt = $invitation->created_at;
|
if ($invitationValid) {
|
||||||
$diff = $createdAt->diffInMinutes(now());
|
|
||||||
if ($diff <= config('constants.invitation.link.expiration')) {
|
|
||||||
$user->teams()->attach($invitation->team->id, ['role' => $invitation->role]);
|
$user->teams()->attach($invitation->team->id, ['role' => $invitation->role]);
|
||||||
|
refreshSession($invitation->team);
|
||||||
$invitation->delete();
|
$invitation->delete();
|
||||||
return redirect()->route('team.index');
|
return redirect()->route('team.index');
|
||||||
} else {
|
} else {
|
||||||
$invitation->delete();
|
|
||||||
abort(401);
|
abort(401);
|
||||||
}
|
}
|
||||||
} catch (Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
ray($e->getMessage());
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +171,7 @@ class Controller extends BaseController
|
|||||||
}
|
}
|
||||||
$invitation->delete();
|
$invitation->delete();
|
||||||
return redirect()->route('team.index');
|
return redirect()->route('team.index');
|
||||||
} catch (Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ use App\Models\Server;
|
|||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
public string $currentState = 'welcome';
|
public string $currentState = 'welcome';
|
||||||
|
|
||||||
|
public ?string $selectedServerType = null;
|
||||||
public ?Collection $privateKeys = null;
|
public ?Collection $privateKeys = null;
|
||||||
public ?int $selectedExistingPrivateKey = null;
|
public ?int $selectedExistingPrivateKey = null;
|
||||||
public ?string $privateKeyType = null;
|
public ?string $privateKeyType = null;
|
||||||
@@ -36,6 +38,7 @@ class Index extends Component
|
|||||||
public ?int $selectedExistingProject = null;
|
public ?int $selectedExistingProject = null;
|
||||||
public ?Project $createdProject = null;
|
public ?Project $createdProject = null;
|
||||||
|
|
||||||
|
public bool $dockerInstallationStarted = false;
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->privateKeyName = generate_random_name();
|
$this->privateKeyName = generate_random_name();
|
||||||
@@ -53,20 +56,24 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->remoteServerHost = 'coolify-testing-host';
|
$this->remoteServerHost = 'coolify-testing-host';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function welcome() {
|
public function explanation()
|
||||||
|
{
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
return $this->setServerType('remote');
|
return $this->setServerType('remote');
|
||||||
}
|
}
|
||||||
$this->currentState = 'select-server-type';
|
$this->currentState = 'select-server-type';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function restartBoarding()
|
public function restartBoarding()
|
||||||
{
|
{
|
||||||
if ($this->createdServer) {
|
// if ($this->selectedServerType !== 'localhost') {
|
||||||
$this->createdServer->delete();
|
// if ($this->createdServer) {
|
||||||
}
|
// $this->createdServer->delete();
|
||||||
if ($this->createdPrivateKey) {
|
// }
|
||||||
$this->createdPrivateKey->delete();
|
// if ($this->createdPrivateKey) {
|
||||||
}
|
// $this->createdPrivateKey->delete();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
return redirect()->route('boarding');
|
return redirect()->route('boarding');
|
||||||
}
|
}
|
||||||
public function skipBoarding()
|
public function skipBoarding()
|
||||||
@@ -81,13 +88,14 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
|
|
||||||
public function setServerType(string $type)
|
public function setServerType(string $type)
|
||||||
{
|
{
|
||||||
if ($type === 'localhost') {
|
$this->selectedServerType = $type;
|
||||||
|
if ($this->selectedServerType === 'localhost') {
|
||||||
$this->createdServer = Server::find(0);
|
$this->createdServer = Server::find(0);
|
||||||
if (!$this->createdServer) {
|
if (!$this->createdServer) {
|
||||||
return $this->emit('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
|
return $this->emit('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
|
||||||
}
|
}
|
||||||
return $this->validateServer();
|
return $this->validateServer('localhost');
|
||||||
} elseif ($type === 'remote') {
|
} elseif ($this->selectedServerType === 'remote') {
|
||||||
$this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
|
$this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
|
||||||
if ($this->privateKeys->count() > 0) {
|
if ($this->privateKeys->count() > 0) {
|
||||||
$this->selectedExistingPrivateKey = $this->privateKeys->first()->id;
|
$this->selectedExistingPrivateKey = $this->privateKeys->first()->id;
|
||||||
@@ -111,10 +119,9 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
}
|
}
|
||||||
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
|
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
|
||||||
$this->validateServer();
|
$this->validateServer();
|
||||||
$this->getProxyType();
|
|
||||||
$this->getProjects();
|
|
||||||
}
|
}
|
||||||
public function getProxyType() {
|
public function getProxyType()
|
||||||
|
{
|
||||||
$proxyTypeSet = $this->createdServer->proxy->type;
|
$proxyTypeSet = $this->createdServer->proxy->type;
|
||||||
if (!$proxyTypeSet) {
|
if (!$proxyTypeSet) {
|
||||||
$this->currentState = 'select-proxy';
|
$this->currentState = 'select-proxy';
|
||||||
@@ -124,6 +131,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
}
|
}
|
||||||
public function selectExistingPrivateKey()
|
public function selectExistingPrivateKey()
|
||||||
{
|
{
|
||||||
|
$this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey);
|
||||||
$this->currentState = 'create-server';
|
$this->currentState = 'create-server';
|
||||||
}
|
}
|
||||||
public function createNewServer()
|
public function createNewServer()
|
||||||
@@ -146,6 +154,13 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
'privateKeyName' => 'required',
|
'privateKeyName' => 'required',
|
||||||
'privateKey' => 'required',
|
'privateKey' => 'required',
|
||||||
]);
|
]);
|
||||||
|
$this->createdPrivateKey = PrivateKey::create([
|
||||||
|
'name' => $this->privateKeyName,
|
||||||
|
'description' => $this->privateKeyDescription,
|
||||||
|
'private_key' => $this->privateKey,
|
||||||
|
'team_id' => currentTeam()->id
|
||||||
|
]);
|
||||||
|
$this->createdPrivateKey->save();
|
||||||
$this->currentState = 'create-server';
|
$this->currentState = 'create-server';
|
||||||
}
|
}
|
||||||
public function saveServer()
|
public function saveServer()
|
||||||
@@ -153,16 +168,14 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->validate([
|
$this->validate([
|
||||||
'remoteServerName' => 'required',
|
'remoteServerName' => 'required',
|
||||||
'remoteServerHost' => 'required',
|
'remoteServerHost' => 'required',
|
||||||
'remoteServerPort' => 'required',
|
'remoteServerPort' => 'required|integer',
|
||||||
'remoteServerUser' => 'required',
|
'remoteServerUser' => 'required',
|
||||||
]);
|
]);
|
||||||
$this->privateKey = formatPrivateKey($this->privateKey);
|
$this->privateKey = formatPrivateKey($this->privateKey);
|
||||||
$this->createdPrivateKey = PrivateKey::create([
|
$foundServer = Server::whereIp($this->remoteServerHost)->first();
|
||||||
'name' => $this->privateKeyName,
|
if ($foundServer) {
|
||||||
'description' => $this->privateKeyDescription,
|
return $this->emit('error', 'IP address is already in use by another team.');
|
||||||
'private_key' => $this->privateKey,
|
}
|
||||||
'team_id' => currentTeam()->id
|
|
||||||
]);
|
|
||||||
$this->createdServer = Server::create([
|
$this->createdServer = Server::create([
|
||||||
'name' => $this->remoteServerName,
|
'name' => $this->remoteServerName,
|
||||||
'ip' => $this->remoteServerHost,
|
'ip' => $this->remoteServerHost,
|
||||||
@@ -170,38 +183,46 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
'user' => $this->remoteServerUser,
|
'user' => $this->remoteServerUser,
|
||||||
'description' => $this->remoteServerDescription,
|
'description' => $this->remoteServerDescription,
|
||||||
'private_key_id' => $this->createdPrivateKey->id,
|
'private_key_id' => $this->createdPrivateKey->id,
|
||||||
'team_id' => currentTeam()->id
|
'team_id' => currentTeam()->id,
|
||||||
]);
|
]);
|
||||||
|
$this->createdServer->save();
|
||||||
$this->validateServer();
|
$this->validateServer();
|
||||||
}
|
}
|
||||||
public function validateServer() {
|
public function validateServer(?string $type = null)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->createdServer);
|
$customErrorMessage = "Server is not reachable:";
|
||||||
if (!$uptime) {
|
config()->set('coolify.mux_enabled', false);
|
||||||
throw new \Exception('Server is not reachable.');
|
|
||||||
} else {
|
|
||||||
$this->createdServer->settings->update([
|
|
||||||
'is_reachable' => true,
|
|
||||||
]);
|
|
||||||
$this->emit('success', 'Server is reachable.');
|
|
||||||
}
|
|
||||||
ray($dockerVersion, $uptime);
|
|
||||||
if (!$dockerVersion) {
|
|
||||||
$this->emit('error', 'Docker is not installed on the server.');
|
|
||||||
$this->currentState = 'install-docker';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->getProxyType();
|
|
||||||
|
|
||||||
|
instant_remote_process(['uptime'], $this->createdServer, true);
|
||||||
|
|
||||||
|
$this->createdServer->settings->update([
|
||||||
|
'is_reachable' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
|
||||||
|
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
|
||||||
|
if (is_null($dockerVersion)) {
|
||||||
|
$this->currentState = 'install-docker';
|
||||||
|
throw new \Exception('Docker version is not supported or not installed.');
|
||||||
|
}
|
||||||
|
$this->dockerInstalledOrSkipped();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
return handleError(error: $e, customErrorMessage: $customErrorMessage, livewire: $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function installDocker()
|
public function installDocker()
|
||||||
{
|
{
|
||||||
$activity = resolve(InstallDocker::class)($this->createdServer, currentTeam());
|
$this->dockerInstallationStarted = true;
|
||||||
|
$activity = resolve(InstallDocker::class)($this->createdServer);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
$this->currentState = 'select-proxy';
|
}
|
||||||
|
public function dockerInstalledOrSkipped()
|
||||||
|
{
|
||||||
|
$this->createdServer->settings->update([
|
||||||
|
'is_usable' => true,
|
||||||
|
]);
|
||||||
|
$this->getProxyType();
|
||||||
}
|
}
|
||||||
public function selectProxy(string|null $proxyType = null)
|
public function selectProxy(string|null $proxyType = null)
|
||||||
{
|
{
|
||||||
@@ -214,14 +235,16 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->getProjects();
|
$this->getProjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProjects() {
|
public function getProjects()
|
||||||
|
{
|
||||||
$this->projects = Project::ownedByCurrentTeam(['name'])->get();
|
$this->projects = Project::ownedByCurrentTeam(['name'])->get();
|
||||||
if ($this->projects->count() > 0) {
|
if ($this->projects->count() > 0) {
|
||||||
$this->selectedExistingProject = $this->projects->first()->id;
|
$this->selectedExistingProject = $this->projects->first()->id;
|
||||||
}
|
}
|
||||||
$this->currentState = 'create-project';
|
$this->currentState = 'create-project';
|
||||||
}
|
}
|
||||||
public function selectExistingProject() {
|
public function selectExistingProject()
|
||||||
|
{
|
||||||
$this->createdProject = Project::find($this->selectedExistingProject);
|
$this->createdProject = Project::find($this->selectedExistingProject);
|
||||||
$this->currentState = 'create-resource';
|
$this->currentState = 'create-resource';
|
||||||
}
|
}
|
||||||
@@ -241,7 +264,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
[
|
[
|
||||||
'project_uuid' => $this->createdProject->uuid,
|
'project_uuid' => $this->createdProject->uuid,
|
||||||
'environment_name' => 'production',
|
'environment_name' => 'production',
|
||||||
'server'=> $this->createdServer->id,
|
'server' => $this->createdServer->id,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class Form extends Component
|
|||||||
$this->destination->delete();
|
$this->destination->delete();
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class StandaloneDocker extends Component
|
|||||||
$this->createNetworkAndAttachToProxy();
|
$this->createNetworkAndAttachToProxy();
|
||||||
return redirect()->route('destination.show', $docker->uuid);
|
return redirect()->route('destination.show', $docker->uuid);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class ForcePasswordReset extends Component
|
|||||||
}
|
}
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Help extends Component
|
|||||||
];
|
];
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->path = Route::current()->uri();
|
$this->path = Route::current()?->uri() ?? null;
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->description = "I'm having trouble with {$this->path}";
|
$this->description = "I'm having trouble with {$this->path}";
|
||||||
$this->subject = "Help with {$this->path}";
|
$this->subject = "Help with {$this->path}";
|
||||||
@@ -41,10 +41,10 @@ class Help extends Component
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
$mail->subject("[HELP - {$subscriptionType}]: {$this->subject}");
|
$mail->subject("[HELP - {$subscriptionType}]: {$this->subject}");
|
||||||
send_user_an_email($mail, 'hi@coollabs.io', auth()->user()?->email);
|
send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
|
||||||
$this->emit('success', 'Your message has been sent successfully. We will get in touch with you as soon as possible.');
|
$this->emit('success', 'Your message has been sent successfully. We will get in touch with you as soon as possible.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function render()
|
public function render()
|
||||||
|
|||||||
@@ -46,9 +46,7 @@ class DiscordSettings extends Component
|
|||||||
public function saveModel()
|
public function saveModel()
|
||||||
{
|
{
|
||||||
$this->team->save();
|
$this->team->save();
|
||||||
if (is_a($this->team, Team::class)) {
|
refreshSession();
|
||||||
refreshSession();
|
|
||||||
}
|
|
||||||
$this->emit('success', 'Settings saved.');
|
$this->emit('success', 'Settings saved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,10 @@ class EmailSettings extends Component
|
|||||||
'team.smtp_from_name' => 'required',
|
'team.smtp_from_name' => 'required',
|
||||||
]);
|
]);
|
||||||
$this->team->save();
|
$this->team->save();
|
||||||
|
refreshSession();
|
||||||
$this->emit('success', 'Settings saved successfully.');
|
$this->emit('success', 'Settings saved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function sendTestNotification()
|
public function sendTestNotification()
|
||||||
@@ -81,9 +82,10 @@ class EmailSettings extends Component
|
|||||||
$this->team->smtp_enabled = false;
|
$this->team->smtp_enabled = false;
|
||||||
$this->team->resend_enabled = false;
|
$this->team->resend_enabled = false;
|
||||||
$this->team->save();
|
$this->team->save();
|
||||||
|
refreshSession();
|
||||||
$this->emit('success', 'Settings saved successfully.');
|
$this->emit('success', 'Settings saved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +96,7 @@ class EmailSettings extends Component
|
|||||||
$this->submitResend();
|
$this->submitResend();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->team->smtp_enabled = false;
|
$this->team->smtp_enabled = false;
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
@@ -104,15 +106,13 @@ class EmailSettings extends Component
|
|||||||
$this->submit();
|
$this->submit();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->team->smtp_enabled = false;
|
$this->team->smtp_enabled = false;
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function saveModel()
|
public function saveModel()
|
||||||
{
|
{
|
||||||
$this->team->save();
|
$this->team->save();
|
||||||
if (is_a($this->team, Team::class)) {
|
refreshSession();
|
||||||
refreshSession();
|
|
||||||
}
|
|
||||||
$this->emit('success', 'Settings saved.');
|
$this->emit('success', 'Settings saved.');
|
||||||
}
|
}
|
||||||
public function submit()
|
public function submit()
|
||||||
@@ -130,10 +130,11 @@ class EmailSettings extends Component
|
|||||||
'team.smtp_timeout' => 'nullable',
|
'team.smtp_timeout' => 'nullable',
|
||||||
]);
|
]);
|
||||||
$this->team->save();
|
$this->team->save();
|
||||||
|
refreshSession();
|
||||||
$this->emit('success', 'Settings saved successfully.');
|
$this->emit('success', 'Settings saved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->team->smtp_enabled = false;
|
$this->team->smtp_enabled = false;
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function submitResend()
|
public function submitResend()
|
||||||
@@ -141,6 +142,8 @@ class EmailSettings extends Component
|
|||||||
try {
|
try {
|
||||||
$this->resetErrorBag();
|
$this->resetErrorBag();
|
||||||
$this->validate([
|
$this->validate([
|
||||||
|
'team.smtp_from_address' => 'required|email',
|
||||||
|
'team.smtp_from_name' => 'required',
|
||||||
'team.resend_api_key' => 'required'
|
'team.resend_api_key' => 'required'
|
||||||
]);
|
]);
|
||||||
$this->team->save();
|
$this->team->save();
|
||||||
@@ -148,7 +151,7 @@ class EmailSettings extends Component
|
|||||||
$this->emit('success', 'Settings saved successfully.');
|
$this->emit('success', 'Settings saved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->team->resend_enabled = false;
|
$this->team->resend_enabled = false;
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function copyFromInstanceSettings()
|
public function copyFromInstanceSettings()
|
||||||
|
|||||||
@@ -52,9 +52,7 @@ class TelegramSettings extends Component
|
|||||||
public function saveModel()
|
public function saveModel()
|
||||||
{
|
{
|
||||||
$this->team->save();
|
$this->team->save();
|
||||||
if (is_a($this->team, Team::class)) {
|
refreshSession();
|
||||||
refreshSession();
|
|
||||||
}
|
|
||||||
$this->emit('success', 'Settings saved.');
|
$this->emit('success', 'Settings saved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class Change extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->public_key = $this->private_key->publicKey();
|
$this->public_key = $this->private_key->publicKey();
|
||||||
}catch(\Exception $e) {
|
}catch(\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function delete()
|
public function delete()
|
||||||
@@ -39,7 +39,7 @@ class Change extends Component
|
|||||||
}
|
}
|
||||||
$this->emit('error', 'This private key is in use and cannot be deleted. Please delete all servers, applications, and GitHub/GitLab apps that use this private key before deleting it.');
|
$this->emit('error', 'This private key is in use and cannot be deleted. Please delete all servers, applications, and GitHub/GitLab apps that use this private key before deleting it.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ class Change extends Component
|
|||||||
$this->private_key->save();
|
$this->private_key->save();
|
||||||
refresh_server_connection($this->private_key);
|
refresh_server_connection($this->private_key);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,20 @@
|
|||||||
namespace App\Http\Livewire\PrivateKey;
|
namespace App\Http\Livewire\PrivateKey;
|
||||||
|
|
||||||
use App\Models\PrivateKey;
|
use App\Models\PrivateKey;
|
||||||
|
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use phpseclib3\Crypt\PublicKeyLoader;
|
||||||
|
|
||||||
class Create extends Component
|
class Create extends Component
|
||||||
{
|
{
|
||||||
public string|null $from = null;
|
use WithRateLimiting;
|
||||||
public string $name;
|
public string $name;
|
||||||
public string|null $description = null;
|
|
||||||
public string $value;
|
public string $value;
|
||||||
|
|
||||||
|
public ?string $from = null;
|
||||||
|
public ?string $description = null;
|
||||||
|
public ?string $publicKey = null;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'name' => 'required|string',
|
'name' => 'required|string',
|
||||||
'value' => 'required|string',
|
'value' => 'required|string',
|
||||||
@@ -20,6 +26,32 @@ class Create extends Component
|
|||||||
'value' => 'private Key',
|
'value' => 'private Key',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function generateNewKey()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->rateLimit(10);
|
||||||
|
$this->name = generate_random_name();
|
||||||
|
$this->description = 'Created by Coolify';
|
||||||
|
['private' => $this->value, 'public' => $this->publicKey] = generateSSHKey();
|
||||||
|
} catch(\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function updated($updateProperty)
|
||||||
|
{
|
||||||
|
if ($updateProperty === 'value') {
|
||||||
|
try {
|
||||||
|
$this->publicKey = PublicKeyLoader::load($this->$updateProperty)->getPublicKey()->toString('OpenSSH',['comment' => '']);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
if ($this->$updateProperty === "") {
|
||||||
|
$this->publicKey = "";
|
||||||
|
} else {
|
||||||
|
$this->publicKey = "Invalid private key";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->validateOnly($updateProperty);
|
||||||
|
}
|
||||||
public function createPrivateKey()
|
public function createPrivateKey()
|
||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
@@ -39,7 +71,7 @@ class Create extends Component
|
|||||||
}
|
}
|
||||||
return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class Form extends Component
|
|||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class AddEmpty extends Component
|
|||||||
]);
|
]);
|
||||||
return redirect()->route('project.show', $project->uuid);
|
return redirect()->route('project.show', $project->uuid);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->name = '';
|
$this->name = '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class AddEnvironment extends Component
|
|||||||
'environment_name' => $environment->name,
|
'environment_name' => $environment->name,
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
general_error_handler($e, $this);
|
handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->name = '';
|
$this->name = '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class DeploymentNavbar extends Component
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ class General extends Component
|
|||||||
$this->application->save();
|
$this->application->save();
|
||||||
$this->emit('success', 'Application settings updated!');
|
$this->emit('success', 'Application settings updated!');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
namespace App\Http\Livewire\Project\Application;
|
||||||
|
|
||||||
use App\Jobs\ApplicationContainerStatusJob;
|
use App\Jobs\ContainerStatusJob;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Notifications\Application\StatusChanged;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
@@ -22,10 +21,11 @@ class Heading extends Component
|
|||||||
|
|
||||||
public function check_status()
|
public function check_status()
|
||||||
{
|
{
|
||||||
dispatch_sync(new ApplicationContainerStatusJob(
|
dispatch_sync(new ContainerStatusJob($this->application->destination->server));
|
||||||
application: $this->application,
|
|
||||||
));
|
|
||||||
$this->application->refresh();
|
$this->application->refresh();
|
||||||
|
$this->application->previews->each(function ($preview) {
|
||||||
|
$preview->refresh();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function force_deploy_without_cache()
|
public function force_deploy_without_cache()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
namespace App\Http\Livewire\Project\Application;
|
||||||
|
|
||||||
use App\Jobs\ApplicationContainerStatusJob;
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -23,14 +22,6 @@ class Previews extends Component
|
|||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadStatus($pull_request_id)
|
|
||||||
{
|
|
||||||
dispatch(new ApplicationContainerStatusJob(
|
|
||||||
application: $this->application,
|
|
||||||
pullRequestId: $pull_request_id
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function load_prs()
|
public function load_prs()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -39,7 +30,7 @@ class Previews extends Component
|
|||||||
$this->pull_requests = $data->sortBy('number')->values();
|
$this->pull_requests = $data->sortBy('number')->values();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->rate_limit_remaining = 0;
|
$this->rate_limit_remaining = 0;
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +59,7 @@ class Previews extends Component
|
|||||||
'environment_name' => $this->parameters['environment_name'],
|
'environment_name' => $this->parameters['environment_name'],
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +79,7 @@ class Previews extends Component
|
|||||||
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete();
|
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete();
|
||||||
$this->application->refresh();
|
$this->application->refresh();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class Rollback extends Component
|
|||||||
];
|
];
|
||||||
})->toArray();
|
})->toArray();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class CreateScheduledBackup extends Component
|
|||||||
]);
|
]);
|
||||||
$this->emit('refreshScheduledBackups');
|
$this->emit('refreshScheduledBackups');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
general_error_handler($e, $this);
|
handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->frequency = '';
|
$this->frequency = '';
|
||||||
$this->save_s3 = true;
|
$this->save_s3 = true;
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
namespace App\Http\Livewire\Project\Database;
|
namespace App\Http\Livewire\Project\Database;
|
||||||
|
|
||||||
use App\Actions\Database\StartPostgresql;
|
use App\Actions\Database\StartPostgresql;
|
||||||
use App\Jobs\DatabaseContainerStatusJob;
|
use App\Jobs\ContainerStatusJob;
|
||||||
use App\Notifications\Application\StatusChanged;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Heading extends Component
|
class Heading extends Component
|
||||||
@@ -25,9 +24,7 @@ class Heading extends Component
|
|||||||
|
|
||||||
public function check_status()
|
public function check_status()
|
||||||
{
|
{
|
||||||
dispatch_sync(new DatabaseContainerStatusJob(
|
dispatch_sync(new ContainerStatusJob($this->database->destination->server));
|
||||||
database: $this->database,
|
|
||||||
));
|
|
||||||
$this->database->refresh();
|
$this->database->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +35,7 @@ class Heading extends Component
|
|||||||
|
|
||||||
public function stop()
|
public function stop()
|
||||||
{
|
{
|
||||||
remote_process(
|
instant_remote_process(
|
||||||
["docker rm -f {$this->database->uuid}"],
|
["docker rm -f {$this->database->uuid}"],
|
||||||
$this->database->destination->server
|
$this->database->destination->server
|
||||||
);
|
);
|
||||||
@@ -48,7 +45,7 @@ class Heading extends Component
|
|||||||
}
|
}
|
||||||
$this->database->status = 'stopped';
|
$this->database->status = 'stopped';
|
||||||
$this->database->save();
|
$this->database->save();
|
||||||
$this->emit('refresh');
|
$this->check_status();
|
||||||
// $this->database->environment->project->team->notify(new StatusChanged($this->database));
|
// $this->database->environment->project->team->notify(new StatusChanged($this->database));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class InitScript extends Component
|
|||||||
$this->script['filename'] = $this->filename;
|
$this->script['filename'] = $this->filename;
|
||||||
$this->emitUp('save_init_script', $this->script);
|
$this->emitUp('save_init_script', $this->script);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Http\Livewire\Project\Database\Postgresql;
|
|||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
use function Aws\filter;
|
use function Aws\filter;
|
||||||
|
|
||||||
class General extends Component
|
class General extends Component
|
||||||
@@ -73,9 +74,9 @@ class General extends Component
|
|||||||
}
|
}
|
||||||
$this->getDbUrl();
|
$this->getDbUrl();
|
||||||
$this->database->save();
|
$this->database->save();
|
||||||
} catch(Exception $e) {
|
} catch(\Throwable $e) {
|
||||||
$this->database->is_public = !$this->database->is_public;
|
$this->database->is_public = !$this->database->is_public;
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -140,7 +141,7 @@ class General extends Component
|
|||||||
$this->database->save();
|
$this->database->save();
|
||||||
$this->emit('success', 'Database updated successfully.');
|
$this->emit('success', 'Database updated successfully.');
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class Edit extends Component
|
|||||||
$this->project->save();
|
$this->project->save();
|
||||||
$this->emit('saved');
|
$this->emit('saved');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ class GithubPrivateRepository extends Component
|
|||||||
'project_uuid' => $project->uuid,
|
'project_uuid' => $project->uuid,
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class GithubPrivateRepositoryDeployKey extends Component
|
|||||||
'application_uuid' => $application->uuid,
|
'application_uuid' => $application->uuid,
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,14 +76,14 @@ class PublicGitRepository extends Component
|
|||||||
$this->get_branch();
|
$this->get_branch();
|
||||||
$this->selected_branch = $this->git_branch;
|
$this->selected_branch = $this->git_branch;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
if (!$this->branch_found && $this->git_branch == 'main') {
|
if (!$this->branch_found && $this->git_branch == 'main') {
|
||||||
try {
|
try {
|
||||||
$this->git_branch = 'master';
|
$this->git_branch = 'master';
|
||||||
$this->get_branch();
|
$this->get_branch();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ class PublicGitRepository extends Component
|
|||||||
'application_uuid' => $application->uuid,
|
'application_uuid' => $application->uuid,
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Select extends Component
|
|||||||
// instantCommand("psql {$this->existingPostgresqlUrl} -c 'SELECT 1'");
|
// instantCommand("psql {$this->existingPostgresqlUrl} -c 'SELECT 1'");
|
||||||
// $this->emit('success', 'Successfully connected to the database.');
|
// $this->emit('success', 'Successfully connected to the database.');
|
||||||
// } catch (\Throwable $e) {
|
// } catch (\Throwable $e) {
|
||||||
// return general_error_handler($e, $this);
|
// return handleError($e, $this);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
public function setType(string $type)
|
public function setType(string $type)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
|
|||||||
use App\Models\EnvironmentVariable;
|
use App\Models\EnvironmentVariable;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
use Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class All extends Component
|
class All extends Component
|
||||||
{
|
{
|
||||||
@@ -114,7 +114,7 @@ class All extends Component
|
|||||||
$this->refreshEnvs();
|
$this->refreshEnvs();
|
||||||
$this->emit('success', 'Environment variable added successfully.');
|
$this->emit('success', 'Environment variable added successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class ResourceLimits extends Component
|
|||||||
$this->resource->save();
|
$this->resource->save();
|
||||||
$this->emit('success', 'Resource limits updated successfully.');
|
$this->emit('success', 'Resource limits updated successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class All extends Component
|
|||||||
$this->emit('success', 'Storage added successfully');
|
$this->emit('success', 'Storage added successfully');
|
||||||
$this->emit('clearAddStorage');
|
$this->emit('clearAddStorage');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class RunCommand extends Component
|
|||||||
$activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true);
|
$activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class Form extends Component
|
|||||||
public $dockerVersion;
|
public $dockerVersion;
|
||||||
public string|null $wildcard_domain = null;
|
public string|null $wildcard_domain = null;
|
||||||
public int $cleanup_after_percentage;
|
public int $cleanup_after_percentage;
|
||||||
|
public bool $dockerInstallationStarted = false;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'server.name' => 'required|min:6',
|
'server.name' => 'required|min:6',
|
||||||
@@ -44,19 +45,23 @@ class Form extends Component
|
|||||||
|
|
||||||
public function installDocker()
|
public function installDocker()
|
||||||
{
|
{
|
||||||
$activity = resolve(InstallDocker::class)($this->server, currentTeam());
|
$this->dockerInstallationStarted = true;
|
||||||
|
$activity = resolve(InstallDocker::class)($this->server);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateServer()
|
public function validateServer()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
$this->uptime = $uptime;
|
$this->uptime = $uptime;
|
||||||
$this->emit('success', 'Server is reachable!');
|
$this->emit('success', 'Server is reachable.');
|
||||||
} else {
|
} else {
|
||||||
$this->emit('error', 'Server is not rachable');
|
ray($this->uptime);
|
||||||
|
|
||||||
|
$this->emit('error', 'Server is not reachable.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($dockerVersion) {
|
if ($dockerVersion) {
|
||||||
@@ -64,10 +69,10 @@ class Form extends Component
|
|||||||
$this->emit('proxyStatusUpdated');
|
$this->emit('proxyStatusUpdated');
|
||||||
$this->emit('success', 'Docker Engine 23+ is installed!');
|
$this->emit('success', 'Docker Engine 23+ is installed!');
|
||||||
} else {
|
} else {
|
||||||
$this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.');
|
$this->emit('error', 'No Docker Engine or older than 23 version installed.');
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, that: $this);
|
return handleError($e, $this, customErrorMessage: "Server is not reachable: ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,23 +87,19 @@ class Form extends Component
|
|||||||
$this->server->delete();
|
$this->server->delete();
|
||||||
return redirect()->route('server.all');
|
return redirect()->route('server.all');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
// $validation = Validator::make($this->server->toArray(), [
|
$uniqueIPs = Server::all()->reject(function (Server $server) {
|
||||||
// 'ip' => [
|
return $server->id === $this->server->id;
|
||||||
// 'ip'
|
})->pluck('ip')->toArray();
|
||||||
// ],
|
if (in_array($this->server->ip, $uniqueIPs)) {
|
||||||
// ]);
|
$this->emit('error', 'IP address is already in use by another team.');
|
||||||
// if ($validation->fails()) {
|
return;
|
||||||
// foreach ($validation->errors()->getMessages() as $key => $value) {
|
}
|
||||||
// $this->addError("server.{$key}", $value[0]);
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
$this->server->settings->wildcard_domain = $this->wildcard_domain;
|
$this->server->settings->wildcard_domain = $this->wildcard_domain;
|
||||||
$this->server->settings->cleanup_after_percentage = $this->cleanup_after_percentage;
|
$this->server->settings->cleanup_after_percentage = $this->cleanup_after_percentage;
|
||||||
$this->server->settings->save();
|
$this->server->settings->save();
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class ByIp extends Component
|
|||||||
protected $rules = [
|
protected $rules = [
|
||||||
'name' => 'required|string',
|
'name' => 'required|string',
|
||||||
'description' => 'nullable|string',
|
'description' => 'nullable|string',
|
||||||
'ip' => 'required|ip',
|
'ip' => 'required',
|
||||||
'user' => 'required|string',
|
'user' => 'required|string',
|
||||||
'port' => 'required|integer',
|
'port' => 'required|integer',
|
||||||
];
|
];
|
||||||
@@ -79,7 +79,7 @@ class ByIp extends Component
|
|||||||
$server->settings->save();
|
$server->settings->save();
|
||||||
return redirect()->route('server.show', $server->uuid);
|
return redirect()->route('server.show', $server->uuid);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Server;
|
namespace App\Http\Livewire\Server;
|
||||||
|
|
||||||
use App\Actions\Proxy\CheckConfigurationSync;
|
use App\Actions\Proxy\CheckConfiguration;
|
||||||
use App\Actions\Proxy\SaveConfigurationSync;
|
use App\Actions\Proxy\SaveConfiguration;
|
||||||
use App\Enums\ProxyTypes;
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
@@ -48,34 +47,32 @@ class Proxy extends Component
|
|||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
resolve(SaveConfigurationSync::class)($this->server, $this->proxy_settings);
|
SaveConfiguration::run($this->server);
|
||||||
|
|
||||||
$this->server->proxy->redirect_url = $this->redirect_url;
|
$this->server->proxy->redirect_url = $this->redirect_url;
|
||||||
$this->server->save();
|
$this->server->save();
|
||||||
|
|
||||||
setup_default_redirect_404(redirect_url: $this->server->proxy->redirect_url, server: $this->server);
|
setup_default_redirect_404(redirect_url: $this->server->proxy->redirect_url, server: $this->server);
|
||||||
$this->emit('success', 'Proxy configuration saved.');
|
$this->emit('success', 'Proxy configuration saved.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reset_proxy_configuration()
|
public function reset_proxy_configuration()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server, true);
|
$this->proxy_settings = CheckConfiguration::run($this->server, true);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadProxyConfiguration()
|
public function loadProxyConfiguration()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
ray('loadProxyConfiguration');
|
$this->proxy_settings = CheckConfiguration::run($this->server);
|
||||||
$this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server);
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Server\Proxy;
|
namespace App\Http\Livewire\Server\Proxy;
|
||||||
|
|
||||||
|
use App\Actions\Proxy\SaveConfiguration;
|
||||||
use App\Actions\Proxy\StartProxy;
|
use App\Actions\Proxy\StartProxy;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@@ -12,20 +13,25 @@ class Deploy extends Component
|
|||||||
public $proxy_settings = null;
|
public $proxy_settings = null;
|
||||||
protected $listeners = ['proxyStatusUpdated'];
|
protected $listeners = ['proxyStatusUpdated'];
|
||||||
|
|
||||||
public function proxyStatusUpdated() {
|
public function proxyStatusUpdated()
|
||||||
|
{
|
||||||
$this->server->refresh();
|
$this->server->refresh();
|
||||||
}
|
}
|
||||||
public function startProxy()
|
public function startProxy()
|
||||||
{
|
{
|
||||||
if (
|
try {
|
||||||
$this->server->proxy->last_applied_settings &&
|
if (
|
||||||
$this->server->proxy->last_saved_settings !== $this->server->proxy->last_applied_settings
|
$this->server->proxy->last_applied_settings &&
|
||||||
) {
|
$this->server->proxy->last_saved_settings !== $this->server->proxy->last_applied_settings
|
||||||
resolve(SaveConfigurationSync::class)($this->server, $this->proxy_settings);
|
) {
|
||||||
}
|
SaveConfiguration::run($this->server);
|
||||||
|
}
|
||||||
|
|
||||||
$activity = resolve(StartProxy::class)($this->server);
|
$activity = resolve(StartProxy::class)($this->server);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stop()
|
public function stop()
|
||||||
|
|||||||
16
app/Http/Livewire/Server/Proxy/Modal.php
Normal file
16
app/Http/Livewire/Server/Proxy/Modal.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server\Proxy;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Modal extends Component
|
||||||
|
{
|
||||||
|
public Server $server;
|
||||||
|
|
||||||
|
public function proxyStatusUpdated()
|
||||||
|
{
|
||||||
|
$this->emit('proxyStatusUpdated');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Server\Proxy;
|
namespace App\Http\Livewire\Server\Proxy;
|
||||||
|
|
||||||
|
use App\Jobs\ContainerStatusJob;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
@@ -18,13 +19,11 @@ class Status extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ($this->server->isFunctional()) {
|
if ($this->server->isFunctional()) {
|
||||||
$container = getContainerStatus(server: $this->server, container_id: 'coolify-proxy');
|
dispatch_sync(new ContainerStatusJob($this->server));
|
||||||
$this->server->proxy->status = $container;
|
|
||||||
$this->server->save();
|
|
||||||
$this->emit('proxyStatusUpdated');
|
$this->emit('proxyStatusUpdated');
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function getProxyStatusWithNoti()
|
public function getProxyStatusWithNoti()
|
||||||
|
|||||||
@@ -13,9 +13,12 @@ class Show extends Component
|
|||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->firstOrFail();
|
$this->server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($this->server)) {
|
||||||
|
return redirect()->route('server.all');
|
||||||
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function render()
|
public function render()
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class ShowPrivateKey extends Component
|
|||||||
public function setPrivateKey($newPrivateKeyId)
|
public function setPrivateKey($newPrivateKeyId)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
refresh_server_connection($this->server->privateKey);
|
||||||
$oldPrivateKeyId = $this->server->private_key_id;
|
$oldPrivateKeyId = $this->server->private_key_id;
|
||||||
$this->server->update([
|
$this->server->update([
|
||||||
'private_key_id' => $newPrivateKeyId
|
'private_key_id' => $newPrivateKeyId
|
||||||
@@ -26,28 +27,41 @@ class ShowPrivateKey extends Component
|
|||||||
'private_key_id' => $oldPrivateKeyId
|
'private_key_id' => $oldPrivateKeyId
|
||||||
]);
|
]);
|
||||||
$this->server->refresh();
|
$this->server->refresh();
|
||||||
refresh_server_connection($this->server->privateKey);
|
refresh_server_connection($this->server->privateKey);
|
||||||
return general_error_handler($e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkConnection()
|
public function checkConnection()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_reachable' => true
|
||||||
|
]);
|
||||||
$this->emit('success', 'Server is reachable with this private key.');
|
$this->emit('success', 'Server is reachable with this private key.');
|
||||||
} else {
|
} else {
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_reachable' => false,
|
||||||
|
'is_usable' => false
|
||||||
|
]);
|
||||||
$this->emit('error', 'Server is not reachable with this private key.');
|
$this->emit('error', 'Server is not reachable with this private key.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($dockerVersion) {
|
if ($dockerVersion) {
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_usable' => true
|
||||||
|
]);
|
||||||
$this->emit('success', 'Server is usable for Coolify.');
|
$this->emit('success', 'Server is usable for Coolify.');
|
||||||
} else {
|
} else {
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_usable' => false
|
||||||
|
]);
|
||||||
$this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.');
|
$this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.');
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
throw new \Exception($e->getMessage());
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Settings;
|
namespace App\Http\Livewire\Settings;
|
||||||
|
|
||||||
use App\Jobs\ProxyContainerStatusJob;
|
use App\Jobs\ContainerStatusJob;
|
||||||
use App\Models\InstanceSettings as ModelsInstanceSettings;
|
use App\Models\InstanceSettings as ModelsInstanceSettings;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@@ -124,7 +124,7 @@ class Configuration extends Component
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
$this->save_configuration_to_disk($traefik_dynamic_conf, $file);
|
$this->save_configuration_to_disk($traefik_dynamic_conf, $file);
|
||||||
dispatch(new ProxyContainerStatusJob($this->server));
|
dispatch(new ContainerStatusJob($this->server));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class Email extends Component
|
|||||||
$this->settings->save();
|
$this->settings->save();
|
||||||
$this->emit('success', 'Settings saved successfully.');
|
$this->emit('success', 'Settings saved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function submitResend() {
|
public function submitResend() {
|
||||||
@@ -64,7 +64,7 @@ class Email extends Component
|
|||||||
$this->emit('success', 'Settings saved successfully.');
|
$this->emit('success', 'Settings saved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->settings->resend_enabled = false;
|
$this->settings->resend_enabled = false;
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function instantSaveResend() {
|
public function instantSaveResend() {
|
||||||
@@ -72,7 +72,7 @@ class Email extends Component
|
|||||||
$this->settings->smtp_enabled = false;
|
$this->settings->smtp_enabled = false;
|
||||||
$this->submitResend();
|
$this->submitResend();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
@@ -81,7 +81,7 @@ class Email extends Component
|
|||||||
$this->settings->resend_enabled = false;
|
$this->settings->resend_enabled = false;
|
||||||
$this->submit();
|
$this->submit();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ class Email extends Component
|
|||||||
$this->settings->save();
|
$this->settings->save();
|
||||||
$this->emit('success', 'Settings saved successfully.');
|
$this->emit('success', 'Settings saved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class Change extends Component
|
|||||||
$this->validate();
|
$this->validate();
|
||||||
$this->github_app->save();
|
$this->github_app->save();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ class Change extends Component
|
|||||||
$this->github_app->delete();
|
$this->github_app->delete();
|
||||||
redirect()->route('source.all');
|
redirect()->route('source.all');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class Create extends Component
|
|||||||
}
|
}
|
||||||
redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
|
redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class Actions extends Component
|
|||||||
$this->emit('reloadWindow', 5000);
|
$this->emit('reloadWindow', 5000);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function resume()
|
public function resume()
|
||||||
@@ -66,7 +66,7 @@ class Actions extends Component
|
|||||||
$this->emit('reloadWindow', 5000);
|
$this->emit('reloadWindow', 5000);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function stripeCustomerPortal() {
|
public function stripeCustomerPortal() {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class PricingPlans extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$payload = [
|
$payload = [
|
||||||
|
'billing_address_collection' => 'required',
|
||||||
'client_reference_id' => auth()->user()->id . ':' . currentTeam()->id,
|
'client_reference_id' => auth()->user()->id . ':' . currentTeam()->id,
|
||||||
'line_items' => [[
|
'line_items' => [[
|
||||||
'price' => $priceId,
|
'price' => $priceId,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class Create extends Component
|
|||||||
refreshSession();
|
refreshSession();
|
||||||
return redirect()->route('team.index');
|
return redirect()->route('team.index');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ class Delete extends Component
|
|||||||
$currentTeam = currentTeam();
|
$currentTeam = currentTeam();
|
||||||
$currentTeam->delete();
|
$currentTeam->delete();
|
||||||
|
|
||||||
$team = auth()->user()->teams()->first();
|
|
||||||
$currentTeam->members->each(function ($user) use ($currentTeam) {
|
$currentTeam->members->each(function ($user) use ($currentTeam) {
|
||||||
if ($user->id === auth()->user()->id) {
|
if ($user->id === auth()->user()->id) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class Form extends Component
|
|||||||
$this->team->save();
|
$this->team->save();
|
||||||
refreshSession();
|
refreshSession();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ namespace App\Http\Livewire\Team;
|
|||||||
|
|
||||||
use App\Models\TeamInvitation;
|
use App\Models\TeamInvitation;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\TransactionalEmails\InvitationLink;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class InviteLink extends Component
|
class InviteLink extends Component
|
||||||
{
|
{
|
||||||
@@ -20,64 +24,74 @@ class InviteLink extends Component
|
|||||||
|
|
||||||
public function viaEmail()
|
public function viaEmail()
|
||||||
{
|
{
|
||||||
$this->generate_invite_link(isEmail: true);
|
$this->generate_invite_link(sendEmail: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generate_invite_link(bool $isEmail = false)
|
public function viaLink()
|
||||||
|
{
|
||||||
|
$this->generate_invite_link(sendEmail: false);
|
||||||
|
}
|
||||||
|
private function generate_invite_link(bool $sendEmail = false)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$uuid = new Cuid2(32);
|
|
||||||
$link = url('/') . config('constants.invitation.link.base_url') . $uuid;
|
|
||||||
|
|
||||||
$user = User::whereEmail($this->email);
|
|
||||||
|
|
||||||
if (!$user->exists()) {
|
|
||||||
return general_error_handler(that: $this, customErrorMessage: "$this->email must be registered first (or activate transactional emails to invite via email).");
|
|
||||||
}
|
|
||||||
|
|
||||||
$member_emails = currentTeam()->members()->get()->pluck('email');
|
$member_emails = currentTeam()->members()->get()->pluck('email');
|
||||||
if ($member_emails->contains($this->email)) {
|
if ($member_emails->contains($this->email)) {
|
||||||
return general_error_handler(that: $this, customErrorMessage: "$this->email is already a member of " . currentTeam()->name . ".");
|
return handleError(livewire: $this, customErrorMessage: "$this->email is already a member of " . currentTeam()->name . ".");
|
||||||
}
|
}
|
||||||
|
$uuid = new Cuid2(32);
|
||||||
|
$link = url('/') . config('constants.invitation.link.base_url') . $uuid;
|
||||||
|
$user = User::whereEmail($this->email)->first();
|
||||||
|
|
||||||
$invitation = TeamInvitation::whereEmail($this->email);
|
if (is_null($user)) {
|
||||||
|
$password = Str::password();
|
||||||
if ($invitation->exists()) {
|
$user = User::create([
|
||||||
$created_at = $invitation->first()->created_at;
|
'name' => Str::of($this->email)->before('@'),
|
||||||
$diff = $created_at->diffInMinutes(now());
|
'email' => $this->email,
|
||||||
if ($diff <= config('constants.invitation.link.expiration')) {
|
'password' => Hash::make($password),
|
||||||
return general_error_handler(that: $this, customErrorMessage: "Invitation already sent to $this->email and waiting for action.");
|
'force_password_reset' => true,
|
||||||
|
]);
|
||||||
|
$token = Crypt::encryptString("{$user->email}@@@$password");
|
||||||
|
$link = route('auth.link', ['token' => $token]);
|
||||||
|
}
|
||||||
|
$invitation = TeamInvitation::whereEmail($this->email)->first();
|
||||||
|
if (!is_null($invitation)) {
|
||||||
|
$invitationValid = $invitation->isValid();
|
||||||
|
if ($invitationValid) {
|
||||||
|
return handleError(livewire: $this, customErrorMessage: "Pending invitation already exists for $this->email.");
|
||||||
} else {
|
} else {
|
||||||
$invitation->delete();
|
$invitation->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TeamInvitation::firstOrCreate([
|
$invitation = TeamInvitation::firstOrCreate([
|
||||||
'team_id' => currentTeam()->id,
|
'team_id' => currentTeam()->id,
|
||||||
'uuid' => $uuid,
|
'uuid' => $uuid,
|
||||||
'email' => $this->email,
|
'email' => $this->email,
|
||||||
'role' => $this->role,
|
'role' => $this->role,
|
||||||
'link' => $link,
|
'link' => $link,
|
||||||
'via' => $isEmail ? 'email' : 'link',
|
'via' => $sendEmail ? 'email' : 'link',
|
||||||
]);
|
]);
|
||||||
if ($isEmail) {
|
if ($sendEmail) {
|
||||||
$user->first()->notify(new InvitationLink);
|
$mail = new MailMessage();
|
||||||
|
$mail->view('emails.invitation-link', [
|
||||||
|
'team' => currentTeam()->name,
|
||||||
|
'invitation_link' => $link,
|
||||||
|
]);
|
||||||
|
$mail->subject('You have been invited to ' . currentTeam()->name . ' on ' . config('app.name') . '.');
|
||||||
|
send_user_an_email($mail, $this->email);
|
||||||
$this->emit('success', 'Invitation sent via email successfully.');
|
$this->emit('success', 'Invitation sent via email successfully.');
|
||||||
|
$this->emit('refreshInvitations');
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
$this->emit('success', 'Invitation link generated.');
|
$this->emit('success', 'Invitation link generated.');
|
||||||
|
$this->emit('refreshInvitations');
|
||||||
}
|
}
|
||||||
$this->emit('refreshInvitations');
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$error_message = $e->getMessage();
|
$error_message = $e->getMessage();
|
||||||
if ($e->getCode() === '23505') {
|
if ($e->getCode() === '23505') {
|
||||||
$error_message = 'Invitation already sent.';
|
$error_message = 'Invitation already sent.';
|
||||||
}
|
}
|
||||||
return general_error_handler(err: $e, that: $this, customErrorMessage: $error_message);
|
return handleError(error: $e, livewire: $this, customErrorMessage: $error_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function viaLink()
|
|
||||||
{
|
|
||||||
$this->generate_invite_link();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Livewire\Team;
|
namespace App\Http\Livewire\Team;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Member extends Component
|
class Member extends Component
|
||||||
@@ -24,6 +25,10 @@ class Member extends Component
|
|||||||
public function remove()
|
public function remove()
|
||||||
{
|
{
|
||||||
$this->member->teams()->detach(currentTeam());
|
$this->member->teams()->detach(currentTeam());
|
||||||
|
Cache::forget("team:{$this->member->id}");
|
||||||
|
Cache::remember('team:' . $this->member->id, 3600, function() {
|
||||||
|
return $this->member->teams()->first();
|
||||||
|
});
|
||||||
$this->emit('reloadWindow');
|
$this->emit('reloadWindow');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class Create extends Component
|
|||||||
$this->storage->save();
|
$this->storage->save();
|
||||||
return redirect()->route('team.storages.show', $this->storage->uuid);
|
return redirect()->route('team.storages.show', $this->storage->uuid);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class Create extends Component
|
|||||||
$this->storage->testConnection();
|
$this->storage->testConnection();
|
||||||
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
|
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Form extends Component
|
|||||||
$this->storage->testConnection();
|
$this->storage->testConnection();
|
||||||
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
|
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ class Form extends Component
|
|||||||
$this->storage->delete();
|
$this->storage->delete();
|
||||||
return redirect()->route('team.storages.all');
|
return redirect()->route('team.storages.all');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class Form extends Component
|
|||||||
$this->storage->save();
|
$this->storage->save();
|
||||||
$this->emit('success', 'Storage settings saved.');
|
$this->emit('success', 'Storage settings saved.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ class Upgrade extends Component
|
|||||||
}
|
}
|
||||||
$this->showProgress = true;
|
$this->showProgress = true;
|
||||||
resolve(UpdateCoolify::class)(true);
|
resolve(UpdateCoolify::class)(true);
|
||||||
Toaster::success("Upgrading to {$this->latestVersion} version...");
|
$this->emit('success', "Upgrading to {$this->latestVersion} version...");
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Jobs\SendConfirmationForWaitlistJob;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Waitlist;
|
use App\Models\Waitlist;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
@@ -46,14 +47,14 @@ class Index extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$waitlist = Waitlist::create([
|
$waitlist = Waitlist::create([
|
||||||
'email' => $this->email,
|
'email' => Str::lower($this->email),
|
||||||
'type' => 'registration',
|
'type' => 'registration',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->emit('success', 'Check your email to verify your email address.');
|
$this->emit('success', 'Check your email to verify your email address.');
|
||||||
dispatch(new SendConfirmationForWaitlistJob($this->email, $waitlist->uuid));
|
dispatch(new SendConfirmationForWaitlistJob($this->email, $waitlist->uuid));
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Http\Middleware;
|
|||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class IsBoardingFlow
|
class IsBoardingFlow
|
||||||
{
|
{
|
||||||
@@ -17,6 +18,9 @@ class IsBoardingFlow
|
|||||||
{
|
{
|
||||||
// ray()->showQueries()->color('orange');
|
// ray()->showQueries()->color('orange');
|
||||||
if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
|
if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
|
||||||
|
if (Str::startsWith($request->path(), 'invitations')) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
return redirect('boarding');
|
return redirect('boarding');
|
||||||
}
|
}
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Http\Middleware;
|
|||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class IsSubscriptionValid
|
class IsSubscriptionValid
|
||||||
{
|
{
|
||||||
@@ -31,6 +32,9 @@ class IsSubscriptionValid
|
|||||||
if (!isSubscriptionActive() && !isSubscriptionOnGracePeriod()) {
|
if (!isSubscriptionActive() && !isSubscriptionOnGracePeriod()) {
|
||||||
// ray('SubscriptionValid Middleware');
|
// ray('SubscriptionValid Middleware');
|
||||||
if (!in_array($request->path(), allowedPathsForUnsubscribedAccounts())) {
|
if (!in_array($request->path(), allowedPathsForUnsubscribedAccounts())) {
|
||||||
|
if (Str::startsWith($request->path(), 'invitations')) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
return redirect('subscription');
|
return redirect('subscription');
|
||||||
} else {
|
} else {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\ApplicationPreview;
|
|
||||||
use App\Notifications\Application\StatusChanged;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class ApplicationContainerStatusJob implements ShouldQueue, ShouldBeUnique
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
public string $containerName;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public Application $application,
|
|
||||||
public int $pullRequestId = 0)
|
|
||||||
{
|
|
||||||
$this->containerName = generateApplicationContainerName($application->uuid, $pullRequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function uniqueId(): string
|
|
||||||
{
|
|
||||||
return $this->containerName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$status = getApplicationContainerStatus(application: $this->application);
|
|
||||||
if ($this->application->status === 'running' && $status !== 'running') {
|
|
||||||
// $this->application->environment->project->team->notify(new StatusChanged($this->application));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->pullRequestId !== 0) {
|
|
||||||
$preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pullRequestId);
|
|
||||||
$preview->status = $status;
|
|
||||||
$preview->save();
|
|
||||||
} else {
|
|
||||||
$this->application->status = $status;
|
|
||||||
$this->application->save();
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
ray($e->getMessage());
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,10 +17,10 @@ use App\Notifications\Application\DeploymentSuccess;
|
|||||||
use App\Traits\ExecuteRemoteCommand;
|
use App\Traits\ExecuteRemoteCommand;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
@@ -28,10 +28,8 @@ use Spatie\Url\Url;
|
|||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
use Yosymfony\Toml\Toml;
|
|
||||||
use Yosymfony\Toml\TomlArray;
|
|
||||||
|
|
||||||
class ApplicationDeploymentJob implements ShouldQueue
|
class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, ExecuteRemoteCommand;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, ExecuteRemoteCommand;
|
||||||
|
|
||||||
@@ -49,7 +47,6 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
private GithubApp|GitlabApp $source;
|
private GithubApp|GitlabApp $source;
|
||||||
private StandaloneDocker|SwarmDocker $destination;
|
private StandaloneDocker|SwarmDocker $destination;
|
||||||
private Server $server;
|
private Server $server;
|
||||||
private string $private_key_location;
|
|
||||||
private ApplicationPreview|null $preview = null;
|
private ApplicationPreview|null $preview = null;
|
||||||
|
|
||||||
private string $container_name;
|
private string $container_name;
|
||||||
@@ -92,7 +89,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
||||||
|
|
||||||
$this->container_name = generateApplicationContainerName($this->application->uuid, $this->pull_request_id);
|
$this->container_name = generateApplicationContainerName($this->application->uuid, $this->pull_request_id);
|
||||||
$this->private_key_location = save_private_key_for_server($this->server);
|
addPrivateKeyToSshAgent($this->server);
|
||||||
$this->saved_outputs = collect();
|
$this->saved_outputs = collect();
|
||||||
|
|
||||||
// Set preview fqdn
|
// Set preview fqdn
|
||||||
@@ -122,6 +119,9 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
if ($containers->count() > 0) {
|
if ($containers->count() > 0) {
|
||||||
$this->currently_running_container_name = data_get($containers[0], 'Names');
|
$this->currently_running_container_name = data_get($containers[0], 'Names');
|
||||||
}
|
}
|
||||||
|
if ($this->pull_request_id !== 0 && $this->pull_request_id !== null) {
|
||||||
|
$this->currently_running_container_name = $this->container_name;
|
||||||
|
}
|
||||||
$this->application_deployment_queue->update([
|
$this->application_deployment_queue->update([
|
||||||
'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
|
'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
|
||||||
]);
|
]);
|
||||||
@@ -135,7 +135,9 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
$this->deploy();
|
$this->deploy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->application->fqdn) dispatch(new ProxyContainerStatusJob($this->server));
|
if ($this->server->isProxyShouldRun()) {
|
||||||
|
dispatch(new ContainerStatusJob($this->server));
|
||||||
|
}
|
||||||
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ray($e);
|
ray($e);
|
||||||
@@ -175,7 +177,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
$this->execute_in_builder("echo '$dockerfile_base64' | base64 -d > $this->workdir/Dockerfile")
|
executeInDocker($this->deployment_uuid, "echo '$dockerfile_base64' | base64 -d > $this->workdir/Dockerfile")
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
$this->build_image_name = Str::lower("{$this->application->git_repository}:build");
|
$this->build_image_name = Str::lower("{$this->application->git_repository}:build");
|
||||||
@@ -270,6 +272,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
"echo 'Rolling update completed.'"
|
"echo 'Rolling update completed.'"
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
$this->application->update(['status' => 'running']);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$counter++;
|
$counter++;
|
||||||
@@ -296,7 +299,11 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
// $this->generate_build_env_variables();
|
// $this->generate_build_env_variables();
|
||||||
// $this->add_build_env_variables_to_dockerfile();
|
// $this->add_build_env_variables_to_dockerfile();
|
||||||
$this->build_image();
|
$this->build_image();
|
||||||
$this->rolling_update();
|
$this->stop_running_container();
|
||||||
|
$this->execute_remote_command(
|
||||||
|
["echo -n 'Starting preview deployment.'"],
|
||||||
|
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function prepare_builder_image()
|
private function prepare_builder_image()
|
||||||
@@ -317,16 +324,12 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"command" => $this->execute_in_builder("mkdir -p {$this->workdir}")
|
"command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}")
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function execute_in_builder(string $command)
|
|
||||||
{
|
|
||||||
return "docker exec {$this->deployment_uuid} bash -c '{$command}'";
|
|
||||||
// return "docker exec {$this->deployment_uuid} bash -c '{$command} |& tee -a /proc/1/fd/1; [ \$PIPESTATUS -eq 0 ] || exit \$PIPESTATUS'";
|
|
||||||
}
|
|
||||||
|
|
||||||
private function clone_repository()
|
private function clone_repository()
|
||||||
{
|
{
|
||||||
@@ -338,7 +341,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
$this->importing_git_repository()
|
$this->importing_git_repository()
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
$this->execute_in_builder("cd {$this->workdir} && git rev-parse HEAD"),
|
executeInDocker($this->deployment_uuid, "cd {$this->workdir} && git rev-parse HEAD"),
|
||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
"save" => "git_commit_sha"
|
"save" => "git_commit_sha"
|
||||||
],
|
],
|
||||||
@@ -365,13 +368,13 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->workdir}";
|
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->workdir}";
|
||||||
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
||||||
|
|
||||||
$commands->push($this->execute_in_builder($git_clone_command));
|
$commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
|
||||||
} else {
|
} else {
|
||||||
$github_access_token = generate_github_installation_token($this->source);
|
$github_access_token = generate_github_installation_token($this->source);
|
||||||
$commands->push($this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}"));
|
$commands->push(executeInDocker($this->deployment_uuid, "git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}"));
|
||||||
}
|
}
|
||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
$commands->push($this->execute_in_builder("cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
|
$commands->push(executeInDocker($this->deployment_uuid, "cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
|
||||||
}
|
}
|
||||||
return $commands->implode(' && ');
|
return $commands->implode(' && ');
|
||||||
}
|
}
|
||||||
@@ -381,10 +384,10 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
$git_clone_command = "GIT_SSH_COMMAND=\"ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_full_url} {$this->workdir}";
|
$git_clone_command = "GIT_SSH_COMMAND=\"ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_full_url} {$this->workdir}";
|
||||||
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
||||||
$commands = collect([
|
$commands = collect([
|
||||||
$this->execute_in_builder("mkdir -p /root/.ssh"),
|
executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh"),
|
||||||
$this->execute_in_builder("echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa"),
|
executeInDocker($this->deployment_uuid, "echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa"),
|
||||||
$this->execute_in_builder("chmod 600 /root/.ssh/id_rsa"),
|
executeInDocker($this->deployment_uuid, "chmod 600 /root/.ssh/id_rsa"),
|
||||||
$this->execute_in_builder($git_clone_command)
|
executeInDocker($this->deployment_uuid, $git_clone_command)
|
||||||
]);
|
]);
|
||||||
return $commands->implode(' && ');
|
return $commands->implode(' && ');
|
||||||
}
|
}
|
||||||
@@ -407,7 +410,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
private function cleanup_git()
|
private function cleanup_git()
|
||||||
{
|
{
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[$this->execute_in_builder("rm -fr {$this->workdir}/.git")],
|
[executeInDocker($this->deployment_uuid, "rm -fr {$this->workdir}/.git")],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,8 +421,8 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
"echo -n 'Generating nixpacks configuration.'",
|
"echo -n 'Generating nixpacks configuration.'",
|
||||||
],
|
],
|
||||||
[$this->nixpacks_build_cmd()],
|
[$this->nixpacks_build_cmd()],
|
||||||
[$this->execute_in_builder("cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
|
[executeInDocker($this->deployment_uuid, "cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
|
||||||
[$this->execute_in_builder("rm -f {$this->workdir}/.nixpacks/Dockerfile")]
|
[executeInDocker($this->deployment_uuid, "rm -f {$this->workdir}/.nixpacks/Dockerfile")]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,7 +440,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
|
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
|
||||||
}
|
}
|
||||||
$nixpacks_command .= " {$this->workdir}";
|
$nixpacks_command .= " {$this->workdir}";
|
||||||
return $this->execute_in_builder($nixpacks_command);
|
return executeInDocker($this->deployment_uuid, $nixpacks_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generate_env_variables()
|
private function generate_env_variables()
|
||||||
@@ -515,7 +518,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
$this->docker_compose = Yaml::dump($docker_compose, 10);
|
$this->docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$this->docker_compose_base64 = base64_encode($this->docker_compose);
|
$this->docker_compose_base64 = base64_encode($this->docker_compose);
|
||||||
$this->execute_remote_command([$this->execute_in_builder("echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]);
|
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generate_local_persistent_volumes()
|
private function generate_local_persistent_volumes()
|
||||||
@@ -576,10 +579,15 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
|
|
||||||
private function set_labels_for_applications()
|
private function set_labels_for_applications()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
$appId = $this->application->id;
|
||||||
|
if ($this->pull_request_id !== 0) {
|
||||||
|
$appId = $appId . '-pr-' . $this->pull_request_id;
|
||||||
|
}
|
||||||
$labels = [];
|
$labels = [];
|
||||||
$labels[] = 'coolify.managed=true';
|
$labels[] = 'coolify.managed=true';
|
||||||
$labels[] = 'coolify.version=' . config('version');
|
$labels[] = 'coolify.version=' . config('version');
|
||||||
$labels[] = 'coolify.applicationId=' . $this->application->id;
|
$labels[] = 'coolify.applicationId=' . $appId;
|
||||||
$labels[] = 'coolify.type=application';
|
$labels[] = 'coolify.type=application';
|
||||||
$labels[] = 'coolify.name=' . $this->application->name;
|
$labels[] = 'coolify.name=' . $this->application->name;
|
||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
@@ -640,7 +648,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
|
|
||||||
private function generate_healthcheck_commands()
|
private function generate_healthcheck_commands()
|
||||||
{
|
{
|
||||||
if ($this->application->dockerfile) {
|
if ($this->application->dockerfile || $this->application->build_pack === 'dockerfile') {
|
||||||
// TODO: disabled HC because there are several ways to hc a simple docker image, hard to figure out a good way. Like some docker images (pocketbase) does not have curl.
|
// TODO: disabled HC because there are several ways to hc a simple docker image, hard to figure out a good way. Like some docker images (pocketbase) does not have curl.
|
||||||
return 'exit 0';
|
return 'exit 0';
|
||||||
}
|
}
|
||||||
@@ -667,7 +675,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
|||||||
|
|
||||||
if ($this->application->settings->is_static) {
|
if ($this->application->settings->is_static) {
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
$this->execute_in_builder("docker build --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
|
executeInDocker($this->deployment_uuid, "docker build --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$dockerfile = base64_encode("FROM {$this->application->static_image}
|
$dockerfile = base64_encode("FROM {$this->application->static_image}
|
||||||
@@ -694,18 +702,18 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
}");
|
}");
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
$this->execute_in_builder("echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile-prod")
|
executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile-prod")
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
$this->execute_in_builder("echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
|
executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
$this->execute_in_builder("docker build --network host -f {$this->workdir}/Dockerfile-prod {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
|
executeInDocker($this->deployment_uuid, "docker build --network host -f {$this->workdir}/Dockerfile-prod {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
$this->execute_in_builder("docker build --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
|
executeInDocker($this->deployment_uuid, "docker build --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -715,7 +723,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
if ($this->currently_running_container_name) {
|
if ($this->currently_running_container_name) {
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
["echo -n 'Removing old version of your application.'"],
|
["echo -n 'Removing old version of your application.'"],
|
||||||
[$this->execute_in_builder("docker rm -f $this->currently_running_container_name >/dev/null 2>&1"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "docker rm -f $this->currently_running_container_name >/dev/null 2>&1"), "hidden" => true],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -724,7 +732,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
{
|
{
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
["echo -n 'Rolling update started.'"],
|
["echo -n 'Rolling update started.'"],
|
||||||
[$this->execute_in_builder("docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -747,7 +755,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
private function add_build_env_variables_to_dockerfile()
|
private function add_build_env_variables_to_dockerfile()
|
||||||
{
|
{
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
$this->execute_in_builder("cat {$this->workdir}/Dockerfile"), "hidden" => true, "save" => 'dockerfile'
|
executeInDocker($this->deployment_uuid, "cat {$this->workdir}/Dockerfile"), "hidden" => true, "save" => 'dockerfile'
|
||||||
]);
|
]);
|
||||||
$dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
|
$dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
|
||||||
|
|
||||||
@@ -756,7 +764,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
}
|
}
|
||||||
$dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
|
$dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
$this->execute_in_builder("echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}/Dockerfile"),
|
executeInDocker($this->deployment_uuid, "echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}/Dockerfile"),
|
||||||
"hidden" => true
|
"hidden" => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ use App\Enums\ProcessStatus;
|
|||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class ApplicationPullRequestUpdateJob implements ShouldQueue
|
class ApplicationPullRequestUpdateJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ namespace App\Jobs;
|
|||||||
|
|
||||||
use App\Actions\License\CheckResaleLicense;
|
use App\Actions\License\CheckResaleLicense;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class CheckResaleLicenseJob implements ShouldQueue
|
class CheckResaleLicenseJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\TeamInvitation;
|
||||||
use App\Models\Waitlist;
|
use App\Models\Waitlist;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique
|
class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
@@ -31,7 +33,12 @@ class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
send_internal_notification('CleanupInstanceStuffsJob failed with error: ' . $e->getMessage());
|
send_internal_notification('CleanupInstanceStuffsJob failed with error: ' . $e->getMessage());
|
||||||
ray($e->getMessage());
|
ray($e->getMessage());
|
||||||
throw $e;
|
}
|
||||||
|
try {
|
||||||
|
$this->cleanup_invitation_link();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
send_internal_notification('CleanupInstanceStuffsJob failed with error: ' . $e->getMessage());
|
||||||
|
ray($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,4 +49,11 @@ class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique
|
|||||||
$item->delete();
|
$item->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private function cleanup_invitation_link()
|
||||||
|
{
|
||||||
|
$invitation = TeamInvitation::all();
|
||||||
|
foreach ($invitation as $item) {
|
||||||
|
$item->isValid();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
295
app/Jobs/ContainerStatusJob.php
Normal file
295
app/Jobs/ContainerStatusJob.php
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Actions\Proxy\StartProxy;
|
||||||
|
use App\Models\ApplicationPreview;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Notifications\Container\ContainerRestarted;
|
||||||
|
use App\Notifications\Container\ContainerStopped;
|
||||||
|
use App\Notifications\Server\Unreachable;
|
||||||
|
use Arr;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
|
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\Str;
|
||||||
|
|
||||||
|
class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $tries = 1;
|
||||||
|
public $timeout = 120;
|
||||||
|
|
||||||
|
public function __construct(public Server $server)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function middleware(): array
|
||||||
|
{
|
||||||
|
return [new WithoutOverlapping($this->server->uuid)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uniqueId(): string
|
||||||
|
{
|
||||||
|
return $this->server->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkServerConnection()
|
||||||
|
{
|
||||||
|
$uptime = instant_remote_process(['uptime'], $this->server, false);
|
||||||
|
if (!is_null($uptime)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// ray()->clearAll();
|
||||||
|
$serverUptimeCheckNumber = 0;
|
||||||
|
$serverUptimeCheckNumberMax = 3;
|
||||||
|
while (true) {
|
||||||
|
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
|
||||||
|
$this->server->settings()->update(['is_reachable' => false]);
|
||||||
|
$this->server->team->notify(new Unreachable($this->server));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$result = $this->checkServerConnection();
|
||||||
|
if ($result) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$serverUptimeCheckNumber++;
|
||||||
|
sleep(5);
|
||||||
|
}
|
||||||
|
$containers = instant_remote_process(["docker container ls -q"], $this->server);
|
||||||
|
if (!$containers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server);
|
||||||
|
$containers = format_docker_command_output_to_json($containers);
|
||||||
|
$applications = $this->server->applications();
|
||||||
|
$databases = $this->server->databases();
|
||||||
|
$previews = $this->server->previews();
|
||||||
|
|
||||||
|
/// Check if proxy is running
|
||||||
|
$foundProxyContainer = $containers->filter(function ($value, $key) {
|
||||||
|
return data_get($value, 'Name') === '/coolify-proxy';
|
||||||
|
})->first();
|
||||||
|
if (!$foundProxyContainer) {
|
||||||
|
if ($this->server->isProxyShouldRun()) {
|
||||||
|
resolve(StartProxy::class)($this->server, false);
|
||||||
|
$this->server->team->notify(new ContainerRestarted('coolify-proxy', $this->server));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ray($foundProxyContainer);
|
||||||
|
$this->server->proxy->status = data_get($foundProxyContainer, 'State.Status');
|
||||||
|
$this->server->save();
|
||||||
|
}
|
||||||
|
$foundApplications = [];
|
||||||
|
$foundApplicationPreviews = [];
|
||||||
|
$foundDatabases = [];
|
||||||
|
foreach ($containers as $container) {
|
||||||
|
$containerStatus = data_get($container, 'State.Status');
|
||||||
|
$labels = data_get($container, 'Config.Labels');
|
||||||
|
$labels = Arr::undot(format_docker_labels_to_json($labels));
|
||||||
|
$labelId = data_get($labels, 'coolify.applicationId');
|
||||||
|
if ($labelId) {
|
||||||
|
if (str_contains($labelId, '-pr-')) {
|
||||||
|
$previewId = (int) Str::after($labelId, '-pr-');
|
||||||
|
$applicationId = (int) Str::before($labelId, '-pr-');
|
||||||
|
$preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $previewId)->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 = $applications->where('id', $labelId)->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');
|
||||||
|
if ($uuid) {
|
||||||
|
$database = $databases->where('uuid', $uuid)->first();
|
||||||
|
if ($database) {
|
||||||
|
$foundDatabases[] = $database->id;
|
||||||
|
$statusFromDb = $database->status;
|
||||||
|
if ($statusFromDb !== $containerStatus) {
|
||||||
|
$database->update(['status' => $containerStatus]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Notify user that this container should not be there.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$notRunningApplications = $applications->pluck('id')->diff($foundApplications);
|
||||||
|
foreach ($notRunningApplications as $applicationId) {
|
||||||
|
$application = $applications->where('id', $applicationId)->first();
|
||||||
|
if ($application->status === 'exited') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$application->update(['status' => 'exited']);
|
||||||
|
|
||||||
|
$name = data_get($application, 'name');
|
||||||
|
$fqdn = data_get($application, 'fqdn');
|
||||||
|
|
||||||
|
$containerName = $name ? "$name ($fqdn)" : $fqdn;
|
||||||
|
|
||||||
|
$project = data_get($application, 'environment.project');
|
||||||
|
$environment = data_get($application, 'environment');
|
||||||
|
|
||||||
|
$url = base_url() . '/project/' . $project->uuid . "/" . $environment->name . "/application/" . $application->uuid;
|
||||||
|
|
||||||
|
$this->server->team->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
|
}
|
||||||
|
$notRunningApplicationPreviews = $previews->pluck('id')->diff($foundApplicationPreviews);
|
||||||
|
foreach ($notRunningApplicationPreviews as $previewId) {
|
||||||
|
$preview = $previews->where('id', $previewId)->first();
|
||||||
|
if ($preview->status === 'exited') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$preview->update(['status' => 'exited']);
|
||||||
|
|
||||||
|
$name = data_get($preview, 'name');
|
||||||
|
$fqdn = data_get($preview, 'fqdn');
|
||||||
|
|
||||||
|
$containerName = $name ? "$name ($fqdn)" : $fqdn;
|
||||||
|
|
||||||
|
$project = data_get($preview, 'application.environment.project');
|
||||||
|
$environment = data_get($preview, 'application.environment');
|
||||||
|
|
||||||
|
$url = base_url() . '/project/' . $project->uuid . "/" . $environment->name . "/application/" . $preview->application->uuid;
|
||||||
|
$this->server->team->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
|
}
|
||||||
|
$notRunningDatabases = $databases->pluck('id')->diff($foundDatabases);
|
||||||
|
foreach ($notRunningDatabases as $database) {
|
||||||
|
$database = $databases->where('id', $database)->first();
|
||||||
|
if ($database->status === 'exited') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$database->update(['status' => 'exited']);
|
||||||
|
|
||||||
|
$name = data_get($database, 'name');
|
||||||
|
$fqdn = data_get($database, 'fqdn');
|
||||||
|
|
||||||
|
$containerName = $name;
|
||||||
|
|
||||||
|
$project = data_get($database, 'environment.project');
|
||||||
|
$environment = data_get($database, 'environment');
|
||||||
|
|
||||||
|
$url = base_url() . '/project/' . $project->uuid . "/" . $environment->name . "/database/" . $database->uuid;
|
||||||
|
$this->server->team->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
foreach ($applications as $application) {
|
||||||
|
$uuid = data_get($application, 'uuid');
|
||||||
|
$id = data_get($application, 'id');
|
||||||
|
$foundContainer = $containers->filter(function ($value, $key) use ($id, $uuid) {
|
||||||
|
$labels = data_get($value, 'Config.Labels');
|
||||||
|
$labels = Arr::undot(format_docker_labels_to_json($labels));
|
||||||
|
$labelId = data_get($labels, 'coolify.applicationId');
|
||||||
|
if ($labelId == $id) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
$isPR = Str::startsWith(data_get($value, 'Name'), "/$uuid");
|
||||||
|
$isPR = Str::contains(data_get($value, 'Name'), "-pr-");
|
||||||
|
if ($isPR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
})->first();
|
||||||
|
if ($foundContainer) {
|
||||||
|
$containerStatus = data_get($foundContainer, 'State.Status');
|
||||||
|
$databaseStatus = data_get($application, 'status');
|
||||||
|
if ($containerStatus !== $databaseStatus) {
|
||||||
|
$application->update(['status' => $containerStatus]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$databaseStatus = data_get($application, 'status');
|
||||||
|
if ($databaseStatus !== 'exited') {
|
||||||
|
$application->update(['status' => 'exited']);
|
||||||
|
$name = data_get($application, 'name');
|
||||||
|
$fqdn = data_get($application, 'fqdn');
|
||||||
|
$containerName = $name ? "$name ($fqdn)" : $fqdn;
|
||||||
|
$project = data_get($application, 'environment.project');
|
||||||
|
$environment = data_get($application, 'environment');
|
||||||
|
$url = base_url() . '/project/' . $project->uuid . "/" . $environment->name . "/application/" . $application->uuid;
|
||||||
|
$this->server->team->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$previews = $application->previews;
|
||||||
|
foreach ($previews as $preview) {
|
||||||
|
$foundContainer = $containers->filter(function ($value, $key) use ($id, $uuid, $preview) {
|
||||||
|
$labels = data_get($value, 'Config.Labels');
|
||||||
|
$labels = Arr::undot(format_docker_labels_to_json($labels));
|
||||||
|
$labelId = data_get($labels, 'coolify.applicationId');
|
||||||
|
if ($labelId == "$id-pr-{$preview->id}") {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
return Str::startsWith(data_get($value, 'Name'), "/$uuid-pr-{$preview->id}");
|
||||||
|
})->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($databases as $database) {
|
||||||
|
$uuid = data_get($database, 'uuid');
|
||||||
|
$foundContainer = $containers->filter(function ($value, $key) use ($uuid) {
|
||||||
|
return Str::startsWith(data_get($value, 'Name'), "/$uuid");
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if ($foundContainer) {
|
||||||
|
$containerStatus = data_get($foundContainer, 'State.Status');
|
||||||
|
$databaseStatus = data_get($database, 'status');
|
||||||
|
if ($containerStatus !== $databaseStatus) {
|
||||||
|
$database->update(['status' => $containerStatus]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$databaseStatus = data_get($database, 'status');
|
||||||
|
if ($databaseStatus !== 'exited') {
|
||||||
|
$database->update(['status' => 'exited']);
|
||||||
|
$name = data_get($database, 'name');
|
||||||
|
$containerName = $name;
|
||||||
|
$project = data_get($database, 'environment.project');
|
||||||
|
$environment = data_get($database, 'environment');
|
||||||
|
$url = base_url() . '/project/' . $project->uuid . "/" . $environment->name . "/database/" . $database->uuid;
|
||||||
|
$this->server->team->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO Monitor other containers not managed by Coolify
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
send_internal_notification('ContainerStatusJob failed with: ' . $e->getMessage());
|
||||||
|
ray($e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,14 @@ namespace App\Jobs;
|
|||||||
|
|
||||||
use App\Actions\CoolifyTask\RunRemoteProcess;
|
use App\Actions\CoolifyTask\RunRemoteProcess;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
|
|
||||||
class CoolifyTask implements ShouldQueue
|
class CoolifyTask implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ use App\Notifications\Database\BackupFailed;
|
|||||||
use App\Notifications\Database\BackupSuccess;
|
use App\Notifications\Database\BackupSuccess;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Throwable;
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class DatabaseBackupJob implements ShouldQueue
|
class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ class DatabaseBackupJob implements ShouldQueue
|
|||||||
|
|
||||||
$this->backup_status = 'success';
|
$this->backup_status = 'success';
|
||||||
$this->team->notify(new BackupSuccess($this->backup, $this->database));
|
$this->team->notify(new BackupSuccess($this->backup, $this->database));
|
||||||
} catch (Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->backup_status = 'failed';
|
$this->backup_status = 'failed';
|
||||||
$this->add_to_backup_output($e->getMessage());
|
$this->add_to_backup_output($e->getMessage());
|
||||||
ray('Backup failed for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location . '\n\nError:' . $e->getMessage());
|
ray('Backup failed for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location . '\n\nError:' . $e->getMessage());
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use App\Models\ApplicationPreview;
|
|
||||||
use App\Models\StandalonePostgresql;
|
|
||||||
use App\Notifications\Application\StatusChanged;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class DatabaseContainerStatusJob implements ShouldQueue, ShouldBeUnique
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
public string $containerName;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public StandalonePostgresql $database,
|
|
||||||
) {
|
|
||||||
$this->containerName = $database->uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function uniqueId(): string
|
|
||||||
{
|
|
||||||
return $this->containerName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$status = getContainerStatus(
|
|
||||||
server: $this->database->destination->server,
|
|
||||||
container_id: $this->containerName,
|
|
||||||
throwError: false
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($this->database->status === 'running' && $status !== 'running') {
|
|
||||||
if (data_get($this->database, 'environment.project.team')) {
|
|
||||||
// $this->database->environment->project->team->notify(new StatusChanged($this->database));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($this->database->status !== $status) {
|
|
||||||
$this->database->status = $status;
|
|
||||||
$this->database->save();
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
send_internal_notification('DatabaseContainerStatusJob failed with: ' . $e->getMessage());
|
|
||||||
ray($e->getMessage());
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,13 +5,14 @@ namespace App\Jobs;
|
|||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
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\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class DockerCleanupJob implements ShouldQueue
|
class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ namespace App\Jobs;
|
|||||||
|
|
||||||
use App\Actions\Server\UpdateCoolify;
|
use App\Actions\Server\UpdateCoolify;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class InstanceAutoUpdateJob implements ShouldQueue, ShouldBeUnique
|
class InstanceAutoUpdateJob implements ShouldQueue, ShouldBeUnique, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use App\Actions\Proxy\StartProxy;
|
|
||||||
use App\Enums\ProxyStatus;
|
|
||||||
use App\Enums\ProxyTypes;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class ProxyContainerStatusJob implements ShouldQueue, ShouldBeUnique
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
public Server $server;
|
|
||||||
public $tries = 1;
|
|
||||||
public $timeout = 120;
|
|
||||||
|
|
||||||
public function __construct(Server $server)
|
|
||||||
{
|
|
||||||
$this->server = $server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function middleware(): array
|
|
||||||
{
|
|
||||||
return [new WithoutOverlapping($this->server->uuid)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function uniqueId(): string
|
|
||||||
{
|
|
||||||
ray($this->server->uuid);
|
|
||||||
return $this->server->uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$proxyType = data_get($this->server, 'proxy.type');
|
|
||||||
if ($proxyType === ProxyTypes::NONE->value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (is_null($proxyType)) {
|
|
||||||
if ($this->server->isProxyShouldRun()) {
|
|
||||||
$this->server->proxy->type = ProxyTypes::TRAEFIK_V2->value;
|
|
||||||
$this->server->proxy->status = ProxyStatus::EXITED->value;
|
|
||||||
$this->server->save();
|
|
||||||
resolve(StartProxy::class)($this->server);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$container = getContainerStatus(server: $this->server, all_data: true, container_id: 'coolify-proxy', throwError: false);
|
|
||||||
$containerStatus = data_get($container, 'State.Status');
|
|
||||||
$databaseContainerStatus = data_get($this->server, 'proxy.status', 'exited');
|
|
||||||
|
|
||||||
|
|
||||||
if ($proxyType !== ProxyTypes::NONE->value) {
|
|
||||||
if ($containerStatus === 'running') {
|
|
||||||
$this->server->proxy->status = $containerStatus;
|
|
||||||
$this->server->save();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((is_null($containerStatus) ||$containerStatus !== 'running' || $databaseContainerStatus !== 'running' || ($containerStatus && $databaseContainerStatus !== $containerStatus)) && $this->server->isProxyShouldRun()) {
|
|
||||||
$this->server->proxy->status = $containerStatus;
|
|
||||||
$this->server->save();
|
|
||||||
resolve(StartProxy::class)($this->server);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
if ($e->getCode() === 1) {
|
|
||||||
$this->server->proxy->status = 'exited';
|
|
||||||
$this->server->save();
|
|
||||||
}
|
|
||||||
send_internal_notification('ProxyContainerStatusJob failed with: ' . $e->getMessage());
|
|
||||||
ray($e->getMessage());
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ namespace App\Jobs;
|
|||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\Waitlist;
|
use App\Models\Waitlist;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Mail\Message;
|
use Illuminate\Mail\Message;
|
||||||
@@ -13,7 +14,7 @@ use Illuminate\Queue\InteractsWithQueue;
|
|||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Facades\Mail;
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
class SendConfirmationForWaitlistJob implements ShouldQueue
|
class SendConfirmationForWaitlistJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
class SendMessageToDiscordJob implements ShouldQueue
|
class SendMessageToDiscordJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,15 @@
|
|||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class SendMessageToTelegramJob implements ShouldQueue
|
class SendMessageToTelegramJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
use Str;
|
|
||||||
|
|
||||||
class ServerDetailsCheckJob implements ShouldQueue, ShouldBeUnique
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
public $tries = 1;
|
|
||||||
public $timeout = 120;
|
|
||||||
|
|
||||||
public function __construct(public Server $server)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function middleware(): array
|
|
||||||
{
|
|
||||||
return [new WithoutOverlapping($this->server->uuid)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function uniqueId(): string
|
|
||||||
{
|
|
||||||
return $this->server->uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
ray()->clearAll();
|
|
||||||
$containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server);
|
|
||||||
$containers = format_docker_command_output_to_json($containers);
|
|
||||||
$applications = $this->server->applications();
|
|
||||||
// ray($applications);
|
|
||||||
// ray(format_docker_command_output_to_json($containers));
|
|
||||||
foreach ($applications as $application) {
|
|
||||||
$uuid = data_get($application, 'uuid');
|
|
||||||
$foundContainer = $containers->filter(function ($value, $key) use ($uuid) {
|
|
||||||
$image = data_get($value, 'Config.Image');
|
|
||||||
return Str::startsWith($image, $uuid);
|
|
||||||
})->first();
|
|
||||||
|
|
||||||
if ($foundContainer) {
|
|
||||||
$containerStatus = data_get($foundContainer, 'State.Status');
|
|
||||||
$databaseStatus = data_get($application, 'status');
|
|
||||||
ray($containerStatus, $databaseStatus);
|
|
||||||
if ($containerStatus !== $databaseStatus) {
|
|
||||||
// $application->update(['status' => $containerStatus]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// foreach ($containers as $container) {
|
|
||||||
// $labels = format_docker_labels_to_json(data_get($container,'Config.Labels'));
|
|
||||||
// $foundLabel = $labels->filter(fn ($value, $key) => Str::startsWith($key, 'coolify.applicationId'));
|
|
||||||
// if ($foundLabel->count() > 0) {
|
|
||||||
// $appFound = $applications->where('id', $foundLabel['coolify.applicationId'])->first();
|
|
||||||
// if ($appFound) {
|
|
||||||
// $containerStatus = data_get($container, 'State.Status');
|
|
||||||
// $databaseStatus = data_get($appFound, 'status');
|
|
||||||
// ray($containerStatus, $databaseStatus);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// send_internal_notification('ServerDetailsCheckJob failed with: ' . $e->getMessage());
|
|
||||||
ray($e->getMessage());
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,13 +4,14 @@ namespace App\Jobs;
|
|||||||
|
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class SubscriptionInvoiceFailedJob implements ShouldQueue
|
class SubscriptionInvoiceFailedJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ namespace App\Jobs;
|
|||||||
|
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class SubscriptionTrialEndedJob implements ShouldQueue
|
class SubscriptionTrialEndedJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ namespace App\Jobs;
|
|||||||
|
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class SubscriptionTrialEndsSoonJob implements ShouldQueue
|
class SubscriptionTrialEndsSoonJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,14 @@ class Server extends BaseModel
|
|||||||
})->flatten();
|
})->flatten();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function previews() {
|
||||||
|
return $this->destinations()->map(function ($standaloneDocker) {
|
||||||
|
return $standaloneDocker->applications->map(function ($application) {
|
||||||
|
return $application->previews;
|
||||||
|
})->flatten();
|
||||||
|
})->flatten();
|
||||||
|
}
|
||||||
|
|
||||||
public function destinations()
|
public function destinations()
|
||||||
{
|
{
|
||||||
$standalone_docker = $this->hasMany(StandaloneDocker::class)->get();
|
$standalone_docker = $this->hasMany(StandaloneDocker::class)->get();
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ class Team extends Model implements SendsDiscord, SendsEmail
|
|||||||
'resend_api_key' => 'encrypted',
|
'resend_api_key' => 'encrypted',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected static function booted()
|
||||||
|
{
|
||||||
|
// static::saved(function () {
|
||||||
|
// refreshSession();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
public function routeNotificationForDiscord()
|
public function routeNotificationForDiscord()
|
||||||
{
|
{
|
||||||
return data_get($this, 'discord_webhook_url', null);
|
return data_get($this, 'discord_webhook_url', null);
|
||||||
|
|||||||
@@ -19,4 +19,13 @@ class TeamInvitation extends Model
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(Team::class);
|
return $this->belongsTo(Team::class);
|
||||||
}
|
}
|
||||||
|
public function isValid() {
|
||||||
|
$createdAt = $this->created_at;
|
||||||
|
$diff = $createdAt->diffInMinutes(now());
|
||||||
|
if ($diff <= config('constants.invitation.link.expiration')) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$this->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Notifications\Channels\SendsEmail;
|
use App\Notifications\Channels\SendsEmail;
|
||||||
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
|
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
|
||||||
use Cache;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Laravel\Fortify\TwoFactorAuthenticatable;
|
use Laravel\Fortify\TwoFactorAuthenticatable;
|
||||||
use Laravel\Sanctum\HasApiTokens;
|
use Laravel\Sanctum\HasApiTokens;
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ class User extends Authenticatable implements SendsEmail
|
|||||||
|
|
||||||
public function isAdmin()
|
public function isAdmin()
|
||||||
{
|
{
|
||||||
return $this->pivot->role === 'admin' || $this->pivot->role === 'owner';
|
return data_get($this->pivot,'role') === 'admin' || data_get($this->pivot,'role') === 'owner';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isAdminFromSession()
|
public function isAdminFromSession()
|
||||||
@@ -78,7 +78,8 @@ class User extends Authenticatable implements SendsEmail
|
|||||||
if ($is_part_of_root_team && $is_admin_of_root_team) {
|
if ($is_part_of_root_team && $is_admin_of_root_team) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$role = $teams->where('id', auth()->user()->id)->first()->pivot->role;
|
$team = $teams->where('id', session('currentTeam')->id)->first();
|
||||||
|
$role = data_get($team,'pivot.role');
|
||||||
return $role === 'admin' || $role === 'owner';
|
return $role === 'admin' || $role === 'owner';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ namespace App\Notifications\Application;
|
|||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Notifications\Channels\DiscordChannel;
|
|
||||||
use App\Notifications\Channels\EmailChannel;
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
@@ -18,13 +16,14 @@ class DeploymentFailed extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public $tries = 5;
|
public $tries = 5;
|
||||||
public Application $application;
|
public Application $application;
|
||||||
public string $deployment_uuid;
|
|
||||||
public ?ApplicationPreview $preview = null;
|
public ?ApplicationPreview $preview = null;
|
||||||
|
|
||||||
|
public string $deployment_uuid;
|
||||||
public string $application_name;
|
public string $application_name;
|
||||||
public ?string $deployment_url = null;
|
|
||||||
public string $project_uuid;
|
public string $project_uuid;
|
||||||
public string $environment_name;
|
public string $environment_name;
|
||||||
|
|
||||||
|
public ?string $deployment_url = null;
|
||||||
public ?string $fqdn = null;
|
public ?string $fqdn = null;
|
||||||
|
|
||||||
public function __construct(Application $application, string $deployment_uuid, ?ApplicationPreview $preview = null)
|
public function __construct(Application $application, string $deployment_uuid, ?ApplicationPreview $preview = null)
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ namespace App\Notifications\Application;
|
|||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Notifications\Channels\DiscordChannel;
|
|
||||||
use App\Notifications\Channels\EmailChannel;
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
@@ -18,14 +16,15 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public $tries = 5;
|
public $tries = 5;
|
||||||
public Application $application;
|
public Application $application;
|
||||||
public string $deployment_uuid;
|
|
||||||
public ApplicationPreview|null $preview = null;
|
public ApplicationPreview|null $preview = null;
|
||||||
|
|
||||||
|
public string $deployment_uuid;
|
||||||
public string $application_name;
|
public string $application_name;
|
||||||
public string|null $deployment_url = null;
|
|
||||||
public string $project_uuid;
|
public string $project_uuid;
|
||||||
public string $environment_name;
|
public string $environment_name;
|
||||||
public string|null $fqdn;
|
|
||||||
|
public ?string $deployment_url = null;
|
||||||
|
public ?string $fqdn;
|
||||||
|
|
||||||
public function __construct(Application $application, string $deployment_uuid, ApplicationPreview|null $preview = null)
|
public function __construct(Application $application, string $deployment_uuid, ApplicationPreview|null $preview = null)
|
||||||
{
|
{
|
||||||
@@ -53,7 +52,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
|||||||
$pull_request_id = data_get($this->preview, 'pull_request_id', 0);
|
$pull_request_id = data_get($this->preview, 'pull_request_id', 0);
|
||||||
$fqdn = $this->fqdn;
|
$fqdn = $this->fqdn;
|
||||||
if ($pull_request_id === 0) {
|
if ($pull_request_id === 0) {
|
||||||
$mail->subject("✅New version is deployed of {$this->application_name}");
|
$mail->subject("✅ New version is deployed of {$this->application_name}");
|
||||||
} else {
|
} else {
|
||||||
$fqdn = $this->preview->fqdn;
|
$fqdn = $this->preview->fqdn;
|
||||||
$mail->subject("✅ Pull request #{$pull_request_id} of {$this->application_name} deployed successfully");
|
$mail->subject("✅ Pull request #{$pull_request_id} of {$this->application_name} deployed successfully");
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Notifications\Application;
|
namespace App\Notifications\Application;
|
||||||
|
|
||||||
use App\Notifications\Channels\DiscordChannel;
|
use App\Models\Application;
|
||||||
use App\Notifications\Channels\EmailChannel;
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
@@ -15,13 +14,14 @@ class StatusChanged extends Notification implements ShouldQueue
|
|||||||
use Queueable;
|
use Queueable;
|
||||||
|
|
||||||
public $tries = 5;
|
public $tries = 5;
|
||||||
public $application;
|
|
||||||
|
|
||||||
|
public Application $application;
|
||||||
public string $application_name;
|
public string $application_name;
|
||||||
public string|null $application_url = null;
|
|
||||||
public string $project_uuid;
|
public string $project_uuid;
|
||||||
public string $environment_name;
|
public string $environment_name;
|
||||||
public string|null $fqdn;
|
|
||||||
|
public ?string $application_url = null;
|
||||||
|
public ?string $fqdn;
|
||||||
|
|
||||||
public function __construct($application)
|
public function __construct($application)
|
||||||
{
|
{
|
||||||
|
|||||||
62
app/Notifications/Container/ContainerRestarted.php
Normal file
62
app/Notifications/Container/ContainerRestarted.php
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Container;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class ContainerRestarted extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public $tries = 5;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(public string $name, public Server $server, public ?string $url = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return setNotificationChannels($notifiable, 'status_changes');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail(): MailMessage
|
||||||
|
{
|
||||||
|
$mail = new MailMessage();
|
||||||
|
$mail->subject("✅ Container ({$this->name}) has been restarted automatically on {$this->server->name}");
|
||||||
|
$mail->view('emails.container-restarted', [
|
||||||
|
'containerName' => $this->name,
|
||||||
|
'serverName' => $this->server->name,
|
||||||
|
'url' => $this->url ,
|
||||||
|
]);
|
||||||
|
return $mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDiscord(): string
|
||||||
|
{
|
||||||
|
$message = "✅ Container ({$this->name}) has been restarted automatically on {$this->server->name}";
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
public function toTelegram(): array
|
||||||
|
{
|
||||||
|
$message = "✅ Container ({$this->name}) has been restarted automatically on {$this->server->name}";
|
||||||
|
$payload = [
|
||||||
|
"message" => $message,
|
||||||
|
];
|
||||||
|
if ($this->url) {
|
||||||
|
$payload['buttons'] = [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"text" => "Check Proxy in Coolify",
|
||||||
|
"url" => $this->url
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
};
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
app/Notifications/Container/ContainerStopped.php
Normal file
61
app/Notifications/Container/ContainerStopped.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Container;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class ContainerStopped extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public $tries = 1;
|
||||||
|
|
||||||
|
public function __construct(public string $name, public Server $server, public ?string $url = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return setNotificationChannels($notifiable, 'status_changes');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail(): MailMessage
|
||||||
|
{
|
||||||
|
$mail = new MailMessage();
|
||||||
|
$mail->subject("⛔ Container {$this->name} has been stopped on {$this->server->name}");
|
||||||
|
$mail->view('emails.container-stopped', [
|
||||||
|
'containerName' => $this->name,
|
||||||
|
'serverName' => $this->server->name,
|
||||||
|
'url' => $this->url,
|
||||||
|
]);
|
||||||
|
return $mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDiscord(): string
|
||||||
|
{
|
||||||
|
$message = "⛔ Container {$this->name} has been stopped on {$this->server->name}";
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
public function toTelegram(): array
|
||||||
|
{
|
||||||
|
$message = "⛔ Container ($this->name} has been stopped on {$this->server->name}";
|
||||||
|
$payload = [
|
||||||
|
"message" => $message,
|
||||||
|
];
|
||||||
|
if ($this->url) {
|
||||||
|
$payload['buttons'] = [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"text" => "Open Application in Coolify",
|
||||||
|
"url" => $this->url
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Notifications\Server;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Notifications\Channels\DiscordChannel;
|
|
||||||
use App\Notifications\Channels\EmailChannel;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
|
||||||
use Illuminate\Notifications\Notification;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class NotReachable extends Notification implements ShouldQueue
|
|
||||||
{
|
|
||||||
use Queueable;
|
|
||||||
|
|
||||||
public $tries = 5;
|
|
||||||
public function __construct(public Server $server)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function via(object $notifiable): array
|
|
||||||
{
|
|
||||||
return setNotificationChannels($notifiable, 'status_changes');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toMail(): MailMessage
|
|
||||||
{
|
|
||||||
$mail = new MailMessage();
|
|
||||||
// $fqdn = $this->fqdn;
|
|
||||||
$mail->subject("⛔ Server '{$this->server->name}' is unreachable");
|
|
||||||
// $mail->view('emails.application-status-changes', [
|
|
||||||
// 'name' => $this->application_name,
|
|
||||||
// 'fqdn' => $fqdn,
|
|
||||||
// 'application_url' => $this->application_url,
|
|
||||||
// ]);
|
|
||||||
return $mail;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toDiscord(): string
|
|
||||||
{
|
|
||||||
$message = '⛔ Server \'' . $this->server->name . '\' is unreachable (could be a temporary issue). If you receive this more than twice in a row, please check your server.';
|
|
||||||
return $message;
|
|
||||||
}
|
|
||||||
public function toTelegram(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"message" => '⛔ Server \'' . $this->server->name . '\' is unreachable (could be a temporary issue). If you receive this more than twice in a row, please check your server.'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
47
app/Notifications/Server/Unreachable.php
Normal file
47
app/Notifications/Server/Unreachable.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class Unreachable extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public $tries = 1;
|
||||||
|
public function __construct(public Server $server)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return setNotificationChannels($notifiable, 'status_changes');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail(): MailMessage
|
||||||
|
{
|
||||||
|
$mail = new MailMessage();
|
||||||
|
$mail->subject("⛔ Server ({$this->server->name}) is unreachable after trying to connect to it 5 times");
|
||||||
|
$mail->view('emails.server-lost-connection', [
|
||||||
|
'name' => $this->server->name,
|
||||||
|
]);
|
||||||
|
return $mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDiscord(): string
|
||||||
|
{
|
||||||
|
$message = "⛔ Server '{$this->server->name}' is unreachable after trying to connect to it 5 times. All automations & integrations are turned off! Please check your server! IMPORTANT: You have to validate your server again after you fix the issue.";
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
public function toTelegram(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"message" => "⛔ Server '{$this->server->name}' is unreachable after trying to connect to it 5 times. All automations & integrations are turned off! Please check your server! IMPORTANT: You have to validate your server again after you fix the issue."
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ use Illuminate\Support\Str;
|
|||||||
|
|
||||||
trait ExecuteRemoteCommand
|
trait ExecuteRemoteCommand
|
||||||
{
|
{
|
||||||
public string|null $save = null;
|
public ?string $save = null;
|
||||||
|
|
||||||
public function execute_remote_command(...$commands)
|
public function execute_remote_command(...$commands)
|
||||||
{
|
{
|
||||||
@@ -25,12 +25,8 @@ trait ExecuteRemoteCommand
|
|||||||
throw new \RuntimeException('Server is not set or is not an instance of Server model');
|
throw new \RuntimeException('Server is not set or is not an instance of Server model');
|
||||||
}
|
}
|
||||||
|
|
||||||
$ip = data_get($this->server, 'ip');
|
|
||||||
$user = data_get($this->server, 'user');
|
|
||||||
$port = data_get($this->server, 'port');
|
|
||||||
$private_key_location = get_private_key_for_server($this->server);
|
|
||||||
|
|
||||||
$commandsText->each(function ($single_command) use ($private_key_location, $ip, $user, $port) {
|
$commandsText->each(function ($single_command) {
|
||||||
$command = data_get($single_command, 'command') ?? $single_command[0] ?? null;
|
$command = data_get($single_command, 'command') ?? $single_command[0] ?? null;
|
||||||
if ($command === null) {
|
if ($command === null) {
|
||||||
throw new \RuntimeException('Command is not set');
|
throw new \RuntimeException('Command is not set');
|
||||||
@@ -39,8 +35,8 @@ trait ExecuteRemoteCommand
|
|||||||
$ignore_errors = data_get($single_command, 'ignore_errors', false);
|
$ignore_errors = data_get($single_command, 'ignore_errors', false);
|
||||||
$this->save = data_get($single_command, 'save');
|
$this->save = data_get($single_command, 'save');
|
||||||
|
|
||||||
$remote_command = generate_ssh_command($private_key_location, $ip, $user, $port, $command);
|
$remote_command = generateSshCommand($this->server, $command);
|
||||||
$process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden) {
|
$process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden) {
|
||||||
$output = Str::of($output)->trim();
|
$output = Str::of($output)->trim();
|
||||||
$new_log_entry = [
|
$new_log_entry = [
|
||||||
'command' => $command,
|
'command' => $command,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user