From 46a543441f42756d0194960a017e99595f12ffc4 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 14 Apr 2023 21:09:38 +0200 Subject: [PATCH] logs ot fixes in executeNow. errors handled properly, etc. --- .gitignore | 3 + .../RemoteProcess/RunRemoteProcess.php | 41 ++++--- app/Http/Livewire/ApplicationForm.php | 29 +++++ app/Http/Livewire/DeployApplication.php | 13 +- app/Jobs/DeployApplicationJob.php | 114 ++++++++++++------ docker/dev-ssu/Dockerfile | 2 +- resources/css/app.css | 4 +- .../views/livewire/application-form.blade.php | 15 +++ resources/views/project/application.blade.php | 4 +- 9 files changed, 157 insertions(+), 68 deletions(-) create mode 100644 app/Http/Livewire/ApplicationForm.php create mode 100644 resources/views/livewire/application-form.blade.php diff --git a/.gitignore b/.gitignore index 1b23aac6f..67c5e7aa9 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ yarn-error.log /.npm /.bash_history /_volumes + +.lesshst +psysh_history diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index a243ee5c6..41e86b60d 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -16,7 +16,9 @@ class RunRemoteProcess public bool $hideFromOutput; - public bool $setStatus; + public bool $isFinished; + + public bool $ignoreErrors; protected $timeStart; @@ -31,7 +33,7 @@ class RunRemoteProcess /** * Create a new job instance. */ - public function __construct(Activity $activity, bool $hideFromOutput = false, bool $setStatus = false) + public function __construct(Activity $activity, bool $hideFromOutput = false, bool $isFinished = false, bool $ignoreErrors = false) { if ($activity->getExtraProperty('type') !== ActivityTypes::REMOTE_PROCESS->value && $activity->getExtraProperty('type') !== ActivityTypes::DEPLOYMENT->value) { @@ -40,36 +42,41 @@ class RunRemoteProcess $this->activity = $activity; $this->hideFromOutput = $hideFromOutput; - $this->setStatus = $setStatus; + $this->isFinished = $isFinished; + $this->ignoreErrors = $ignoreErrors; } public function __invoke(): ProcessResult { - $this->activity->properties = $this->activity->properties->merge([ - 'status' => ProcessStatus::IN_PROGRESS, - ]); $this->timeStart = hrtime(true); + $status = ProcessStatus::IN_PROGRESS; + $processResult = Process::run($this->getCommand(), $this->handleOutput(...)); - $status = $processResult->exitCode() != 0 ? ProcessStatus::ERROR : ($this->setStatus ? ProcessStatus::FINISHED : null); + if ($this->activity->properties->get('status') === ProcessStatus::ERROR->value) { + $status = ProcessStatus::ERROR; + } else { + if (($processResult->exitCode() == 0 && $this->isFinished) || $this->activity->properties->get('status') === ProcessStatus::FINISHED->value) { + $status = ProcessStatus::FINISHED; + } + if ($processResult->exitCode() != 0 && !$this->ignoreErrors) { + $status = ProcessStatus::ERROR; + } + } $this->activity->properties = $this->activity->properties->merge([ 'exitCode' => $processResult->exitCode(), - 'stdout' => $this->hideFromOutput || $processResult->output(), + 'stdout' => $processResult->output(), 'stderr' => $processResult->errorOutput(), + 'status' => $status->value, ]); - if (isset($status)) { - $this->activity->properties = $this->activity->properties->merge([ - 'status' => $status->value, - ]); - } - $this->activity->save(); - if ($processResult->exitCode() != 0 && $processResult->errorOutput()) { - throw new \RuntimeException('Remote command failed'); + if ($processResult->exitCode() != 0 && !$this->ignoreErrors) { + throw new \RuntimeException($processResult->errorOutput()); } + return $processResult; } @@ -98,9 +105,7 @@ class RunRemoteProcess if ($this->hideFromOutput) { return; } - $this->currentTime = $this->elapsedTime(); - $this->activity->description = $this->encodeOutput($type, $output); if ($this->isAfterLastThrottle()) { diff --git a/app/Http/Livewire/ApplicationForm.php b/app/Http/Livewire/ApplicationForm.php new file mode 100644 index 000000000..80c319a25 --- /dev/null +++ b/app/Http/Livewire/ApplicationForm.php @@ -0,0 +1,29 @@ +application = Application::find($this->applicationId); + $this->fill([ + 'name' => $this->application->name, + 'fqdn' => $this->application->fqdn, + 'git_repository' => $this->application->git_repository, + 'git_branch' => $this->application->git_branch, + 'git_commit_sha' => $this->application->git_commit_sha, + ]); + } + +} diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index a18d85f6b..8531ed7db 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -9,7 +9,7 @@ use Visus\Cuid2\Cuid2; class DeployApplication extends Component { - public string $application_uuid; + public string $applicationId; public $activity; public $status; public Application $application; @@ -19,10 +19,9 @@ class DeployApplication extends Component protected array $command = []; protected $source; - public function mount($application_uuid) + public function mount($applicationId) { - $this->application_uuid = $application_uuid; - $this->application = Application::where('uuid', $this->application_uuid)->first(); + $this->application = Application::find($applicationId)->first(); $this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first(); } @@ -39,7 +38,7 @@ class DeployApplication extends Component dispatch(new DeployApplicationJob( deployment_uuid: $this->deployment_uuid, - application_uuid: $this->application_uuid, + application_uuid: $this->application->uuid, )); $currentUrl = url()->previous(); @@ -49,13 +48,13 @@ class DeployApplication extends Component public function stop() { - runRemoteCommandSync($this->destination->server, ["docker stop -t 0 {$this->application_uuid} >/dev/null 2>&1"]); + runRemoteCommandSync($this->destination->server, ["docker stop -t 0 {$this->application->uuid} >/dev/null 2>&1"]); $this->application->status = 'stopped'; $this->application->save(); } public function kill() { - runRemoteCommandSync($this->destination->server, ["docker rm -f {$this->application_uuid}"]); + runRemoteCommandSync($this->destination->server, ["docker rm -f {$this->application->uuid}"]); if ($this->application->status != 'exited') { $this->application->status = 'exited'; $this->application->save(); diff --git a/app/Jobs/DeployApplicationJob.php b/app/Jobs/DeployApplicationJob.php index 86a998d3b..50ebf847e 100644 --- a/app/Jobs/DeployApplicationJob.php +++ b/app/Jobs/DeployApplicationJob.php @@ -75,38 +75,39 @@ class DeployApplicationJob implements ShouldQueue */ public function handle(): void { - $coolify_instance_settings = CoolifyInstanceSettings::find(1); - $this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first(); + try { + $coolify_instance_settings = CoolifyInstanceSettings::find(1); + $this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first(); - // Get Wildcard Domain - $project_wildcard_domain = data_get($this->application, 'environment.project.settings.wildcard_domain'); - $global_wildcard_domain = data_get($coolify_instance_settings, 'wildcard_domain'); - $wildcard_domain = $project_wildcard_domain ?? $global_wildcard_domain ?? null; + // Get Wildcard Domain + $project_wildcard_domain = data_get($this->application, 'environment.project.settings.wildcard_domain'); + $global_wildcard_domain = data_get($coolify_instance_settings, 'wildcard_domain'); + $wildcard_domain = $project_wildcard_domain ?? $global_wildcard_domain ?? null; - // Set wildcard domain - if (!$this->application->settings->is_bot && !$this->application->fqdn && $wildcard_domain) { - $this->application->fqdn = $this->application->uuid . '.' . $wildcard_domain; - $this->application->save(); - } - $this->workdir = "/artifacts/{$this->deployment_uuid}"; + // Set wildcard domain + if (!$this->application->settings->is_bot && !$this->application->fqdn && $wildcard_domain) { + $this->application->fqdn = $this->application->uuid . '.' . $wildcard_domain; + $this->application->save(); + } + $this->workdir = "/artifacts/{$this->deployment_uuid}"; - $this->executeNow([ - "docker inspect {$this->application->uuid} >/dev/null 2>&1", - "echo $?" - ], 'stopped_container_check', hideFromOutput: true); + // $this->executeNow([ + // "docker inspect {$this->application->uuid} >/dev/null 2>&1", + // "echo $?" + // ], 'stopped_container_check', hideFromOutput: true, ignoreErrors: true); - if ($this->activity->properties->get('stopped_container_check') == 0) { - $this->executeNow([ - "echo -n 'Container {$this->application->uuid} was stopped, starting it...'" - ]); - $this->executeNow([ - "docker start {$this->application->uuid}" - ], hideFromOutput: true); + // if ($this->activity->properties->get('stopped_container_check') == 0) { + // $this->executeNow([ + // "echo 'Application is already available. Starting it...'" + // ]); + // $this->executeNow([ + // "docker start {$this->application->uuid}" + // ], hideFromOutput: true); - $this->executeNow([ - "echo 'Started! 🎉'" - ], setStatus: true); - } else { + // $this->executeNow([ + // "echo 'Done. 🎉'", + // ], isFinished: true); + // } else { // Pull builder image $this->executeNow([ "echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}...'", @@ -132,6 +133,26 @@ class DeployApplicationJob implements ShouldQueue $this->executeNow([$this->execute_in_builder("cd {$this->workdir} && git rev-parse HEAD")], 'commit_sha', hideFromOutput: true); $this->git_commit = $this->activity->properties->get('commit_sha'); + $this->executeNow([ + "docker inspect {$this->application->uuid} --format '{{json .Config.Image}}' 2>&1", + ], 'stopped_container_image', hideFromOutput: true, ignoreErrors: true); + $image = $this->activity->properties->get('stopped_container_image'); + if (isset($image)) { + $image = explode(':', str_replace('"', '', $image))[1]; + if ($image == $this->git_commit) { + $this->executeNow([ + "echo 'Application found locally with the same Git Commit SHA. Starting it...'" + ]); + $this->executeNow([ + "docker start {$this->application->uuid}" + ], hideFromOutput: true); + + $this->executeNow([ + "echo 'Done. 🎉'", + ], isFinished: true); + return; + } + } $this->executeNow([ $this->execute_in_builder("rm -fr {$this->workdir}/.git") ], hideFromOutput: true); @@ -173,14 +194,21 @@ class DeployApplicationJob implements ShouldQueue $this->executeNow([ "echo 'Done. 🎉'", - "docker stop -t 0 {$this->deployment_uuid} >/dev/null" - ], setStatus: true); + ], isFinished: true); + // Saving docker-compose.yml + Storage::disk('deployments')->put(Str::kebab($this->application->name) . '/docker-compose.yml', $docker_compose); + // } + + } catch (\Exception $e) { + $this->executeNow([ + "echo 'Oops something is not okay, are you okay? 😢'", + "echo '\n\n{$e->getMessage()}'", + ]); + throw new \Exception('Deployment finished'); + } finally { + $this->executeNow(["docker rm -f {$this->deployment_uuid} >/dev/null 2>&1"], hideFromOutput: true); + dispatch(new ContainerStatusJob($this->application_uuid)); } - - dispatch(new ContainerStatusJob($this->application_uuid)); - - // Saving docker-compose.yml - Storage::disk('deployments')->put(Str::kebab($this->application->name) . '/docker-compose.yml', $docker_compose); } private function execute_in_builder(string $command) @@ -314,8 +342,14 @@ class DeployApplicationJob implements ShouldQueue return $labels; } - private function executeNow(array|Collection $command, string $propertyName = null, bool $hideFromOutput = false, $setStatus = false, bool $isDebuggable = false) - { + private function executeNow( + array|Collection $command, + string $propertyName = null, + bool $isFinished = false, + bool $hideFromOutput = false, + bool $isDebuggable = false, + bool $ignoreErrors = false + ) { static::$batch_counter++; if ($command instanceof Collection) { @@ -334,16 +368,20 @@ class DeployApplicationJob implements ShouldQueue $remoteProcess = resolve(RunRemoteProcess::class, [ 'activity' => $this->activity, 'hideFromOutput' => $hideFromOutput, - 'setStatus' => $setStatus, + 'isFinished' => $isFinished, + 'ignoreErrors' => $ignoreErrors, ]); $result = $remoteProcess(); - if ($propertyName) { $this->activity->properties = $this->activity->properties->merge([ $propertyName => trim($result->output()), ]); $this->activity->save(); } + + if ($result->exitCode() != 0 && $result->errorOutput() && !$ignoreErrors) { + throw new \RuntimeException($result->errorOutput()); + } } private function gitImport() { diff --git a/docker/dev-ssu/Dockerfile b/docker/dev-ssu/Dockerfile index 4b0c99f6a..c90e53d08 100644 --- a/docker/dev-ssu/Dockerfile +++ b/docker/dev-ssu/Dockerfile @@ -1,6 +1,6 @@ FROM serversideup/php:8.2-fpm-nginx ARG POSTGRES_VERSION=15 -RUN apt-get update && apt-get install -y php-pgsql openssh-client git git-lfs +RUN apt-get update && apt-get install -y php-pgsql openssh-client git git-lfs postgresql-client RUN apt-get -y autoremove \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* diff --git a/resources/css/app.css b/resources/css/app.css index d6d88bf25..dc83d5cf5 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,3 +1,3 @@ -/* @tailwind base; +/* @tailwind base; */ @tailwind components; -@tailwind utilities; */ +@tailwind utilities; diff --git a/resources/views/livewire/application-form.blade.php b/resources/views/livewire/application-form.blade.php new file mode 100644 index 000000000..e2770fbea --- /dev/null +++ b/resources/views/livewire/application-form.blade.php @@ -0,0 +1,15 @@ +
+
+ + + + + + + + + + + +
+
diff --git a/resources/views/project/application.blade.php b/resources/views/project/application.blade.php index 716fb3765..679ab14d9 100644 --- a/resources/views/project/application.blade.php +++ b/resources/views/project/application.blade.php @@ -1,7 +1,7 @@

Application

-

Name: {{ $application->name }}

- + +

Deployments

@foreach ($deployments as $deployment)