fix: improve startProxy action

fix: improve installDocker action and process
feat: add noSubmit prop to custom modal
This commit is contained in:
Andras Bacsai 2023-09-09 15:30:46 +02:00
parent b9d49d2951
commit 56981d134c
11 changed files with 104 additions and 91 deletions

View File

@ -30,19 +30,19 @@ public function __invoke(Server $server): Activity
$server->save(); $server->save();
$activity = remote_process([ $activity = remote_process([
"echo 'Creating required Docker networks...'", "echo '####### Creating required Docker networks...'",
...$create_networks_command, ...$create_networks_command,
"cd $proxy_path", "cd $proxy_path",
"echo 'Creating Docker Compose file...'", "echo '####### Creating Docker Compose file...'",
"echo 'Pulling docker image...'", "echo '####### Pulling docker image...'",
'docker compose pull', 'docker compose pull',
"echo 'Stopping existing proxy...'", "echo '####### Stopping existing proxy...'",
'docker compose down -v --remove-orphans', 'docker compose down -v --remove-orphans',
"lsof -nt -i:80 | xargs -r kill -9", "lsof -nt -i:80 | xargs -r kill -9",
"lsof -nt -i:443 | xargs -r kill -9", "lsof -nt -i:443 | xargs -r kill -9",
"echo 'Starting proxy...'", "echo '####### Starting proxy...'",
'docker compose up -d --remove-orphans', 'docker compose up -d --remove-orphans',
"echo 'Proxy installed successfully...'" "echo '####### Proxy installed successfully...'"
], $server); ], $server);
return $activity; return $activity;

View File

@ -18,31 +18,6 @@ public function __invoke(Server $server, Team $team)
"max-file": "3" "max-file": "3"
} }
}'); }');
if (isDev()) {
$activity = remote_process([
"echo ####### Installing Prerequisites...",
"echo ####### Installing/updating Docker Engine...",
"echo ####### Configuring Docker Engine (merging existing configuration with the required)...",
"echo ####### Restarting Docker Engine...",
], $server);
} else {
$activity = remote_process([
"echo ####### Installing Prerequisites...",
"command -v jq >/dev/null || apt-get update",
"command -v jq >/dev/null || apt install -y jq",
"echo ####### Installing/updating Docker Engine...",
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
"echo ####### Configuring Docker Engine (merging existing configuration with the required)...",
"test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json \"/etc/docker/daemon.json.original-`date +\"%Y%m%d-%H%M%S\"`\" || echo '{$config}' | base64 -d > /etc/docker/daemon.json",
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
"cat <<< $(jq . /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json.coolify",
"cat <<< $(jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json",
"echo ####### Restarting Docker Engine...",
"systemctl restart docker",
"echo ####### Creating default network...",
"docker network create --attachable coolify >/dev/null 2>&1 || true",
"echo ####### Done!"
], $server);
$found = StandaloneDocker::where('server_id', $server->id); $found = StandaloneDocker::where('server_id', $server->id);
if ($found->count() == 0) { if ($found->count() == 0) {
StandaloneDocker::create([ StandaloneDocker::create([
@ -51,9 +26,34 @@ public function __invoke(Server $server, Team $team)
'server_id' => $server->id, 'server_id' => $server->id,
]); ]);
} }
} if (isDev()) {
return remote_process([
"echo '####### Installing Prerequisites...'",
return $activity; "sleep 1",
"echo '####### Installing/updating Docker Engine...'",
"echo '####### Configuring Docker Engine (merging existing configuration with the required)...'",
"sleep 4",
"echo '####### Restarting Docker Engine...'",
"ls -l /tmp"
], $server);
} else {
return remote_process([
"echo '####### Installing Prerequisites...'",
"command -v jq >/dev/null || apt-get update",
"command -v jq >/dev/null || apt install -y jq",
"echo '####### Installing/updating Docker Engine...'",
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
"echo '####### Configuring Docker Engine (merging existing configuration with the required)...'",
"test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json \"/etc/docker/daemon.json.original-`date +\"%Y%m%d-%H%M%S\"`\" || echo '{$config}' | base64 -d > /etc/docker/daemon.json",
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
"cat <<< $(jq . /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json.coolify",
"cat <<< $(jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json",
"echo '####### Restarting Docker Engine...'",
"systemctl restart docker",
"echo '####### Creating default Docker network (coolify)...'",
"docker network create --attachable coolify >/dev/null 2>&1 || true",
"echo '####### Done!'"
], $server);
}
} }
} }

