From 42de7ec0f03da4d9d7c5840e00366e0b73dbadb3 Mon Sep 17 00:00:00 2001 From: David Buday Date: Mon, 11 Nov 2024 15:35:25 +0100 Subject: [PATCH] chore: database, navigation images --- app/Jobs/ApplicationDeploymentJob.php | 47 ++++++----- app/Livewire/Images/Images/Create.php | 0 app/Livewire/Images/Images/Index.php | 13 +++ app/Livewire/Images/Registry/Create.php | 50 +++++++++++ app/Livewire/Images/Registry/Index.php | 18 ++++ app/Livewire/Images/Registry/Show.php | 82 +++++++++++++++++++ app/Livewire/Project/Application/General.php | 4 +- app/Livewire/Project/New/DockerImage.php | 9 +- app/Models/Application.php | 2 +- .../{Registry.php => DockerRegistry.php} | 14 +--- ...4_11_10_203115_create_registries_table.php | 1 - .../views/components/images/navbar.blade.php | 14 ++++ resources/views/components/navbar.blade.php | 14 +++- .../livewire/images/images/index.blade.php | 16 ++++ .../livewire/images/registry/create.blade.php | 23 ++++++ .../livewire/images/registry/index.blade.php | 18 ++++ .../livewire/images/registry/show.blade.php | 32 ++++++++ .../project/application/general.blade.php | 4 +- .../project/new/docker-image.blade.php | 22 ++--- routes/web.php | 7 +- 20 files changed, 332 insertions(+), 58 deletions(-) create mode 100644 app/Livewire/Images/Images/Create.php create mode 100644 app/Livewire/Images/Images/Index.php create mode 100644 app/Livewire/Images/Registry/Create.php create mode 100644 app/Livewire/Images/Registry/Index.php create mode 100644 app/Livewire/Images/Registry/Show.php rename app/Models/{Registry.php => DockerRegistry.php} (72%) create mode 100644 resources/views/components/images/navbar.blade.php create mode 100644 resources/views/livewire/images/images/index.blade.php create mode 100644 resources/views/livewire/images/registry/create.blade.php create mode 100644 resources/views/livewire/images/registry/index.blade.php create mode 100644 resources/views/livewire/images/registry/show.blade.php diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index e480a6fc7..957817813 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -9,6 +9,7 @@ use App\Events\ApplicationStatusChanged; use App\Models\Application; use App\Models\ApplicationDeploymentQueue; use App\Models\ApplicationPreview; +use App\Models\DockerRegistry; use App\Models\EnvironmentVariable; use App\Models\GithubApp; use App\Models\GitlabApp; @@ -383,6 +384,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue private function deploy_dockerimage_buildpack() { + $useCustomRegistry = $this->application->docker_use_custom_registry; try { // setup $this->dockerImage = $this->application->docker_registry_image_name; @@ -394,7 +396,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}."); // login if use custom registry - if ($this->application->docker_use_custom_registry) { + if ($useCustomRegistry) { $this->handleRegistryAuth(); } @@ -402,25 +404,16 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->prepare_builder_image(); $this->generate_compose_file(); $this->rolling_update(); - - // Logout if use custom registry - if ($this->application->docker_use_custom_registry) { + } catch (Exception $e) { + throw $e; + } finally { + if ($useCustomRegistry) { $this->application_deployment_queue->addLogEntry('Logging out from registry...'); $this->execute_remote_command([ 'docker logout', 'hidden' => true ]); } - } catch (Exception $e) { - // Make sure to logout even if build/pull fails - if ($this->application->docker_use_custom_registry) { - $this->execute_remote_command([ - 'docker logout', - 'hidden' => true - ]); - } - //$this->application_deployment_queue->addLogEntry('Deployment error: ' . $e->getMessage(), 'stderr'); - throw $e; } } @@ -2477,13 +2470,27 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); private function handleRegistryAuth() { - //$registry = $this->$application->registry; ?? - //$token = escapeshellarg($registry->token); ... - $token = escapeshellarg('test'); - $url = escapeshellarg('test'); - $username = escapeshellarg('test'); + $registry = DockerRegistry::find($this->application->docker_registry_id); + if (!$registry) { + throw new Exception('Registry not found.'); + } + + $token = escapeshellarg($registry->token); + $username = escapeshellarg($registry->username); + + // Handle different registry types + $url = match ($registry->type) { + 'docker_hub' => '', // Docker Hub doesn't need URL specified + 'custom' => escapeshellarg($registry->url), + default => escapeshellarg($registry->url) + }; + $this->application_deployment_queue->addLogEntry('Attempting to log into registry...'); - $command = "echo {{secrets.token}} | docker login {$url} -u {$username} --password-stdin"; + + // Build login command based on registry type + $command = $registry->type === 'docker_hub' + ? "echo {{secrets.token}} | docker login -u {$username} --password-stdin" + : "echo {{secrets.token}} | docker login {$url} -u {$username} --password-stdin"; $this->execute_remote_command( [ diff --git a/app/Livewire/Images/Images/Create.php b/app/Livewire/Images/Images/Create.php new file mode 100644 index 000000000..e69de29bb diff --git a/app/Livewire/Images/Images/Index.php b/app/Livewire/Images/Images/Index.php new file mode 100644 index 000000000..4126ebddf --- /dev/null +++ b/app/Livewire/Images/Images/Index.php @@ -0,0 +1,13 @@ + 'required|string|max:255', + 'type' => 'required|string', + 'url' => 'nullable|string|max:255', + 'username' => 'nullable|string|max:255', + 'token' => 'nullable|string', + ]; + + public function getRegistryTypesProperty() + { + return DockerRegistry::getTypes(); + } + + public function submit() + { + $this->validate(); + + DockerRegistry::create([ + 'name' => $this->name, + 'type' => $this->type, + 'url' => $this->type === 'custom' ? $this->url : 'docker.io', + 'username' => $this->username, + 'token' => $this->token, + ]); + + $this->dispatch('registry-added'); + $this->dispatch('success', 'Registry added successfully.'); + $this->dispatch('close-modal'); + } + + public function render() + { + return view('livewire.images.registry.create'); + } +} diff --git a/app/Livewire/Images/Registry/Index.php b/app/Livewire/Images/Registry/Index.php new file mode 100644 index 000000000..f612ebee2 --- /dev/null +++ b/app/Livewire/Images/Registry/Index.php @@ -0,0 +1,18 @@ + '$refresh']; + + public function render() + { + return view('livewire.images.registry.index', [ + 'registries' => DockerRegistry::all() + ]); + } +} diff --git a/app/Livewire/Images/Registry/Show.php b/app/Livewire/Images/Registry/Show.php new file mode 100644 index 000000000..90069f571 --- /dev/null +++ b/app/Livewire/Images/Registry/Show.php @@ -0,0 +1,82 @@ + 'required|string|max:255', + 'type' => 'required|string', + 'url' => 'nullable|string|max:255', + 'username' => 'nullable|string|max:255', + 'token' => 'nullable|string', + ]; + + public function mount(DockerRegistry $registry) + { + $this->registry = $registry; + $this->name = $registry->name; + $this->type = $registry->type; + $this->url = $registry->url; + $this->username = $registry->username; + $this->token = $registry->token; + } + + public function getRegistryTypesProperty() + { + return DockerRegistry::getTypes(); + } + + public function updateRegistry() + { + $this->validate(); + + $this->registry->update([ + 'name' => $this->name, + 'type' => $this->type, + 'url' => $this->type === 'custom' ? $this->url : 'docker.io', + 'username' => $this->username, + 'token' => $this->token, + ]); + + $this->dispatch('success', 'Registry updated successfully.'); + } + + public function delete() + { + // Update all applications using this registry + $this->registry->applications() + ->update([ + 'docker_registry_id' => null, + 'docker_use_custom_registry' => false + ]); + + $this->registry->delete(); + $this->dispatch('registry-added'); + $this->dispatch('success', 'Registry deleted successfully.'); + } + + public function render() + { + return view('livewire.images.registry.show'); + } + + public function getIsFormDirtyProperty(): bool + { + return $this->name !== $this->registry->name + || $this->type !== $this->registry->type + || $this->url !== $this->registry->url + || $this->username !== $this->registry->username + || $this->token !== $this->registry->token; + } +} diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index d1e905dd9..72829c8de 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -4,7 +4,7 @@ namespace App\Livewire\Project\Application; use App\Actions\Application\GenerateConfig; use App\Models\Application; -use App\Models\Registry; +use App\Models\DockerRegistry; use Illuminate\Support\Collection; use Livewire\Component; use Spatie\Url\Url; @@ -444,7 +444,7 @@ class General extends Component public function render() { return view('livewire.project.application.general', [ - 'registries' => Registry::all(), + 'registries' => DockerRegistry::all(), ]); } } diff --git a/app/Livewire/Project/New/DockerImage.php b/app/Livewire/Project/New/DockerImage.php index 936e22b5e..7833a11b9 100644 --- a/app/Livewire/Project/New/DockerImage.php +++ b/app/Livewire/Project/New/DockerImage.php @@ -3,7 +3,7 @@ namespace App\Livewire\Project\New; use App\Models\Application; -use App\Models\Registry; +use App\Models\DockerRegistry; use App\Models\Project; use App\Models\StandaloneDocker; use App\Models\SwarmDocker; @@ -20,8 +20,7 @@ class DockerImage extends Component protected $rules = [ 'dockerImage' => 'required|string', - 'selectedRegistry' => 'nullable|required_if:useCustomRegistry,true', - 'useCustomRegistry' => 'boolean' + 'selectedRegistry' => 'required_if:useCustomRegistry,true|nullable|exists:docker_registries,id' ]; public function mount() @@ -62,7 +61,7 @@ class DockerImage extends Component 'docker_registry_image_name' => $image, 'docker_registry_image_tag' => $tag, 'docker_use_custom_registry' => $this->useCustomRegistry, - 'docker_registry_id' => $this->selectedRegistry, + 'docker_registry_id' => $this->selectedRegistry ?? null, 'environment_id' => $environment->id, 'destination_id' => $destination->id, 'destination_type' => $destination_class, @@ -85,7 +84,7 @@ class DockerImage extends Component public function render() { return view('livewire.project.new.docker-image', [ - 'registries' => Registry::all() + 'registries' => DockerRegistry::all() ]); } } diff --git a/app/Models/Application.php b/app/Models/Application.php index 5cd1eb99b..6ecc5f202 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -1536,6 +1536,6 @@ class Application extends BaseModel public function registry() { - return $this->belongsTo(Registry::class); + return $this->belongsTo(DockerRegistry::class); } } diff --git a/app/Models/Registry.php b/app/Models/DockerRegistry.php similarity index 72% rename from app/Models/Registry.php rename to app/Models/DockerRegistry.php index 8793815a2..c3638d0ad 100644 --- a/app/Models/Registry.php +++ b/app/Models/DockerRegistry.php @@ -5,16 +5,10 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; -class Registry extends Model +// #[OA\Schema( +class DockerRegistry extends Model { - protected $fillable = [ - 'name', - 'type', - 'url', - 'username', - 'token', - 'is_default' - ]; + protected $guarded = []; protected $casts = [ 'is_default' => 'boolean', @@ -34,6 +28,6 @@ class Registry extends Model public function applications(): HasMany { - return $this->hasMany(Application::class); + return $this->hasMany(Application::class, 'docker_registry_id', 'id'); } } diff --git a/database/migrations/2024_11_10_203115_create_registries_table.php b/database/migrations/2024_11_10_203115_create_registries_table.php index 01cb3e654..cc71abc06 100644 --- a/database/migrations/2024_11_10_203115_create_registries_table.php +++ b/database/migrations/2024_11_10_203115_create_registries_table.php @@ -14,7 +14,6 @@ return new class extends Migration { $table->string('url')->nullable(); $table->string('username')->nullable(); $table->text('token')->nullable(); - $table->boolean('is_default')->default(false); $table->timestamps(); }); diff --git a/resources/views/components/images/navbar.blade.php b/resources/views/components/images/navbar.blade.php new file mode 100644 index 000000000..c13b94c95 --- /dev/null +++ b/resources/views/components/images/navbar.blade.php @@ -0,0 +1,14 @@ +
+

Images

+
Images and container management.
+ +
diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index f635a6787..b80e44ad5 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -145,6 +145,16 @@ Sources +
  • + + + + Images + +
  • - + diff --git a/resources/views/livewire/images/images/index.blade.php b/resources/views/livewire/images/images/index.blade.php new file mode 100644 index 000000000..c97d65a2a --- /dev/null +++ b/resources/views/livewire/images/images/index.blade.php @@ -0,0 +1,16 @@ +
    + +
    +

    Images

    + + + + +
    + {{-- Images Tab Content --}} +
    +
    + Image management coming soon... +
    +
    +
    diff --git a/resources/views/livewire/images/registry/create.blade.php b/resources/views/livewire/images/registry/create.blade.php new file mode 100644 index 000000000..e25d91343 --- /dev/null +++ b/resources/views/livewire/images/registry/create.blade.php @@ -0,0 +1,23 @@ +
    + + + + @foreach ($this->registryTypes as $key => $value) + + @endforeach + + + @if ($type === 'custom') + + @endif + + + + + +
    + Save Registry +
    + diff --git a/resources/views/livewire/images/registry/index.blade.php b/resources/views/livewire/images/registry/index.blade.php new file mode 100644 index 000000000..455b5c3b7 --- /dev/null +++ b/resources/views/livewire/images/registry/index.blade.php @@ -0,0 +1,18 @@ +
    + +
    +

    Registries

    + + + +
    +
    Configure registries to pull Docker images from.
    + + @forelse($registries as $registry) + + @empty +
    + No registries configured yet. Add one to get started. +
    + @endforelse +
    diff --git a/resources/views/livewire/images/registry/show.blade.php b/resources/views/livewire/images/registry/show.blade.php new file mode 100644 index 000000000..6f68d4b7d --- /dev/null +++ b/resources/views/livewire/images/registry/show.blade.php @@ -0,0 +1,32 @@ +
    +
    +
    +
    + Update + +
    +
    + +
    + + + + @foreach ($this->registryTypes as $key => $value) + + @endforeach + + + @if ($type === 'custom') + + @endif + + + + +
    +
    +
    diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index 145c5575a..dc1aa64a3 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -144,7 +144,9 @@ @if ($application->docker_use_custom_registry)
    - + + {{-- --}} @foreach ($registries as $registry) @endforeach diff --git a/resources/views/livewire/project/new/docker-image.blade.php b/resources/views/livewire/project/new/docker-image.blade.php index 7af0ffcfd..e9cbf6dfe 100644 --- a/resources/views/livewire/project/new/docker-image.blade.php +++ b/resources/views/livewire/project/new/docker-image.blade.php @@ -10,23 +10,17 @@
    + helper="Select a registry to pull the image from." label="Use Private Registry" />
    @if ($useCustomRegistry) -

    Registry Authentication

    -
    - - - - - +
    + + + @foreach ($registries as $registry) + + @endforeach +
    @endif diff --git a/routes/web.php b/routes/web.php index afe392052..b860c011a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -33,6 +33,8 @@ use App\Livewire\Project\Shared\ExecuteContainerCommand; use App\Livewire\Project\Shared\Logs; use App\Livewire\Project\Shared\ScheduledTask\Show as ScheduledTaskShow; use App\Livewire\Project\Show as ProjectShow; +use App\Livewire\Images\Registry\Index as RegistryIndex; +use App\Livewire\Images\Images\Index as ImagesIndex; use App\Livewire\Security\ApiTokens; use App\Livewire\Security\PrivateKey\Index as SecurityPrivateKeyIndex; use App\Livewire\Security\PrivateKey\Show as SecurityPrivateKeyShow; @@ -228,6 +230,8 @@ Route::middleware(['auth', 'verified'])->group(function () { Route::get('/security/private-key/{private_key_uuid}', SecurityPrivateKeyShow::class)->name('security.private-key.show'); Route::get('/security/api-tokens', ApiTokens::class)->name('security.api-tokens'); + Route::get('/images/images', ImagesIndex::class)->name('images.images.index'); + Route::get('/images/registries', RegistryIndex::class)->name('images.registries.index'); }); Route::middleware(['auth'])->group(function () { @@ -306,13 +310,12 @@ Route::middleware(['auth'])->group(function () { fclose($stream); }, 200, [ 'Content-Type' => 'application/octet-stream', - 'Content-Disposition' => 'attachment; filename="'.basename($filename).'"', + 'Content-Disposition' => 'attachment; filename="' . basename($filename) . '"', ]); } catch (\Throwable $e) { return response()->json(['message' => $e->getMessage()], 500); } })->name('download.backup'); - }); Route::any('/{any}', function () {