diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php index 92dd7e8c3..36c540950 100644 --- a/app/Actions/Server/InstallDocker.php +++ b/app/Actions/Server/InstallDocker.php @@ -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...'", ]); diff --git a/app/Actions/Server/InstallPrerequisites.php b/app/Actions/Server/InstallPrerequisites.php new file mode 100644 index 000000000..1a7d3bbd9 --- /dev/null +++ b/app/Actions/Server/InstallPrerequisites.php @@ -0,0 +1,57 @@ +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); + } +} diff --git a/app/Actions/Server/ValidatePrerequisites.php b/app/Actions/Server/ValidatePrerequisites.php new file mode 100644 index 000000000..f74727112 --- /dev/null +++ b/app/Actions/Server/ValidatePrerequisites.php @@ -0,0 +1,27 @@ +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) { diff --git a/app/Jobs/ValidateAndInstallServerJob.php b/app/Jobs/ValidateAndInstallServerJob.php index 388791f10..a6dcd62f1 100644 --- a/app/Jobs/ValidateAndInstallServerJob.php +++ b/app/Jobs/ValidateAndInstallServerJob.php @@ -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(); diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php index 9f1eac4d2..dfddd7f68 100644 --- a/app/Livewire/Boarding/Index.php +++ b/app/Livewire/Boarding/Index.php @@ -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); diff --git a/app/Livewire/Server/ValidateAndInstall.php b/app/Livewire/Server/ValidateAndInstall.php index bbd7f3dd9..687eadd48 100644 --- a/app/Livewire/Server/ValidateAndInstall.php +++ b/app/Livewire/Server/ValidateAndInstall.php @@ -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); diff --git a/app/Models/Server.php b/app/Models/Server.php index e88af2b15..9210e801b 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -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); diff --git a/resources/views/livewire/server/validate-and-install.blade.php b/resources/views/livewire/server/validate-and-install.blade.php index 572da85e8..85ea3105e 100644 --- a/resources/views/livewire/server/validate-and-install.blade.php +++ b/resources/views/livewire/server/validate-and-install.blade.php @@ -52,6 +52,30 @@ @endif @endif @if ($uptime && $supported_os_type) + @if ($prerequisites_installed) +