From 49f5240ff8a010e8cc5b0d23b685aae4332d330c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 5 Feb 2024 14:40:54 +0100 Subject: [PATCH] fix: better server validation and installation process fix: add destination to queue deployment feat: force start deployment --- app/Actions/Server/InstallDocker.php | 2 +- app/Jobs/ApplicationDeploymentJob.php | 47 +++++--- app/Livewire/ActivityMonitor.php | 2 +- app/Livewire/Boarding/Index.php | 13 ++- app/Livewire/NewActivityMonitor.php | 63 +++++++++++ .../Project/Application/DeploymentNavbar.php | 13 ++- app/Livewire/Project/Application/Heading.php | 20 ---- app/Livewire/Project/Database/Heading.php | 10 +- app/Livewire/Project/Database/Import.php | 2 +- app/Livewire/Project/Service/Navbar.php | 4 +- ...ication.php => ServiceApplicationView.php} | 4 +- .../Shared/ExecuteContainerCommand.php | 2 +- app/Livewire/RunCommand.php | 2 +- app/Livewire/Server/Form.php | 55 ++-------- app/Livewire/Server/Proxy/Deploy.php | 2 +- app/Livewire/Server/Proxy/Status.php | 4 +- app/Livewire/Server/Show.php | 2 +- app/Livewire/Server/ValidateAndInstall.php | 100 ++++++++++++++++++ app/Models/Server.php | 6 ++ bootstrap/helpers/applications.php | 46 ++++++-- ...215_add_destination_to_app_deployments.php | 28 +++++ .../views/components/pricing-plans.blade.php | 3 +- .../views/components/slide-over.blade.php | 22 ++-- resources/views/layouts/base.blade.php | 1 + resources/views/layouts/boarding.blade.php | 10 -- .../views/livewire/boarding/index.blade.php | 43 ++++---- .../livewire/new-activity-monitor.blade.php | 18 ++++ .../application/deployment-navbar.blade.php | 6 +- .../project/application/heading.blade.php | 12 --- .../livewire/project/service/index.blade.php | 2 +- ...php => service-application-view.blade.php} | 0 .../views/livewire/server/form.blade.php | 17 ++- .../views/livewire/server/show.blade.php | 10 -- .../server/validate-and-install.blade.php | 56 ++++++++++ 34 files changed, 443 insertions(+), 184 deletions(-) create mode 100644 app/Livewire/NewActivityMonitor.php rename app/Livewire/Project/Service/{Application.php => ServiceApplicationView.php} (94%) create mode 100644 app/Livewire/Server/ValidateAndInstall.php create mode 100644 database/migrations/2024_02_05_105215_add_destination_to_app_deployments.php create mode 100644 resources/views/livewire/new-activity-monitor.blade.php rename resources/views/livewire/project/service/{application.blade.php => service-application-view.blade.php} (100%) create mode 100644 resources/views/livewire/server/validate-and-install.blade.php diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php index c347b4181..553a1c09d 100644 --- a/app/Actions/Server/InstallDocker.php +++ b/app/Actions/Server/InstallDocker.php @@ -43,6 +43,7 @@ class InstallDocker "echo 'Restarting Docker Engine...'", "ls -l /tmp" ]); + return remote_process($command, $server); } else { if ($supported_os_type->contains('debian')) { $command = $command->merge([ @@ -89,7 +90,6 @@ class InstallDocker "echo 'Done!'", ]); } - return remote_process($command, $server); } } diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 022368548..9d0e069ce 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -122,7 +122,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if ($source) { $this->source = $source->getMorphClass()::where('id', $this->application->source->id)->first(); } - $this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first(); + $this->server = Server::find($this->application_deployment_queue->server_id); + $this->destination = $this->server->destinations()->where('id', $this->application_deployment_queue->destination_id)->first(); $this->server = $this->mainServer = $this->destination->server; $this->serverUser = $this->server->user; $this->basedir = $this->application->generateBaseDir($this->deployment_uuid); @@ -561,12 +562,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->generate_build_env_variables(); $this->add_build_env_variables_to_dockerfile(); $this->build_image(); - // if ($this->application->additional_destinations) { - // $this->push_to_docker_registry(); - // $this->deploy_to_additional_destinations(); - // } else { $this->rolling_update(); - // } } private function deploy_nixpacks_buildpack() { @@ -791,7 +787,18 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted } private function deploy_to_additional_destinations() { + if (str($this->application->additional_destinations)->isEmpty()) { + return; + } $destination_ids = collect(str($this->application->additional_destinations)->explode(',')); + if ($this->server->isSwarm()) { + $this->application_deployment_queue->addLogEntry("Additional destinations are not supported in swarm mode."); + return; + } + if ($destination_ids->contains($this->destination->id)) { + ray('Same destination found in additional destinations. Skipping.'); + return; + } foreach ($destination_ids as $destination_id) { $destination = StandaloneDocker::find($destination_id); $server = $destination->server; @@ -799,11 +806,21 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->application_deployment_queue->addLogEntry("Skipping deployment to {$server->name}. Not in the same team?!"); continue; } - $this->server = $server; - $this->application_deployment_queue->addLogEntry("Deploying to {$this->server->name}."); - $this->prepare_builder_image(); - $this->generate_image_names(); - $this->rolling_update(); + // ray('Deploying to additional destination: ', $server->name); + $deployment_uuid = new Cuid2(); + queue_application_deployment( + deployment_uuid: $deployment_uuid, + application: $this->application, + server: $server, + destination: $destination, + no_questions_asked: true, + ); + $this->application_deployment_queue->addLogEntry("Deploying to additional server: {$server->name}. Click here to see the deployment status: " . route('project.application.deployment.show', [ + 'project_uuid' => data_get($this->application, 'environment.project.uuid'), + 'application_uuid' => data_get($this->application, 'uuid'), + 'deployment_uuid' => $deployment_uuid, + 'environment_name' => data_get($this->application, 'environment.name'), + ])); } } private function set_base_dir() @@ -1507,11 +1524,13 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); 'status' => $status, ]); } - if ($status === ApplicationDeploymentStatus::FINISHED->value) { - $this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview)); - } if ($status === ApplicationDeploymentStatus::FAILED->value) { $this->application->environment->project->team?->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview)); + return; + } + if ($status === ApplicationDeploymentStatus::FINISHED->value) { + // $this->deploy_to_additional_destinations(); + $this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview)); } } diff --git a/app/Livewire/ActivityMonitor.php b/app/Livewire/ActivityMonitor.php index 8f887b3c5..ad2a599a1 100644 --- a/app/Livewire/ActivityMonitor.php +++ b/app/Livewire/ActivityMonitor.php @@ -15,7 +15,7 @@ class ActivityMonitor extends Component public $isPollingActive = false; protected $activity; - protected $listeners = ['newMonitorActivity']; + protected $listeners = ['activityMonitor' => 'newMonitorActivity']; public function newMonitorActivity($activityId, $eventToDispatch = 'activityFinished') { diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php index cc282d4c0..eee62c93d 100644 --- a/app/Livewire/Boarding/Index.php +++ b/app/Livewire/Boarding/Index.php @@ -12,6 +12,7 @@ use Livewire\Component; class Index extends Component { + protected $listeners = ['serverInstalled' => 'validateServer']; public string $currentState = 'welcome'; public ?string $selectedServerType = null; @@ -93,7 +94,11 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== $this->serverPublicKey = $this->createdServer->privateKey->publicKey(); return $this->validateServer('localhost'); } elseif ($this->selectedServerType === 'remote') { - $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get(); + if (isDev()) { + $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->get(); + } else { + $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get(); + } if ($this->privateKeys->count() > 0) { $this->selectedExistingPrivateKey = $this->privateKeys->first()->id; } @@ -190,6 +195,10 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== $this->createdServer->addInitialNetwork(); $this->validateServer(); } + public function installServer() + { + $this->dispatch('validateServer', true); + } public function validateServer() { try { @@ -228,7 +237,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== $this->dockerInstallationStarted = true; $activity = InstallDocker::run($this->createdServer); $this->dispatch('installDocker'); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } catch (\Throwable $e) { $this->dockerInstallationStarted = false; return handleError(error: $e, livewire: $this); diff --git a/app/Livewire/NewActivityMonitor.php b/app/Livewire/NewActivityMonitor.php new file mode 100644 index 000000000..8f2dba0da --- /dev/null +++ b/app/Livewire/NewActivityMonitor.php @@ -0,0 +1,63 @@ + 'newMonitorActivity']; + + public function newMonitorActivity($activityId, $eventToDispatch = 'activityFinished') + { + $this->activityId = $activityId; + $this->eventToDispatch = $eventToDispatch; + + $this->hydrateActivity(); + + $this->isPollingActive = true; + } + + public function hydrateActivity() + { + $this->activity = Activity::find($this->activityId); + } + + public function polling() + { + $this->hydrateActivity(); + // $this->setStatus(ProcessStatus::IN_PROGRESS); + $exit_code = data_get($this->activity, 'properties.exitCode'); + if ($exit_code !== null) { + // if ($exit_code === 0) { + // // $this->setStatus(ProcessStatus::FINISHED); + // } else { + // // $this->setStatus(ProcessStatus::ERROR); + // } + $this->isPollingActive = false; + if ($this->eventToDispatch !== null) { + if (str($this->eventToDispatch)->startsWith('App\\Events\\')) { + $causer_id = data_get($this->activity, 'causer_id'); + $user = User::find($causer_id); + if ($user) { + foreach ($user->teams as $team) { + $teamId = $team->id; + $this->eventToDispatch::dispatch($teamId); + } + } + return; + } + $this->dispatch($this->eventToDispatch); + ray('Dispatched event: ' . $this->eventToDispatch); + } + } + } +} diff --git a/app/Livewire/Project/Application/DeploymentNavbar.php b/app/Livewire/Project/Application/DeploymentNavbar.php index 4c5d2135a..9ba0e7a27 100644 --- a/app/Livewire/Project/Application/DeploymentNavbar.php +++ b/app/Livewire/Project/Application/DeploymentNavbar.php @@ -7,8 +7,6 @@ use App\Models\Application; use App\Models\ApplicationDeploymentQueue; use App\Models\Server; use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\Process; -use Illuminate\Support\Str; use Livewire\Component; class DeploymentNavbar extends Component @@ -37,7 +35,15 @@ class DeploymentNavbar extends Component $this->is_debug_enabled = $this->application->settings->is_debug_enabled; $this->dispatch('refreshQueue'); } - + public function force_start() + { + try { + force_start_deployment($this->application_deployment_queue); + } catch (\Throwable $e) { + ray($e); + return handleError($e, $this); + } + } public function cancel() { try { @@ -67,7 +73,6 @@ class DeploymentNavbar extends Component 'current_process_id' => null, 'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value, ]); - // queue_next_deployment($this->application); } } } diff --git a/app/Livewire/Project/Application/Heading.php b/app/Livewire/Project/Application/Heading.php index afac72d85..8f7a22ec8 100644 --- a/app/Livewire/Project/Application/Heading.php +++ b/app/Livewire/Project/Application/Heading.php @@ -46,26 +46,6 @@ class Heading extends Component $this->deploy(force_rebuild: true); } - public function deployNew() - { - if ($this->application->build_pack === 'dockercompose' && is_null($this->application->docker_compose_raw)) { - $this->dispatch('error', 'Please load a Compose file first.'); - return; - } - $this->setDeploymentUuid(); - queue_application_deployment( - application: $this->application, - deployment_uuid: $this->deploymentUuid, - force_rebuild: false, - is_new_deployment: true, - ); - return redirect()->route('project.application.deployment.show', [ - 'project_uuid' => $this->parameters['project_uuid'], - 'application_uuid' => $this->parameters['application_uuid'], - 'deployment_uuid' => $this->deploymentUuid, - 'environment_name' => $this->parameters['environment_name'], - ]); - } public function deploy(bool $force_rebuild = false) { if ($this->application->build_pack === 'dockercompose' && is_null($this->application->docker_compose_raw)) { diff --git a/app/Livewire/Project/Database/Heading.php b/app/Livewire/Project/Database/Heading.php index 76b36a5ba..303166227 100644 --- a/app/Livewire/Project/Database/Heading.php +++ b/app/Livewire/Project/Database/Heading.php @@ -58,19 +58,19 @@ class Heading extends Component { if ($this->database->type() === 'standalone-postgresql') { $activity = StartPostgresql::run($this->database); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } else if ($this->database->type() === 'standalone-redis') { $activity = StartRedis::run($this->database); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } else if ($this->database->type() === 'standalone-mongodb') { $activity = StartMongodb::run($this->database); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } else if ($this->database->type() === 'standalone-mysql') { $activity = StartMysql::run($this->database); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } else if ($this->database->type() === 'standalone-mariadb') { $activity = StartMariadb::run($this->database); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } } } diff --git a/app/Livewire/Project/Database/Import.php b/app/Livewire/Project/Database/Import.php index 697b14646..c111753d5 100644 --- a/app/Livewire/Project/Database/Import.php +++ b/app/Livewire/Project/Database/Import.php @@ -129,7 +129,7 @@ class Import extends Component if (!empty($this->importCommands)) { $activity = remote_process($this->importCommands, $this->server, ignore_errors: true); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } } catch (\Throwable $e) { $this->validated = false; diff --git a/app/Livewire/Project/Service/Navbar.php b/app/Livewire/Project/Service/Navbar.php index d401a1022..2eb9f938c 100644 --- a/app/Livewire/Project/Service/Navbar.php +++ b/app/Livewire/Project/Service/Navbar.php @@ -57,7 +57,7 @@ class Navbar extends Component } $this->service->parse(); $activity = StartService::run($this->service); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } public function stop(bool $forceCleanup = false) { @@ -82,6 +82,6 @@ class Navbar extends Component StopService::run($this->service); $this->service->parse(); $activity = StartService::run($this->service); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } } diff --git a/app/Livewire/Project/Service/Application.php b/app/Livewire/Project/Service/ServiceApplicationView.php similarity index 94% rename from app/Livewire/Project/Service/Application.php rename to app/Livewire/Project/Service/ServiceApplicationView.php index c3157921b..a17494d1d 100644 --- a/app/Livewire/Project/Service/Application.php +++ b/app/Livewire/Project/Service/ServiceApplicationView.php @@ -5,7 +5,7 @@ namespace App\Livewire\Project\Service; use App\Models\ServiceApplication; use Livewire\Component; -class Application extends Component +class ServiceApplicationView extends Component { public ServiceApplication $application; public $parameters; @@ -20,7 +20,7 @@ class Application extends Component ]; public function render() { - return view('livewire.project.service.application'); + return view('livewire.project.service.service-application-view'); } public function instantSave() { diff --git a/app/Livewire/Project/Shared/ExecuteContainerCommand.php b/app/Livewire/Project/Shared/ExecuteContainerCommand.php index 83df5a15c..3687669a9 100644 --- a/app/Livewire/Project/Shared/ExecuteContainerCommand.php +++ b/app/Livewire/Project/Shared/ExecuteContainerCommand.php @@ -115,7 +115,7 @@ class ExecuteContainerCommand extends Component $exec = "docker exec {$this->container} {$cmd}"; } $activity = remote_process([$exec], $this->server, ignore_errors: true); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/RunCommand.php b/app/Livewire/RunCommand.php index 309283403..42f914818 100644 --- a/app/Livewire/RunCommand.php +++ b/app/Livewire/RunCommand.php @@ -31,7 +31,7 @@ class RunCommand extends Component $this->validate(); try { $activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true); - $this->dispatch('newMonitorActivity', $activity->id); + $this->dispatch('activityMonitor', $activity->id); } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 8ec31a228..936f8e724 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -2,7 +2,6 @@ namespace App\Livewire\Server; -use App\Actions\Server\InstallDocker; use App\Models\Server; use Livewire\Component; @@ -14,7 +13,8 @@ class Form extends Component public ?string $wildcard_domain = null; public int $cleanup_after_percentage; public bool $dockerInstallationStarted = false; - protected $listeners = ['serverRefresh']; + + protected $listeners = ['serverInstalled']; protected $rules = [ 'server.name' => 'required', @@ -49,9 +49,10 @@ class Form extends Component $this->wildcard_domain = $this->server->settings->wildcard_domain; $this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage; } - public function serverRefresh($install = true) + public function serverInstalled() { - $this->validateServer($install); + $this->server->refresh(); + $this->server->settings->refresh(); } public function instantSave() { @@ -64,13 +65,6 @@ class Form extends Component return handleError($e, $this); } } - public function installDocker() - { - $this->dispatch('installDocker'); - $this->dockerInstallationStarted = true; - $activity = InstallDocker::run($this->server); - $this->dispatch('newMonitorActivity', $activity->id); - } public function checkLocalhostConnection() { $uptime = $this->server->validateConnection(); @@ -80,48 +74,13 @@ class Form extends Component $this->server->settings->is_usable = true; $this->server->settings->save(); } else { - $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection.