View File

@ -37,7 +37,7 @@ public function createPrivateKey()
if ($this->from === 'server') { if ($this->from === 'server') {
return redirect()->route('server.create'); return redirect()->route('server.create');
} }
return redirect()->route('private-key.show', ['private_key_uuid' => $private_key->uuid]); return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
} catch (\Exception $e) { } catch (\Exception $e) {
return general_error_handler(err: $e, that: $this); return general_error_handler(err: $e, that: $this);
} }

View File

@ -54,13 +54,19 @@ public function validateServer()
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server); ['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
if ($uptime) { if ($uptime) {
$this->uptime = $uptime; $this->uptime = $uptime;
$this->emit('success', 'Server is reachable!');
} else {
throw new \Exception('Server is not rachable');
} }
if ($dockerVersion) { if ($dockerVersion) {
$this->dockerVersion = $dockerVersion; $this->dockerVersion = $dockerVersion;
$this->emit('proxyStatusUpdated'); $this->emit('proxyStatusUpdated');
$this->emit('success', 'Docker Engine 23+ is installed!');
} else {
throw new \Exception('Old Docker version detected (lower than 23).');
} }
} catch (\Exception $e) { } catch (\Exception $e) {
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this); return general_error_handler($e, that: $this);
} }
} }
@ -77,8 +83,6 @@ public function delete()
} catch (\Exception $e) { } catch (\Exception $e) {
return general_error_handler(err: $e, that: $this); return general_error_handler(err: $e, that: $this);
} }
} }
public function submit() public function submit()
{ {

View File

@ -4,7 +4,6 @@
use App\Models\Server; use App\Models\Server;
use Livewire\Component; use Livewire\Component;
use Masmerise\Toaster\Toaster;
class ShowPrivateKey extends Component class ShowPrivateKey extends Component
{ {
@ -12,14 +11,24 @@ class ShowPrivateKey extends Component
public $privateKeys; public $privateKeys;
public $parameters; public $parameters;
public function setPrivateKey($private_key_id) public function setPrivateKey($newPrivateKeyId)
{ {
try {
$oldPrivateKeyId = $this->server->private_key_id;
$this->server->update([ $this->server->update([
'private_key_id' => $private_key_id 'private_key_id' => $newPrivateKeyId
]); ]);
refresh_server_connection($this->server->privateKey);
$this->server->refresh(); $this->server->refresh();
refresh_server_connection($this->server->privateKey);
$this->checkConnection(); $this->checkConnection();
} catch (\Exception $e) {
$this->server->update([
'private_key_id' => $oldPrivateKeyId
]);
$this->server->refresh();
refresh_server_connection($this->server->privateKey);
return general_error_handler($e, that: $this);
}
} }
public function checkConnection() public function checkConnection()
@ -27,13 +36,17 @@ public function checkConnection()
try { try {
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server); ['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
if ($uptime) { if ($uptime) {
Toaster::success('Server is reachable with this private key.'); $this->emit('success', 'Server is reachable with this private key.');
} else {
throw new \Exception('Server is not reachable with this private key.');
} }
if ($dockerVersion) { if ($dockerVersion) {
Toaster::success('Server is usable for Coolify.'); $this->emit('success', 'Server is usable for Coolify.');
} else {
throw new \Exception('Old Docker version detected (lower than 23).');
} }
} catch (\Exception $e) { } catch (\Exception $e) {
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this); throw new \Exception($e->getMessage());
} }
} }

View File

@ -16,6 +16,7 @@ public function __construct(
public string|null $modalTitle = null, public string|null $modalTitle = null,
public string|null $modalBody = null, public string|null $modalBody = null,
public string|null $modalSubmit = null, public string|null $modalSubmit = null,
public bool $noSubmit = false,
public bool $yesOrNo = false, public bool $yesOrNo = false,
public string $action = 'delete' public string $action = 'delete'
) { ) {

View File

@ -164,9 +164,9 @@ function refresh_server_connection(PrivateKey $private_key)
// Delete the old ssh mux file to force a new one to be created // Delete the old ssh mux file to force a new one to be created
Storage::disk('ssh-mux')->delete($server->muxFilename()); Storage::disk('ssh-mux')->delete($server->muxFilename());
// check if user is authenticated // check if user is authenticated
if (currentTeam()->id) { // if (currentTeam()->id) {
currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get(); // currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
} // }
} }
} }
@ -184,7 +184,7 @@ function validateServer(Server $server)
} }
$server->settings->is_reachable = true; $server->settings->is_reachable = true;
$dockerVersion = instant_remote_process(['docker version|head -2|grep -i version'], $server, false); $dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $server, false);
if (!$dockerVersion) { if (!$dockerVersion) {
$dockerVersion = null; $dockerVersion = null;
return [ return [
@ -192,7 +192,13 @@ function validateServer(Server $server)
"dockerVersion" => null, "dockerVersion" => null,
]; ];
} }
$majorDockerVersion = Str::of($dockerVersion)->before('.')->value();
if ($majorDockerVersion <= 22) {
$dockerVersion = null;
$server->settings->is_usable = false;
} else {
$server->settings->is_usable = true; $server->settings->is_usable = true;
}
return [ return [
"uptime" => $uptime, "uptime" => $uptime,
"dockerVersion" => $dockerVersion, "dockerVersion" => $dockerVersion,
@ -202,7 +208,7 @@ function validateServer(Server $server)
$server->settings->is_usable = false; $server->settings->is_usable = false;
throw $e; throw $e;
} finally { } finally {
$server->settings->save(); if(data_get($server,'settings')) $server->settings->save();
} }
} }

