feat: implement prerequisite validation and installation for server setup
This commit is contained in:
parent
ce4f8d02a2
commit
01957f2752
9 changed files with 218 additions and 32 deletions
|
|
@ -59,8 +59,6 @@ public function handle(Server $server)
|
|||
$command = collect([]);
|
||||
if (isDev() && $server->id === 0) {
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Prerequisites...'",
|
||||
'sleep 1',
|
||||
"echo 'Installing Docker Engine...'",
|
||||
"echo 'Configuring Docker Engine (merging existing configuration with the required)...'",
|
||||
'sleep 4',
|
||||
|
|
@ -70,35 +68,6 @@ public function handle(Server $server)
|
|||
|
||||
return remote_process($command, $server);
|
||||
} else {
|
||||
if ($supported_os_type->contains('debian')) {
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Prerequisites...'",
|
||||
'apt-get update -y',
|
||||
'command -v curl >/dev/null || apt install -y curl',
|
||||
'command -v wget >/dev/null || apt install -y wget',
|
||||
'command -v git >/dev/null || apt install -y git',
|
||||
'command -v jq >/dev/null || apt install -y jq',
|
||||
]);
|
||||
} elseif ($supported_os_type->contains('rhel')) {
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Prerequisites...'",
|
||||
'command -v curl >/dev/null || dnf install -y curl',
|
||||
'command -v wget >/dev/null || dnf install -y wget',
|
||||
'command -v git >/dev/null || dnf install -y git',
|
||||
'command -v jq >/dev/null || dnf install -y jq',
|
||||
]);
|
||||
} elseif ($supported_os_type->contains('sles')) {
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Prerequisites...'",
|
||||
'zypper update -y',
|
||||
'command -v curl >/dev/null || zypper install -y curl',
|
||||
'command -v wget >/dev/null || zypper install -y wget',
|
||||
'command -v git >/dev/null || zypper install -y git',
|
||||
'command -v jq >/dev/null || zypper install -y jq',
|
||||
]);
|
||||
} else {
|
||||
throw new \Exception('Unsupported OS');
|
||||
}
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Docker Engine...'",
|
||||
]);
|
||||
|
|
|
|||
57
app/Actions/Server/InstallPrerequisites.php
Normal file
57
app/Actions/Server/InstallPrerequisites.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class InstallPrerequisites
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public string $jobQueue = 'high';
|
||||
|
||||
public function handle(Server $server)
|
||||
{
|
||||
$supported_os_type = $server->validateOS();
|
||||
if (! $supported_os_type) {
|
||||
throw new \Exception('Server OS type is not supported for automated installation. Please install prerequisites manually.');
|
||||
}
|
||||
|
||||
$command = collect([]);
|
||||
|
||||
if ($supported_os_type->contains('debian')) {
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Prerequisites...'",
|
||||
'apt-get update -y',
|
||||
'command -v curl >/dev/null || apt install -y curl',
|
||||
'command -v wget >/dev/null || apt install -y wget',
|
||||
'command -v git >/dev/null || apt install -y git',
|
||||
'command -v jq >/dev/null || apt install -y jq',
|
||||
]);
|
||||
} elseif ($supported_os_type->contains('rhel')) {
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Prerequisites...'",
|
||||
'command -v curl >/dev/null || dnf install -y curl',
|
||||
'command -v wget >/dev/null || dnf install -y wget',
|
||||
'command -v git >/dev/null || dnf install -y git',
|
||||
'command -v jq >/dev/null || dnf install -y jq',
|
||||
]);
|
||||
} elseif ($supported_os_type->contains('sles')) {
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Prerequisites...'",
|
||||
'zypper update -y',
|
||||
'command -v curl >/dev/null || zypper install -y curl',
|
||||
'command -v wget >/dev/null || zypper install -y wget',
|
||||
'command -v git >/dev/null || zypper install -y git',
|
||||
'command -v jq >/dev/null || zypper install -y jq',
|
||||
]);
|
||||
} else {
|
||||
throw new \Exception('Unsupported OS type for prerequisites installation');
|
||||
}
|
||||
|
||||
$command->push("echo 'Prerequisites installed successfully.'");
|
||||
|
||||
return remote_process($command, $server);
|
||||
}
|
||||
}
|
||||
27
app/Actions/Server/ValidatePrerequisites.php
Normal file
27
app/Actions/Server/ValidatePrerequisites.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class ValidatePrerequisites
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public string $jobQueue = 'high';
|
||||
|
||||
public function handle(Server $server): bool
|
||||
{
|
||||
$requiredCommands = ['git', 'curl', 'jq'];
|
||||
|
||||
foreach ($requiredCommands as $cmd) {
|
||||
$found = instant_remote_process(["command -v {$cmd}"], $server, false);
|
||||
if (! $found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,15 @@ public function handle(Server $server)
|
|||
throw new \Exception($this->error);
|
||||
}
|
||||
|
||||
$prerequisitesInstalled = $server->validatePrerequisites();
|
||||
if (! $prerequisitesInstalled) {
|
||||
$this->error = 'Prerequisites (git, curl, jq) are not installed. Please install them before continuing or use the validation with installation endpoint.';
|
||||
$server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
throw new \Exception($this->error);
|
||||
}
|
||||
|
||||
$this->docker_installed = $server->validateDockerEngine();
|
||||
$this->docker_compose_installed = $server->validateDockerCompose();
|
||||
if (! $this->docker_installed || ! $this->docker_compose_installed) {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,37 @@ public function handle(): void
|
|||
return;
|
||||
}
|
||||
|
||||
// Check and install prerequisites
|
||||
$prerequisitesInstalled = $this->server->validatePrerequisites();
|
||||
if (! $prerequisitesInstalled) {
|
||||
if ($this->numberOfTries >= $this->maxTries) {
|
||||
$errorMessage = 'Prerequisites (git, curl, jq) could not be installed after '.$this->maxTries.' attempts. Please install them manually before continuing.';
|
||||
$this->server->update([
|
||||
'validation_logs' => $errorMessage,
|
||||
'is_validating' => false,
|
||||
]);
|
||||
Log::error('ValidateAndInstallServer: Prerequisites installation failed after max tries', [
|
||||
'server_id' => $this->server->id,
|
||||
'attempts' => $this->numberOfTries,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log::info('ValidateAndInstallServer: Installing prerequisites', [
|
||||
'server_id' => $this->server->id,
|
||||
'attempt' => $this->numberOfTries + 1,
|
||||
]);
|
||||
|
||||
// Install prerequisites
|
||||
$this->server->installPrerequisites();
|
||||
|
||||
// Retry validation after installation
|
||||
self::dispatch($this->server, $this->numberOfTries + 1)->delay(now()->addSeconds(30));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if Docker is installed
|
||||
$dockerInstalled = $this->server->validateDockerEngine();
|
||||
$dockerComposeInstalled = $this->server->validateDockerCompose();
|
||||
|
|
|
|||
|
|
@ -320,6 +320,21 @@ public function validateServer()
|
|||
return handleError(error: $e, livewire: $this);
|
||||
}
|
||||
|
||||
try {
|
||||
// Check prerequisites
|
||||
$prerequisitesInstalled = $this->createdServer->validatePrerequisites();
|
||||
if (! $prerequisitesInstalled) {
|
||||
$this->createdServer->installPrerequisites();
|
||||
// Recheck after installation
|
||||
$prerequisitesInstalled = $this->createdServer->validatePrerequisites();
|
||||
if (! $prerequisitesInstalled) {
|
||||
throw new \Exception('Prerequisites (git, curl, jq) could not be installed. Please install them manually.');
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError(error: $e, livewire: $this);
|
||||
}
|
||||
|
||||
try {
|
||||
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
|
||||
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ class ValidateAndInstall extends Component
|
|||
|
||||
public $supported_os_type = null;
|
||||
|
||||
public $prerequisites_installed = null;
|
||||
|
||||
public $docker_installed = null;
|
||||
|
||||
public $docker_compose_installed = null;
|
||||
|
|
@ -33,12 +35,15 @@ class ValidateAndInstall extends Component
|
|||
|
||||
public $error = null;
|
||||
|
||||
public string $installationStep = 'Prerequisites';
|
||||
|
||||
public bool $ask = false;
|
||||
|
||||
protected $listeners = [
|
||||
'init',
|
||||
'validateConnection',
|
||||
'validateOS',
|
||||
'validatePrerequisites',
|
||||
'validateDockerEngine',
|
||||
'validateDockerVersion',
|
||||
'refresh' => '$refresh',
|
||||
|
|
@ -48,6 +53,7 @@ public function init(int $data = 0)
|
|||
{
|
||||
$this->uptime = null;
|
||||
$this->supported_os_type = null;
|
||||
$this->prerequisites_installed = null;
|
||||
$this->docker_installed = null;
|
||||
$this->docker_version = null;
|
||||
$this->docker_compose_installed = null;
|
||||
|
|
@ -69,6 +75,7 @@ public function retry()
|
|||
$this->authorize('update', $this->server);
|
||||
$this->uptime = null;
|
||||
$this->supported_os_type = null;
|
||||
$this->prerequisites_installed = null;
|
||||
$this->docker_installed = null;
|
||||
$this->docker_compose_installed = null;
|
||||
$this->docker_version = null;
|
||||
|
|
@ -103,6 +110,40 @@ public function validateOS()
|
|||
|
||||
return;
|
||||
}
|
||||
$this->dispatch('validatePrerequisites');
|
||||
}
|
||||
|
||||
public function validatePrerequisites()
|
||||
{
|
||||
$this->prerequisites_installed = $this->server->validatePrerequisites();
|
||||
if (! $this->prerequisites_installed) {
|
||||
if ($this->install) {
|
||||
if ($this->number_of_tries == $this->max_tries) {
|
||||
$this->error = 'Prerequisites (git, curl, jq) could not be installed. Please install them manually before continuing.';
|
||||
$this->server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
|
||||
return;
|
||||
} else {
|
||||
if ($this->number_of_tries <= $this->max_tries) {
|
||||
$this->installationStep = 'Prerequisites';
|
||||
$activity = $this->server->installPrerequisites();
|
||||
$this->number_of_tries++;
|
||||
$this->dispatch('activityMonitor', $activity->id, 'init', $this->number_of_tries);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$this->error = 'Prerequisites (git, curl, jq) are not installed. Please install them before continuing.';
|
||||
$this->server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->dispatch('validateDockerEngine');
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +162,7 @@ public function validateDockerEngine()
|
|||
return;
|
||||
} else {
|
||||
if ($this->number_of_tries <= $this->max_tries) {
|
||||
$this->installationStep = 'Docker';
|
||||
$activity = $this->server->installDocker();
|
||||
$this->number_of_tries++;
|
||||
$this->dispatch('activityMonitor', $activity->id, 'init', $this->number_of_tries);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
use App\Actions\Proxy\StartProxy;
|
||||
use App\Actions\Server\InstallDocker;
|
||||
use App\Actions\Server\InstallPrerequisites;
|
||||
use App\Actions\Server\StartSentinel;
|
||||
use App\Actions\Server\ValidatePrerequisites;
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Events\ServerReachabilityChanged;
|
||||
use App\Helpers\SslHelper;
|
||||
|
|
@ -1184,6 +1186,16 @@ public function installDocker()
|
|||
return InstallDocker::run($this);
|
||||
}
|
||||
|
||||
public function validatePrerequisites(): bool
|
||||
{
|
||||
return ValidatePrerequisites::run($this);
|
||||
}
|
||||
|
||||
public function installPrerequisites()
|
||||
{
|
||||
return InstallPrerequisites::run($this);
|
||||
}
|
||||
|
||||
public function validateDockerEngine($throwError = false)
|
||||
{
|
||||
$dockerBinary = instant_remote_process(['command -v docker'], $this, false, no_sudo: true);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,30 @@
|
|||
@endif
|
||||
@endif
|
||||
@if ($uptime && $supported_os_type)
|
||||
@if ($prerequisites_installed)
|
||||
<div class="flex w-64 gap-2">Prerequisites are installed: <svg class="w-5 h-5 text-success"
|
||||
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="currentColor">
|
||||
<path
|
||||
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
||||
opacity=".2" />
|
||||
<path
|
||||
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
||||
</g>
|
||||
</svg></div>
|
||||
@else
|
||||
@if ($error)
|
||||
<div class="flex w-64 gap-2">Prerequisites are installed: <svg class="w-5 h-5 text-error"
|
||||
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
||||
</svg></div>
|
||||
@else
|
||||
<div class="w-64"><x-loading text="Prerequisites are installed:" /></div>
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
@if ($uptime && $supported_os_type && $prerequisites_installed)
|
||||
@if ($docker_installed)
|
||||
<div class="flex w-64 gap-2">Docker is installed: <svg class="w-5 h-5 text-success"
|
||||
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
|
|
@ -120,7 +144,7 @@
|
|||
@endif
|
||||
|
||||
@endif
|
||||
<livewire:activity-monitor header="Docker Installation Logs" :showWaiting="false" />
|
||||
<livewire:activity-monitor header="{{ $installationStep }} Installation Logs" :showWaiting="false" />
|
||||
@isset($error)
|
||||
<pre class="font-bold whitespace-pre-line text-error">{!! $error !!}</pre>
|
||||
<x-forms.button canGate="update" :canResource="$server" wire:click="retry" class="mt-4">
|
||||
|
|
|
|||
Loading…
Reference in a new issue