Check this documentation for further help.'); + $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.'); return; } } public function validateServer($install = true) { - try { - $uptime = $this->server->validateConnection(); - if (!$uptime) { - $install && $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection.

Check this documentation for further help.'); - return; - } - $supported_os_type = $this->server->validateOS(); - if (!$supported_os_type) { - $install && $this->dispatch('error', 'Server OS type is not supported for automated installation. Please install Docker manually before continuing: documentation.'); - return; - } - $dockerInstalled = $this->server->validateDockerEngine(); - if ($dockerInstalled) { - $install && $this->dispatch('success', 'Docker Engine is installed.
Checking version.'); - } else { - $install && $this->installDocker(); - return; - } - $dockerVersion = $this->server->validateDockerEngineVersion(); - if ($dockerVersion) { - $install && $this->dispatch('success', 'Docker Engine version is 22+.'); - } else { - $install && $this->installDocker(); - return; - } - if ($this->server->isSwarm()) { - $swarmInstalled = $this->server->validateDockerSwarm(); - if ($swarmInstalled) { - $install && $this->dispatch('success', 'Docker Swarm is initiated.'); - } - } - } catch (\Throwable $e) { - return handleError($e, $this); - } finally { - $this->dispatch('proxyStatusUpdated'); - } + $this->dispatch('validateServer', $install); } public function submit() diff --git a/app/Livewire/Server/Proxy/Deploy.php b/app/Livewire/Server/Proxy/Deploy.php index 8349325d0..72d0b3884 100644 --- a/app/Livewire/Server/Proxy/Deploy.php +++ b/app/Livewire/Server/Proxy/Deploy.php @@ -71,7 +71,7 @@ class Deploy extends Component { try { $activity = StartProxy::run($this->server); - $this->dispatch('newMonitorActivity', $activity->id, ProxyStatusChanged::class); + $this->dispatch('activityMonitor', $activity->id, ProxyStatusChanged::class); } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Server/Proxy/Status.php b/app/Livewire/Server/Proxy/Status.php index 04dd1f97e..a41994c8f 100644 --- a/app/Livewire/Server/Proxy/Status.php +++ b/app/Livewire/Server/Proxy/Status.php @@ -12,10 +12,8 @@ class Status extends Component public Server $server; public bool $polling = false; public int $numberOfPolls = 0; - protected $listeners = ['proxyStatusUpdated', 'startProxyPolling']; - public function mount() { - } + public function startProxyPolling() { $this->checkProxy(); diff --git a/app/Livewire/Server/Show.php b/app/Livewire/Server/Show.php index 31abe8910..92449820c 100644 --- a/app/Livewire/Server/Show.php +++ b/app/Livewire/Server/Show.php @@ -11,7 +11,7 @@ class Show extends Component use AuthorizesRequests; public ?Server $server = null; public $parameters = []; - protected $listeners = ['proxyStatusUpdated' => '$refresh']; + protected $listeners = ['serverInstalled' => '$refresh']; public function mount() { $this->parameters = get_route_parameters(); diff --git a/app/Livewire/Server/ValidateAndInstall.php b/app/Livewire/Server/ValidateAndInstall.php new file mode 100644 index 000000000..c93f51735 --- /dev/null +++ b/app/Livewire/Server/ValidateAndInstall.php @@ -0,0 +1,100 @@ +install = $install; + $this->uptime = null; + $this->supported_os_type = null; + $this->docker_installed = null; + $this->docker_version = null; + + try { + $this->validateConnection(); + $this->validateOS(); + $this->validateDockerEngine(); + + if ($this->server->isSwarm()) { + $swarmInstalled = $this->server->validateDockerSwarm(); + if ($swarmInstalled) { + $this->dispatch('success', 'Docker Swarm is initiated.'); + } + } + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function validateConnection() + { + $this->uptime = $this->server->validateConnection(); + if (!$this->uptime) { + $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.'); + return; + } + } + public function validateOS() + { + $this->supported_os_type = $this->server->validateOS(); + if (!$this->supported_os_type) { + $this->dispatch('error', 'Server OS type is not supported.', 'Please install Docker manually before continuing: documentation.'); + return; + } + } + public function validateDockerEngine() + { + $this->docker_installed = $this->server->validateDockerEngine(); + if (!$this->docker_installed) { + if ($this->install) { + ray($this->number_of_tries, $this->max_tries); + if ($this->number_of_tries == $this->max_tries) { + $this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: documentation.'; + return; + } else { + $activity = $this->server->installDocker(); + $this->number_of_tries++; + $this->dispatch('newActivityMonitor', $activity->id, 'validateDockerEngine'); + return; + + } + } else { + $this->dispatch('error', 'Docker Engine is not installed.', 'Please install Docker manually before continuing: documentation.'); + return; + } + } else { + $this->validateDockerVersion(); + } + } + public function validateDockerVersion() + { + $this->docker_version = $this->server->validateDockerEngineVersion(); + if ($this->docker_version) { + $this->dispatch('serverInstalled'); + $this->dispatch('success', 'Server validated successfully.'); + } else { + $this->dispatch('error', 'Docker Engine version is not 22+.', 'Please install Docker manually before continuing: documentation.'); + return; + } + } + public function render() + { + return view('livewire.server.validate-and-install'); + } +} diff --git a/app/Models/Server.php b/app/Models/Server.php index 972751083..b3f4abc61 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Actions\Server\InstallDocker; use App\Enums\ProxyStatus; use App\Enums\ProxyTypes; use App\Notifications\Server\Revived; @@ -411,6 +412,11 @@ class Server extends BaseModel return true; } + public function installDocker() + { + $activity = InstallDocker::run($this); + return $activity; + } public function validateDockerEngine($throwError = false) { $dockerBinary = instant_remote_process(["command -v docker"], $this, false); diff --git a/bootstrap/helpers/applications.php b/bootstrap/helpers/applications.php index 5e0040872..120c92ddd 100644 --- a/bootstrap/helpers/applications.php +++ b/bootstrap/helpers/applications.php @@ -5,20 +5,31 @@ use App\Jobs\ApplicationDeploymentJob; use App\Models\Application; use App\Models\ApplicationDeploymentQueue; use App\Models\Server; +use App\Models\StandaloneDocker; use Spatie\Url\Url; -function queue_application_deployment(Application $application, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null) +function queue_application_deployment(Application $application, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, Server $server = null, StandaloneDocker $destination = null) { $application_id = $application->id; $deployment_link = Url::fromString($application->link() . "/deployment/{$deployment_uuid}"); $deployment_url = $deployment_link->getPath(); $server_id = $application->destination->server->id; $server_name = $application->destination->server->name; + $destination_id = $application->destination->id; + + if ($server) { + $server_id = $server->id; + $server_name = $server->name; + } + if ($destination) { + $destination_id = $destination->id; + } $deployment = ApplicationDeploymentQueue::create([ 'application_id' => $application_id, 'application_name' => $application->name, 'server_id' => $server_id, 'server_name' => $server_name, + 'destination_id' => $destination_id, 'deployment_uuid' => $deployment_uuid, 'deployment_url' => $deployment_url, 'pull_request_id' => $pull_request_id, @@ -29,16 +40,31 @@ function queue_application_deployment(Application $application, string $deployme 'git_type' => $git_type ]); - if (next_queuable($server_id, $application_id)) { - $deployment->update([ - 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, - ]); - dispatch(new ApplicationDeploymentJob( - application_deployment_queue_id: $deployment->id, - )); - } + // if ($no_questions_asked) { + // $deployment->update([ + // 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, + // ]); + // dispatch(new ApplicationDeploymentJob( + // application_deployment_queue_id: $deployment->id, + // )); + // } else if (next_queuable($server_id, $application_id)) { + // $deployment->update([ + // 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, + // ]); + // dispatch(new ApplicationDeploymentJob( + // application_deployment_queue_id: $deployment->id, + // )); + // } +} +function force_start_deployment(ApplicationDeploymentQueue $deployment) +{ + $deployment->update([ + 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, + ]); + dispatch(new ApplicationDeploymentJob( + application_deployment_queue_id: $deployment->id, + )); } - function queue_next_deployment(Application $application) { $server_id = $application->destination->server_id; diff --git a/database/migrations/2024_02_05_105215_add_destination_to_app_deployments.php b/database/migrations/2024_02_05_105215_add_destination_to_app_deployments.php new file mode 100644 index 000000000..29f43dd3f --- /dev/null +++ b/database/migrations/2024_02_05_105215_add_destination_to_app_deployments.php @@ -0,0 +1,28 @@ +string('destination_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('application_deployment_queues', function (Blueprint $table) { + $table->dropColumn('destination_id'); + }); + } +}; diff --git a/resources/views/components/pricing-plans.blade.php b/resources/views/components/pricing-plans.blade.php index 2c5844e6c..3773e2770 100644 --- a/resources/views/components/pricing-plans.blade.php +++ b/resources/views/components/pricing-plans.blade.php @@ -258,7 +258,8 @@
Need official support for your self-hosted instance? - Contact + Contact Us
diff --git a/resources/views/components/slide-over.blade.php b/resources/views/components/slide-over.blade.php index bf68f9413..a77e71507 100644 --- a/resources/views/components/slide-over.blade.php +++ b/resources/views/components/slide-over.blade.php @@ -1,31 +1,37 @@ +@props(['closeWithX' => 'false', 'fullScreen' => 'false'])
{{ $slot }}