View File

@ -1,6 +1,6 @@
<dialog id="{{ $modalId }}" class="modal"> <dialog id="{{ $modalId }}" class="modal">
@if ($yesOrNo) @if ($yesOrNo)
<form method="dialog" class="rounded modal-box" wire:submit.prevent='submit'> <form method="dialog" class="rounded modal-box" @if(!$noSubmit) wire:submit.prevent='submit' @endif>
<div class="flex items-start"> <div class="flex items-start">
<div class="flex items-center justify-center flex-shrink-0 w-10 h-10 mr-4 rounded-full"> <div class="flex items-center justify-center flex-shrink-0 w-10 h-10 mr-4 rounded-full">
<svg class="w-8 h-8 text-error" fill="none" viewBox="0 0 24 24" stroke-width="1.5" <svg class="w-8 h-8 text-error" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
@ -34,7 +34,7 @@
</form> </form>
@else @else
<form method="dialog" class="flex flex-col w-11/12 max-w-5xl gap-2 rounded modal-box" <form method="dialog" class="flex flex-col w-11/12 max-w-5xl gap-2 rounded modal-box"
wire:submit.prevent='submit'> @if(!$noSubmit) wire:submit.prevent='submit' @endif>
@isset($modalTitle) @isset($modalTitle)
<h3 class="text-lg font-bold">{{ $modalTitle }}</h3> <h3 class="text-lg font-bold">{{ $modalTitle }}</h3>
@endisset @endisset

View File

