From b57a439b766fc1b178fb6d34cd9a86cd98f2fad3 Mon Sep 17 00:00:00 2001 From: David Buday Date: Fri, 8 Nov 2024 13:31:30 +0100 Subject: [PATCH] chore: add registry auth to docker image apps --- app/Jobs/ApplicationDeploymentJob.php | 63 ++++++++++++++++--- app/Livewire/Project/New/DockerImage.php | 41 +++++++----- ...dd_registry_auth_to_applications_table.php | 23 +++++++ .../project/new/docker-image.blade.php | 14 ++++- 4 files changed, 116 insertions(+), 25 deletions(-) create mode 100644 database/migrations/2024_11_08_084443_add_registry_auth_to_applications_table.php diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 5ceed332a..bab7925c0 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -381,17 +381,35 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue private function deploy_dockerimage_buildpack() { - $this->dockerImage = $this->application->docker_registry_image_name; - if (str($this->application->docker_registry_image_tag)->isEmpty()) { - $this->dockerImageTag = 'latest'; - } else { - $this->dockerImageTag = $this->application->docker_registry_image_tag; + try { + $didLogin = $this->handleRegistryAuth(); + + // Pull the image + $this->execute_remote_command([ + "docker pull {$this->application->image}", + ]); + + // Logout if we logged in + if ($didLogin) { + $this->application_deployment_queue->addLogEntry('Logging out from registry...'); + $this->execute_remote_command([ + 'docker logout', + 'hidden' => true + ]); + } + + // Continue with the rest of the deployment... + } catch (Exception $e) { + // Make sure to logout even if pull fails + if ($didLogin ?? false) { + $this->execute_remote_command([ + 'docker logout', + 'hidden' => true + ]); + } + $this->application_deployment_queue->addLogEntry('Deployment error: ' . $e->getMessage(), 'stderr'); + throw $e; } - $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}."); - $this->generate_image_names(); - $this->prepare_builder_image(); - $this->generate_compose_file(); - $this->rolling_update(); } private function deploy_docker_compose_buildpack() @@ -2444,4 +2462,29 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); } } } + + private function handleRegistryAuth() +{ + if ($this->application->registry_username && $this->application->registry_token) { + try { + $username = escapeshellarg($this->application->registry_username); + $token = escapeshellarg(decrypt($this->application->registry_token)); + + $this->application_deployment_queue->addLogEntry('Attempting to log into registry...'); + + $command = "echo {$token} | docker login -u {$username} --password-stdin > /dev/null"; + + $this->execute_remote_command([ + $command, + 'hidden' => true, + ]); + + return true; + } catch (Exception $e) { + $this->application_deployment_queue->addLogEntry('Registry authentication error: ' . $e->getMessage(), 'stderr'); + throw $e; + } + } + return false; +} } diff --git a/app/Livewire/Project/New/DockerImage.php b/app/Livewire/Project/New/DockerImage.php index 417fb2ea0..af7c62dd8 100644 --- a/app/Livewire/Project/New/DockerImage.php +++ b/app/Livewire/Project/New/DockerImage.php @@ -12,11 +12,17 @@ use Visus\Cuid2\Cuid2; class DockerImage extends Component { public string $dockerImage = ''; - + public ?string $registryUsername = null; + public ?string $registryToken = null; public array $parameters; - public array $query; + protected $rules = [ + 'dockerImage' => 'required|string', + 'registryUsername' => 'nullable|string', + 'registryToken' => 'nullable|string', + ]; + public function mount() { $this->parameters = get_route_parameters(); @@ -27,25 +33,30 @@ class DockerImage extends Component { $this->validate([ 'dockerImage' => 'required', + 'registryUsername' => 'required_with:registryToken', + 'registryToken' => 'required_with:registryUsername', ]); + $image = str($this->dockerImage)->before(':'); - if (str($this->dockerImage)->contains(':')) { - $tag = str($this->dockerImage)->after(':'); - } else { - $tag = 'latest'; - } + $tag = str($this->dockerImage)->contains(':') ? + str($this->dockerImage)->after(':') : + 'latest'; + $destination_uuid = $this->query['destination']; - $destination = StandaloneDocker::where('uuid', $destination_uuid)->first(); - if (! $destination) { - $destination = SwarmDocker::where('uuid', $destination_uuid)->first(); - } - if (! $destination) { - throw new \Exception('Destination not found. What?!'); + $destination = StandaloneDocker::where('uuid', $destination_uuid)->first() + ?? SwarmDocker::where('uuid', $destination_uuid)->first(); + + if (!$destination) { + throw new \Exception('Destination not found.'); } $destination_class = $destination->getMorphClass(); $project = Project::where('uuid', $this->parameters['project_uuid'])->first(); - $environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first(); + $environment = $project->load(['environments']) + ->environments + ->where('name', $this->parameters['environment_name']) + ->first(); + $application = Application::create([ 'name' => 'docker-image-'.new Cuid2, 'repository_project_id' => 0, @@ -59,6 +70,8 @@ class DockerImage extends Component 'destination_id' => $destination->id, 'destination_type' => $destination_class, 'health_check_enabled' => false, + 'registry_username' => $this->registryUsername, + 'registry_token' => $this->registryToken ? encrypt($this->registryToken) : null, ]); $fqdn = generateFqdn($destination->server, $application->uuid); diff --git a/database/migrations/2024_11_08_084443_add_registry_auth_to_applications_table.php b/database/migrations/2024_11_08_084443_add_registry_auth_to_applications_table.php new file mode 100644 index 000000000..d3800b4a9 --- /dev/null +++ b/database/migrations/2024_11_08_084443_add_registry_auth_to_applications_table.php @@ -0,0 +1,23 @@ +string('registry_username')->nullable(); + $table->text('registry_token')->nullable(); + }); + } + + public function down(): void + { + Schema::table('applications', function (Blueprint $table) { + $table->dropColumn('registry_username'); + $table->dropColumn('registry_token'); + }); + } +}; \ No newline at end of file diff --git a/resources/views/livewire/project/new/docker-image.blade.php b/resources/views/livewire/project/new/docker-image.blade.php index 4cc86710a..5bc7df060 100644 --- a/resources/views/livewire/project/new/docker-image.blade.php +++ b/resources/views/livewire/project/new/docker-image.blade.php @@ -6,6 +6,18 @@

Docker Image

Save - + + +

Registry Authentication

+
+ + + +