fix: server validation process
This commit is contained in:
parent
5b584a6c6d
commit
dcaa7a6ad7
@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Actions\Server;
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
|
|
||||||
class InstallDocker
|
class InstallDocker
|
||||||
{
|
{
|
||||||
public function __invoke(Server $server)
|
use AsAction;
|
||||||
|
public function handle(Server $server)
|
||||||
{
|
{
|
||||||
$dockerVersion = '24.0';
|
$dockerVersion = '24.0';
|
||||||
$config = base64_encode('{
|
$config = base64_encode('{
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Models\PrivateKey;
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
|
||||||
|
|
||||||
class ServerController extends Controller
|
|
||||||
{
|
|
||||||
use AuthorizesRequests, ValidatesRequests;
|
|
||||||
|
|
||||||
public function new_server()
|
|
||||||
{
|
|
||||||
$privateKeys = PrivateKey::ownedByCurrentTeam()->get();
|
|
||||||
if (!isCloud()) {
|
|
||||||
return view('server.create', [
|
|
||||||
'limit_reached' => false,
|
|
||||||
'private_keys' => $privateKeys,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
$team = currentTeam();
|
|
||||||
$servers = $team->servers->count();
|
|
||||||
['serverLimit' => $serverLimit] = $team->limits;
|
|
||||||
$limit_reached = $servers >= $serverLimit;
|
|
||||||
|
|
||||||
return view('server.create', [
|
|
||||||
'limit_reached' => $limit_reached,
|
|
||||||
'private_keys' => $privateKeys,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
@ -220,7 +220,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
public function installDocker()
|
public function installDocker()
|
||||||
{
|
{
|
||||||
$this->dockerInstallationStarted = true;
|
$this->dockerInstallationStarted = true;
|
||||||
$activity = resolve(InstallDocker::class)($this->createdServer);
|
$activity = InstallDocker::run($this->createdServer);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
}
|
}
|
||||||
public function dockerInstalledOrSkipped()
|
public function dockerInstalledOrSkipped()
|
||||||
|
29
app/Http/Livewire/Server/Create.php
Normal file
29
app/Http/Livewire/Server/Create.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server;
|
||||||
|
|
||||||
|
use App\Models\PrivateKey;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Create extends Component
|
||||||
|
{
|
||||||
|
public $private_keys = [];
|
||||||
|
public bool $limit_reached = false;
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->private_keys = PrivateKey::ownedByCurrentTeam()->get();
|
||||||
|
if (!isCloud()) {
|
||||||
|
$this->limit_reached = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$team = currentTeam();
|
||||||
|
$servers = $team->servers->count();
|
||||||
|
['serverLimit' => $serverLimit] = $team->limits;
|
||||||
|
|
||||||
|
$this->limit_reached = $servers >= $serverLimit;
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.create');
|
||||||
|
}
|
||||||
|
}
|
28
app/Http/Livewire/Server/Destination/Show.php
Normal file
28
app/Http/Livewire/Server/Destination/Show.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server\Destination;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Show extends Component
|
||||||
|
{
|
||||||
|
public ?Server $server = null;
|
||||||
|
public $parameters = [];
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
try {
|
||||||
|
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($this->server)) {
|
||||||
|
return redirect()->route('server.all');
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.destination.show');
|
||||||
|
}
|
||||||
|
}
|
@ -11,11 +11,12 @@ class Form extends Component
|
|||||||
{
|
{
|
||||||
use AuthorizesRequests;
|
use AuthorizesRequests;
|
||||||
public Server $server;
|
public Server $server;
|
||||||
public $uptime;
|
public bool $isValidConnection = false;
|
||||||
public $dockerVersion;
|
public bool $isValidDocker = false;
|
||||||
public string|null $wildcard_domain = null;
|
public ?string $wildcard_domain = null;
|
||||||
public int $cleanup_after_percentage;
|
public int $cleanup_after_percentage;
|
||||||
public bool $dockerInstallationStarted = false;
|
public bool $dockerInstallationStarted = false;
|
||||||
|
protected $listeners = ['serverRefresh'];
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'server.name' => 'required|min:6',
|
'server.name' => 'required|min:6',
|
||||||
@ -44,37 +45,49 @@ class Form extends Component
|
|||||||
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
||||||
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
|
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
|
||||||
}
|
}
|
||||||
public function instantSave() {
|
public function serverRefresh() {
|
||||||
|
$this->validateServer();
|
||||||
|
}
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
refresh_server_connection($this->server->privateKey);
|
refresh_server_connection($this->server->privateKey);
|
||||||
$this->validateServer();
|
$this->validateServer();
|
||||||
$this->server->settings->save();
|
$this->server->settings->save();
|
||||||
}
|
}
|
||||||
public function installDocker()
|
public function installDocker()
|
||||||
{
|
{
|
||||||
|
$this->emit('installDocker');
|
||||||
$this->dockerInstallationStarted = true;
|
$this->dockerInstallationStarted = true;
|
||||||
$activity = resolve(InstallDocker::class)($this->server);
|
$activity = InstallDocker::run($this->server);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateServer()
|
public function validateServer($install = true)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
|
$uptime = $this->server->validateConnection();
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
$this->uptime = $uptime;
|
$install && $this->emit('success', 'Server is reachable.');
|
||||||
$this->emit('success', 'Server is reachable.');
|
|
||||||
} else {
|
} else {
|
||||||
$this->emit('error', 'Server is not reachable.');
|
$install &&$this->emit('error', 'Server is not reachable. Please check your connection and private key configuration.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($dockerVersion) {
|
$dockerInstalled = $this->server->validateDockerEngine();
|
||||||
$this->dockerVersion = $dockerVersion;
|
if ($dockerInstalled) {
|
||||||
$this->emit('success', 'Docker Engine 23+ is installed!');
|
$install && $this->emit('success', 'Docker Engine is installed.<br> Checking version.');
|
||||||
} else {
|
} else {
|
||||||
$this->emit('error', 'No Docker Engine or older than 23 version installed.');
|
$install && $this->installDocker();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$dockerVersion = $this->server->validateDockerEngineVersion();
|
||||||
|
if ($dockerVersion) {
|
||||||
|
$install && $this->emit('success', 'Docker Engine version is 23+.');
|
||||||
|
} else {
|
||||||
|
$install && $this->installDocker();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this, customErrorMessage: "Server is not reachable: ");
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->emit('proxyStatusUpdated');
|
$this->emit('proxyStatusUpdated');
|
||||||
}
|
}
|
||||||
|
31
app/Http/Livewire/Server/PrivateKey/Show.php
Normal file
31
app/Http/Livewire/Server/PrivateKey/Show.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server\PrivateKey;
|
||||||
|
|
||||||
|
use App\Models\PrivateKey;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Show extends Component
|
||||||
|
{
|
||||||
|
public ?Server $server = null;
|
||||||
|
public $privateKeys = [];
|
||||||
|
public $parameters = [];
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
try {
|
||||||
|
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($this->server)) {
|
||||||
|
return redirect()->route('server.all');
|
||||||
|
}
|
||||||
|
$this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.private-key.show');
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ class Deploy extends Component
|
|||||||
public Server $server;
|
public Server $server;
|
||||||
public bool $traefikDashboardAvailable = false;
|
public bool $traefikDashboardAvailable = false;
|
||||||
public ?string $currentRoute = null;
|
public ?string $currentRoute = null;
|
||||||
protected $listeners = ['proxyStatusUpdated', 'traefikDashboardAvailable'];
|
protected $listeners = ['proxyStatusUpdated', 'traefikDashboardAvailable', 'serverRefresh' => 'proxyStatusUpdated'];
|
||||||
|
|
||||||
public function mount() {
|
public function mount() {
|
||||||
$this->currentRoute = request()->route()->getName();
|
$this->currentRoute = request()->route()->getName();
|
||||||
|
28
app/Http/Livewire/Server/Proxy/Show.php
Normal file
28
app/Http/Livewire/Server/Proxy/Show.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server\Proxy;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Show extends Component
|
||||||
|
{
|
||||||
|
public ?Server $server = null;
|
||||||
|
public $parameters = [];
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
try {
|
||||||
|
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($this->server)) {
|
||||||
|
return redirect()->route('server.all');
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.proxy.show');
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,9 @@ class Status extends Component
|
|||||||
}
|
}
|
||||||
public function getProxyStatusWithNoti()
|
public function getProxyStatusWithNoti()
|
||||||
{
|
{
|
||||||
$this->emit('success', 'Refreshed proxy status.');
|
if ($this->server->isFunctional()) {
|
||||||
$this->getProxyStatus();
|
$this->emit('success', 'Refreshed proxy status.');
|
||||||
|
$this->getProxyStatus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,10 @@ class Show extends Component
|
|||||||
{
|
{
|
||||||
use AuthorizesRequests;
|
use AuthorizesRequests;
|
||||||
public ?Server $server = null;
|
public ?Server $server = null;
|
||||||
|
public $parameters = [];
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
try {
|
try {
|
||||||
$this->server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
$this->server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
if (is_null($this->server)) {
|
if (is_null($this->server)) {
|
||||||
@ -21,6 +23,10 @@ class Show extends Component
|
|||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
$this->emit('serverRefresh');
|
||||||
|
}
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.server.show');
|
return view('livewire.server.show');
|
||||||
|
@ -32,36 +32,34 @@ class ShowPrivateKey extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkConnection()
|
public function checkConnection($install = false)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
|
$uptime = $this->server->validateConnection();
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
$this->server->settings->update([
|
$install && $this->emit('success', 'Server is reachable.');
|
||||||
'is_reachable' => true
|
|
||||||
]);
|
|
||||||
$this->emit('success', 'Server is reachable with this private key.');
|
|
||||||
} else {
|
} else {
|
||||||
$this->server->settings->update([
|
$install && $this->emit('error', 'Server is not reachable. Please check your connection and private key configuration.');
|
||||||
'is_reachable' => false,
|
|
||||||
'is_usable' => false
|
|
||||||
]);
|
|
||||||
$this->emit('error', 'Server is not reachable with this private key.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($dockerVersion) {
|
$dockerInstalled = $this->server->validateDockerEngine();
|
||||||
$this->server->settings->update([
|
if ($dockerInstalled) {
|
||||||
'is_usable' => true
|
$install && $this->emit('success', 'Docker Engine is installed.<br> Checking version.');
|
||||||
]);
|
|
||||||
$this->emit('success', 'Server is usable for Coolify.');
|
|
||||||
} else {
|
} else {
|
||||||
$this->server->settings->update([
|
$install && $this->installDocker();
|
||||||
'is_usable' => false
|
return;
|
||||||
]);
|
}
|
||||||
$this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.');
|
$dockerVersion = $this->server->validateDockerEngineVersion();
|
||||||
|
if ($dockerVersion) {
|
||||||
|
$install && $this->emit('success', 'Docker Engine version is 23+.');
|
||||||
|
} else {
|
||||||
|
$install && $this->installDocker();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
|
} finally {
|
||||||
|
$this->emit('proxyStatusUpdated');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,15 +41,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
{
|
{
|
||||||
return $this->server->uuid;
|
return $this->server->uuid;
|
||||||
}
|
}
|
||||||
|
public function handle()
|
||||||
private function checkServerConnection()
|
|
||||||
{
|
|
||||||
$uptime = instant_remote_process(['uptime'], $this->server, false);
|
|
||||||
if (!is_null($uptime)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function handle(): void
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
ray("checking server status for {$this->server->name}");
|
ray("checking server status for {$this->server->name}");
|
||||||
@ -57,9 +49,11 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$serverUptimeCheckNumber = 0;
|
$serverUptimeCheckNumber = 0;
|
||||||
$serverUptimeCheckNumberMax = 3;
|
$serverUptimeCheckNumberMax = 3;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
ray('checking # ' . $serverUptimeCheckNumber);
|
||||||
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
|
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
|
||||||
send_internal_notification('Server unreachable: ' . $this->server->name);
|
send_internal_notification('Server unreachable: ' . $this->server->name);
|
||||||
if ($this->server->unreachable_email_sent === false) {
|
if ($this->server->unreachable_email_sent === false) {
|
||||||
|
ray('Server unreachable, sending notification...');
|
||||||
$this->server->team->notify(new Unreachable($this->server));
|
$this->server->team->notify(new Unreachable($this->server));
|
||||||
}
|
}
|
||||||
$this->server->settings()->update([
|
$this->server->settings()->update([
|
||||||
@ -68,7 +62,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->server->update(['unreachable_email_sent' => true]);
|
$this->server->update(['unreachable_email_sent' => true]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$result = $this->checkServerConnection();
|
$result = $this->server->validateConnection();
|
||||||
if ($result) {
|
if ($result) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -76,6 +70,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
sleep(5);
|
sleep(5);
|
||||||
}
|
}
|
||||||
if (data_get($this->server, 'unreachable_email_sent') === true) {
|
if (data_get($this->server, 'unreachable_email_sent') === true) {
|
||||||
|
ray('Server is reachable again, sending notification...');
|
||||||
$this->server->team->notify(new Revived($this->server));
|
$this->server->team->notify(new Revived($this->server));
|
||||||
$this->server->update(['unreachable_email_sent' => false]);
|
$this->server->update(['unreachable_email_sent' => false]);
|
||||||
}
|
}
|
||||||
@ -88,7 +83,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
'is_usable' => true
|
'is_usable' => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
$this->server->validateDockerEngine(true);
|
||||||
$containers = instant_remote_process(["docker container ls -q"], $this->server);
|
$containers = instant_remote_process(["docker container ls -q"], $this->server);
|
||||||
if (!$containers) {
|
if (!$containers) {
|
||||||
return;
|
return;
|
||||||
@ -288,7 +283,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
send_internal_notification('ContainerStatusJob failed with: ' . $e->getMessage());
|
send_internal_notification('ContainerStatusJob failed with: ' . $e->getMessage());
|
||||||
ray($e->getMessage());
|
ray($e->getMessage());
|
||||||
throw $e;
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,11 @@ class Server extends BaseModel
|
|||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::saved(function ($server) {
|
static::saving(function ($server) {
|
||||||
$server->ip = Str::of($server->ip)->trim();
|
$server->forceFill([
|
||||||
$server->user = Str::of($server->user)->trim();
|
'ip' => Str::of($server->ip)->trim(),
|
||||||
|
'user' => Str::of($server->user)->trim(),
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
static::created(function ($server) {
|
static::created(function ($server) {
|
||||||
@ -205,4 +207,48 @@ class Server extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->settings->is_reachable && $this->settings->is_usable;
|
return $this->settings->is_reachable && $this->settings->is_usable;
|
||||||
}
|
}
|
||||||
|
public function validateConnection()
|
||||||
|
{
|
||||||
|
$uptime = instant_remote_process(['uptime'], $this, false);
|
||||||
|
if (!$uptime) {
|
||||||
|
$this->settings->is_reachable = false;
|
||||||
|
$this->settings->save();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->settings->is_reachable = true;
|
||||||
|
$this->settings->save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public function validateDockerEngine($throwError = false)
|
||||||
|
{
|
||||||
|
$dockerBinary = instant_remote_process(["command -v docker"], $this, false);
|
||||||
|
if (is_null($dockerBinary)) {
|
||||||
|
$this->settings->is_usable = false;
|
||||||
|
$this->settings->save();
|
||||||
|
if ($throwError) {
|
||||||
|
throw new \Exception('Server is not usable.');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->settings->is_usable = true;
|
||||||
|
$this->settings->save();
|
||||||
|
$this->validateCoolifyNetwork();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public function validateDockerEngineVersion()
|
||||||
|
{
|
||||||
|
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this, false);
|
||||||
|
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
|
||||||
|
if (is_null($dockerVersion)) {
|
||||||
|
$this->settings->is_usable = false;
|
||||||
|
$this->settings->save();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->settings->is_usable = true;
|
||||||
|
$this->settings->save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public function validateCoolifyNetwork() {
|
||||||
|
return instant_remote_process(["docker network create coolify --attachable >/dev/null 2>&1 || true"], $this, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@ namespace App\Notifications\Server;
|
|||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use App\Notifications\Channels\DiscordChannel;
|
||||||
|
use App\Notifications\Channels\EmailChannel;
|
||||||
|
use App\Notifications\Channels\TelegramChannel;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
@ -22,7 +25,21 @@ class Revived extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function via(object $notifiable): array
|
public function via(object $notifiable): array
|
||||||
{
|
{
|
||||||
return setNotificationChannels($notifiable, 'status_changes');
|
$channels = [];
|
||||||
|
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||||
|
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||||
|
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||||
|
|
||||||
|
if ($isDiscordEnabled) {
|
||||||
|
$channels[] = DiscordChannel::class;
|
||||||
|
}
|
||||||
|
if ($isEmailEnabled ) {
|
||||||
|
$channels[] = EmailChannel::class;
|
||||||
|
}
|
||||||
|
if ($isTelegramEnabled) {
|
||||||
|
$channels[] = TelegramChannel::class;
|
||||||
|
}
|
||||||
|
return $channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
namespace App\Notifications\Server;
|
namespace App\Notifications\Server;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Notifications\Channels\DiscordChannel;
|
||||||
|
use App\Notifications\Channels\EmailChannel;
|
||||||
|
use App\Notifications\Channels\TelegramChannel;
|
||||||
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;
|
||||||
@ -20,7 +23,21 @@ class Unreachable extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function via(object $notifiable): array
|
public function via(object $notifiable): array
|
||||||
{
|
{
|
||||||
return setNotificationChannels($notifiable, 'status_changes');
|
$channels = [];
|
||||||
|
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||||
|
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||||
|
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||||
|
|
||||||
|
if ($isDiscordEnabled) {
|
||||||
|
$channels[] = DiscordChannel::class;
|
||||||
|
}
|
||||||
|
if ($isEmailEnabled ) {
|
||||||
|
$channels[] = EmailChannel::class;
|
||||||
|
}
|
||||||
|
if ($isTelegramEnabled) {
|
||||||
|
$channels[] = TelegramChannel::class;
|
||||||
|
}
|
||||||
|
return $channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
|
@ -56,7 +56,7 @@ a {
|
|||||||
@apply flex items-center p-2 transition-colors cursor-pointer min-h-16 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem];
|
@apply flex items-center p-2 transition-colors cursor-pointer min-h-16 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem];
|
||||||
}
|
}
|
||||||
.box-without-bg {
|
.box-without-bg {
|
||||||
@apply flex items-center p-2 transition-colors min-h-16 hover:text-white hover:no-underline min-w-[24rem];
|
@apply flex items-center p-2 transition-colors min-h-16 hover:text-white hover:no-underline min-w-[24rem];
|
||||||
}
|
}
|
||||||
|
|
||||||
.lds-heart {
|
.lds-heart {
|
||||||
|
@ -8,25 +8,25 @@
|
|||||||
<nav class="navbar-main">
|
<nav class="navbar-main">
|
||||||
<a class="{{ request()->routeIs('server.show') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.show') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.show', [
|
href="{{ route('server.show', [
|
||||||
'server_uuid' => Route::current()->parameters()['server_uuid'],
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
]) }}">
|
]) }}">
|
||||||
<button>General</button>
|
<button>General</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('server.private-key') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.private-key') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.private-key', [
|
href="{{ route('server.private-key', [
|
||||||
'server_uuid' => Route::current()->parameters()['server_uuid'],
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
]) }}">
|
]) }}">
|
||||||
<button>Private Key</button>
|
<button>Private Key</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('server.proxy') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.proxy') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.proxy', [
|
href="{{ route('server.proxy', [
|
||||||
'server_uuid' => Route::current()->parameters()['server_uuid'],
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
]) }}">
|
]) }}">
|
||||||
<button>Proxy</button>
|
<button>Proxy</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('server.destinations') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.destinations') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.destinations', [
|
href="{{ route('server.destinations', [
|
||||||
'server_uuid' => Route::current()->parameters()['server_uuid'],
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
]) }}">
|
]) }}">
|
||||||
<button>Destinations</button>
|
<button>Destinations</button>
|
||||||
</a>
|
</a>
|
||||||
|
@ -5,10 +5,6 @@ Container ({{ $containerName }}) has been restarted automatically on {{$serverNa
|
|||||||
@if ($containerName === 'coolify-proxy')
|
@if ($containerName === 'coolify-proxy')
|
||||||
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
|
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
|
||||||
|
|
||||||
Note: The proxy should not stop unexpectedly, so please check what is going on your server.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to Custom(None).
|
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to Custom(None).
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
9
resources/views/livewire/server/create.blade.php
Normal file
9
resources/views/livewire/server/create.blade.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<div>
|
||||||
|
@if ($private_keys->count() === 0)
|
||||||
|
<h1>Create Private Key</h1>
|
||||||
|
<div class="subtitle">You need to create a private key before you can create a server.</div>
|
||||||
|
<livewire:private-key.create from="server" />
|
||||||
|
@else
|
||||||
|
<livewire:server.new.by-ip :private_keys="$private_keys" :limit_reached="$limit_reached" />
|
||||||
|
@endif
|
||||||
|
</div>
|
@ -0,0 +1,4 @@
|
|||||||
|
<div>
|
||||||
|
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||||
|
<livewire:destination.show :server="$server" />
|
||||||
|
</div>
|
@ -1,4 +1,4 @@
|
|||||||
<div>
|
<div x-init="$wire.validateServer(false)">
|
||||||
<x-modal yesOrNo modalId="deleteServer" modalTitle="Delete Server">
|
<x-modal yesOrNo modalId="deleteServer" modalTitle="Delete Server">
|
||||||
<x-slot:modalBody>
|
<x-slot:modalBody>
|
||||||
<p>This server will be deleted. It is not reversible. <br>Please think again..</p>
|
<p>This server will be deleted. It is not reversible. <br>Please think again..</p>
|
||||||
@ -25,6 +25,11 @@
|
|||||||
@else
|
@else
|
||||||
Server is reachable and validated.
|
Server is reachable and validated.
|
||||||
@endif
|
@endif
|
||||||
|
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id !== 0)
|
||||||
|
<x-forms.button class="mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-100" wire:click.prevent='validateServer' isHighlighted>
|
||||||
|
Validate Server & Install Docker Engine
|
||||||
|
</x-forms.button>
|
||||||
|
@endif
|
||||||
<div class="flex flex-col gap-2 pt-4">
|
<div class="flex flex-col gap-2 pt-4">
|
||||||
<div class="flex flex-col w-full gap-2 lg:flex-row">
|
<div class="flex flex-col w-full gap-2 lg:flex-row">
|
||||||
<x-forms.input id="server.name" label="Name" required />
|
<x-forms.input id="server.name" label="Name" required />
|
||||||
@ -42,27 +47,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-64">
|
<div class="w-64">
|
||||||
<x-forms.checkbox instantSave helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
<x-forms.checkbox instantSave
|
||||||
|
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
||||||
id="server.settings.is_cloudflare_tunnel" label="Cloudflare Tunnel" />
|
id="server.settings.is_cloudflare_tunnel" label="Cloudflare Tunnel" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (!$server->settings->is_reachable)
|
|
||||||
<x-forms.button class="mt-8 mb-4 box" wire:click.prevent='validateServer'>
|
|
||||||
Validate Server
|
|
||||||
</x-forms.button>
|
|
||||||
@endif
|
|
||||||
@if ($server->settings->is_reachable && !$server->settings->is_usable && $server->id !== 0)
|
|
||||||
@if ($dockerInstallationStarted)
|
|
||||||
<x-forms.button class="mt-8 mb-4 box" wire:click.prevent='validateServer'>
|
|
||||||
Validate Server
|
|
||||||
</x-forms.button>
|
|
||||||
@else
|
|
||||||
<x-forms.button class="mt-8 mb-4 box" onclick="installDocker.showModal()"
|
|
||||||
wire:click.prevent='installDocker' isHighlighted>
|
|
||||||
Install Docker Engine 24.0
|
|
||||||
</x-forms.button>
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
@if ($server->isFunctional())
|
@if ($server->isFunctional())
|
||||||
<h3 class="py-4">Settings</h3>
|
<h3 class="py-4">Settings</h3>
|
||||||
<x-forms.input id="cleanup_after_percentage" label="Disk Cleanup threshold (%)" required
|
<x-forms.input id="cleanup_after_percentage" label="Disk Cleanup threshold (%)" required
|
||||||
@ -80,4 +70,11 @@
|
|||||||
Delete
|
Delete
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Livewire.on('installDocker', () => {
|
||||||
|
console.log('asd');
|
||||||
|
installDocker.showModal();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<x-layout>
|
<div>
|
||||||
<x-server.navbar :server="$server" />
|
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||||
<livewire:server.show-private-key :server="$server" :privateKeys="$privateKeys" />
|
<livewire:server.show-private-key :server="$server" :privateKeys="$privateKeys" />
|
||||||
</x-layout>
|
</div>
|
4
resources/views/livewire/server/proxy/show.blade.php
Normal file
4
resources/views/livewire/server/proxy/show.blade.php
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<div>
|
||||||
|
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||||
|
<livewire:server.proxy :server="$server" />
|
||||||
|
</div>
|
@ -1,7 +1,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<x-modal noSubmit modalId="installDocker">
|
<x-modal modalId="installDocker">
|
||||||
<x-slot:modalBody>
|
<x-slot:modalBody>
|
||||||
<livewire:activity-monitor header="Installation Logs" />
|
<livewire:activity-monitor header="Docker Installation Logs" />
|
||||||
</x-slot:modalBody>
|
</x-slot:modalBody>
|
||||||
<x-slot:modalSubmit>
|
<x-slot:modalSubmit>
|
||||||
<x-forms.button onclick="installDocker.close()" type="submit">
|
<x-forms.button onclick="installDocker.close()" type="submit">
|
||||||
@ -9,6 +9,6 @@
|
|||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</x-slot:modalSubmit>
|
</x-slot:modalSubmit>
|
||||||
</x-modal>
|
</x-modal>
|
||||||
<x-server.navbar :server="$server" />
|
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||||
<livewire:server.form :server="$server" />
|
<livewire:server.form :server="$server" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
<x-layout>
|
|
||||||
|
|
||||||
</x-layout>
|
|
@ -1,4 +0,0 @@
|
|||||||
<x-layout>
|
|
||||||
<x-server.navbar :server="$server" />
|
|
||||||
<livewire:destination.show :server="$server" />
|
|
||||||
</x-layout>
|
|
@ -1,4 +0,0 @@
|
|||||||
<x-layout>
|
|
||||||
<x-server.navbar :server="$server" />
|
|
||||||
<livewire:server.proxy :server="$server" />
|
|
||||||
</x-layout>
|
|
@ -1,4 +0,0 @@
|
|||||||
<x-layout>
|
|
||||||
<x-server.navbar :server="$server" />
|
|
||||||
<livewire:server.form :server="$server" />
|
|
||||||
</x-layout>
|
|
@ -13,6 +13,10 @@ use App\Http\Livewire\Dev\Compose as Compose;
|
|||||||
use App\Http\Livewire\Dashboard;
|
use App\Http\Livewire\Dashboard;
|
||||||
use App\Http\Livewire\Project\Shared\Logs;
|
use App\Http\Livewire\Project\Shared\Logs;
|
||||||
use App\Http\Livewire\Server\All;
|
use App\Http\Livewire\Server\All;
|
||||||
|
use App\Http\Livewire\Server\Create;
|
||||||
|
use App\Http\Livewire\Server\Destination\Show as DestinationShow;
|
||||||
|
use App\Http\Livewire\Server\PrivateKey\Show as PrivateKeyShow;
|
||||||
|
use App\Http\Livewire\Server\Proxy\Show as ProxyShow;
|
||||||
use App\Http\Livewire\Server\Show;
|
use App\Http\Livewire\Server\Show;
|
||||||
use App\Http\Livewire\Waitlist\Index as WaitlistIndex;
|
use App\Http\Livewire\Waitlist\Index as WaitlistIndex;
|
||||||
use App\Models\GithubApp;
|
use App\Models\GithubApp;
|
||||||
@ -102,18 +106,11 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
Route::get('/servers', All::class)->name('server.all');
|
Route::get('/servers', All::class)->name('server.all');
|
||||||
Route::get('/server/new', [ServerController::class, 'new_server'])->name('server.create');
|
Route::get('/server/new', Create::class)->name('server.create');
|
||||||
Route::get('/server/{server_uuid}', Show::class)->name('server.show');
|
Route::get('/server/{server_uuid}', Show::class)->name('server.show');
|
||||||
Route::get('/server/{server_uuid}/proxy', fn () => view('server.proxy', [
|
Route::get('/server/{server_uuid}/proxy', ProxyShow::class)->name('server.proxy');
|
||||||
'server' => Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->firstOrFail(),
|
Route::get('/server/{server_uuid}/private-key', PrivateKeyShow::class)->name('server.private-key');
|
||||||
]))->name('server.proxy');
|
Route::get('/server/{server_uuid}/destinations', DestinationShow::class)->name('server.destinations');
|
||||||
Route::get('/server/{server_uuid}/private-key', fn () => view('server.private-key', [
|
|
||||||
'server' => Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->firstOrFail(),
|
|
||||||
'privateKeys' => PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false),
|
|
||||||
]))->name('server.private-key');
|
|
||||||
Route::get('/server/{server_uuid}/destinations', fn () => view('server.destinations', [
|
|
||||||
'server' => Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->firstOrFail()
|
|
||||||
]))->name('server.destinations');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user