@ -18,11 +18,6 @@
@else @else
<x-forms.button type="submit">Save</x-forms.button> <x-forms.button type="submit">Save</x-forms.button>
@endif @endif
@if (!$server->settings->is_reachable || !$server->settings->is_usable)
<x-forms.button wire:click.prevent='validateServer'>
Validate Server
</x-forms.button>
@endif
</div> </div>
@if (!$server->settings->is_reachable || !$server->settings->is_usable) @if (!$server->settings->is_reachable || !$server->settings->is_usable)
@ -51,43 +46,25 @@
</div> </div>
</div> </div>
</div> </div>
@if ($server->settings->is_reachable) @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)
<x-forms.button wire:poll.2000ms='validateServer' class="mt-8 mb-4 box" onclick="installDocker.showModal()" wire:click.prevent='installDocker' isHighlighted>
Install Docker Engine 24.0
</x-forms.button>
@endif
@if ($server->settings->is_usable)
<h3 class="py-4">Settings</h3> <h3 class="py-4">Settings</h3>
<div class="flex items-center w-64 gap-2"> <div class="flex items-center w-64 gap-2">
<x-forms.input id="cleanup_after_percentage" label="Disk Cleanup threshold (%)" required <x-forms.input id="cleanup_after_percentage" label="Disk Cleanup threshold (%)" required
helper="Disk cleanup job will be executed if disk usage is more than this number." /> helper="Disk cleanup job will be executed if disk usage is more than this number." />
</div> </div>
<h3 class="py-4">Actions</h3>
<div class="flex items-center gap-2">
<x-forms.button wire:click.prevent='validateServer'>
Check Server Details
</x-forms.button>
@if ($server->id !== 0)
<x-forms.button wire:click.prevent='installDocker' isHighlighted>
@if ($server->settings->is_usable)
Reconfigure Docker Engine
@else
Install Docker Engine
@endif @endif
</x-forms.button>
@endif
</div>
@endif
<div class="container w-full py-4 mx-auto">
<livewire:activity-monitor header="Logs" />
</div>
@isset($uptime)
<h3 class="pb-3">Server Info</h3>
<div class="py-2 pb-4">
<p>Uptime: {{ $uptime }}</p>
@isset($dockerVersion)
<p>Docker Engine {{ $dockerVersion }}</p>
@endisset
</div>
@endisset
</form> </form>
<h2>Danger Zone</h2> <h2 class="pt-4">Danger Zone</h2>
<div class="">Woah. I hope you know what are you doing.</div> <div class="">Woah. I hope you know what are you doing.</div>
<h4 class="pt-4">Delete Server</h4> <h4 class="pt-4">Delete Server</h4>
<div class="pb-4">This will remove this server from Coolify. Beware! There is no coming <div class="pb-4">This will remove this server from Coolify. Beware! There is no coming

View File

@ -22,11 +22,13 @@
@endif @endif
</div> </div>
<h3 class="pb-4">Select a different Private Key</h3> <h3 class="pb-4">Choose another Key</h3>
<div class="grid gap-2"> <div class="grid grid-cols-3 gap-2">
@forelse ($privateKeys as $private_key) @forelse ($privateKeys as $private_key)
<div class="cursor-pointer box" wire:click='setPrivateKey({{ $private_key->id }})'>{{ $private_key->name }} <x-forms.button class="flex flex-col box" wire:click='setPrivateKey({{ $private_key->id }})'>
</div> <div>{{ $private_key->name }}</div>
<div class="text-xs">{{ $private_key->description }}</div>
</x-forms.button>
@empty @empty
<div>No private keys found. <div>No private keys found.
<x-use-magic-bar link="/security/private-key/new" /> <x-use-magic-bar link="/security/private-key/new" />

View File

@ -1,4 +1,14 @@
<div> <div>
<x-modal noSubmit modalId="installDocker">
<x-slot:modalBody>
<livewire:activity-monitor header="Installation Logs" />
</x-slot:modalBody>
<x-slot:modalSubmit>
<x-forms.button onclick="installDocker.close()" type="submit">
Close
</x-forms.button>
</x-slot:modalSubmit>
</x-modal>
<x-server.navbar :server="$server" /> <x-server.navbar :server="$server" />
<livewire:server.form :server="$server" /> <livewire:server.form :server="$server" />
</div> </div>