chore: added registry url with default plus fixed functionality

This commit is contained in:
David Buday 2024-11-08 17:53:47 +01:00
parent b57a439b76
commit 15653e645c
7 changed files with 148 additions and 67 deletions

View file

@ -363,7 +363,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$this->server = $this->build_server;
}
$dockerfile_base64 = base64_encode($this->application->dockerfile);
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name} to {$this->server->name}.");
$didLogin = $this->handleRegistryAuth();
$this->prepare_builder_image();
$this->execute_remote_command(
[
@ -382,12 +384,24 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
private function deploy_dockerimage_buildpack()
{
try {
// setup
$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;
}
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.");
// login
$didLogin = $this->handleRegistryAuth();
// Pull the image
$this->execute_remote_command([
"docker pull {$this->application->image}",
]);
$this->generate_image_names();
$this->prepare_builder_image();
$this->generate_compose_file();
$this->rolling_update();
// Logout if we logged in
if ($didLogin) {
@ -591,6 +605,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
private function deploy_dockerfile_buildpack()
{
// login
$didLogin = $this->handleRegistryAuth();
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
if ($this->use_build_server) {
$this->server = $this->build_server;
@ -1970,7 +1986,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$this->application_deployment_queue->addLogEntry("Pulling latest image ($image) from the registry.");
$this->execute_remote_command(
[
executeInDocker($this->deployment_uuid, "docker pull {$image}"),
executeInDocker($this->deployment_uuid, "docker pull {$this->application->registry_url}/{$image}"),
'hidden' => true,
]
);
@ -2464,27 +2480,31 @@ 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));
{
if ($this->application->docker_use_custom_registry) {
try {
$username = escapeshellarg($this->application->docker_registry_username);
$token = escapeshellarg(decrypt($this->application->docker_registry_token));
$registry = $this->application->docker_registry_url ?: 'docker.io'; // Default to docker.io
$registry = escapeshellarg($registry);
$this->application_deployment_queue->addLogEntry('Attempting to log into registry...');
$this->application_deployment_queue->addLogEntry('Attempting to log into registry...');
$command = "echo {$token} | docker login -u {$username} --password-stdin > /dev/null";
$command = "echo {$token} | docker login {$registry} -u {$username} --password-stdin";
$this->application_deployment_queue->addLogEntry($command);
$this->execute_remote_command([
$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 true;
} catch (Exception $e) {
$this->application_deployment_queue->addLogEntry('Registry authentication error: ' . $e->getMessage(), 'stderr');
throw $e;
}
}
return false;
}
return false;
}
}

View file

@ -71,6 +71,10 @@ class General extends Component
'application.dockerfile' => 'nullable',
'application.docker_registry_image_name' => 'nullable',
'application.docker_registry_image_tag' => 'nullable',
'application.docker_use_custom_registry' => 'boolean',
'application.docker_registry_url' => 'nullable',
'application.docker_registry_username' => 'required_with:application.docker_use_custom_registry',
'application.docker_registry_token' => 'required_with:application.docker_use_custom_registry',
'application.dockerfile_location' => 'nullable',
'application.docker_compose_location' => 'nullable',
'application.docker_compose' => 'nullable',
@ -112,6 +116,10 @@ class General extends Component
'application.dockerfile' => 'Dockerfile',
'application.docker_registry_image_name' => 'Docker registry image name',
'application.docker_registry_image_tag' => 'Docker registry image tag',
'application.docker_use_custom_registry' => 'Docker use custom registry',
'application.docker_registry_url' => 'Registry URL',
'application.docker_registry_username' => 'Registry Username',
'application.docker_registry_token' => 'Registry Token',
'application.dockerfile_location' => 'Dockerfile location',
'application.docker_compose_location' => 'Docker compose location',
'application.docker_compose' => 'Docker compose',

View file

@ -14,29 +14,41 @@ class DockerImage extends Component
public string $dockerImage = '';
public ?string $registryUsername = null;
public ?string $registryToken = null;
public ?string $registryUrl = 'docker.io';
public bool $useCustomRegistry = false;
public array $parameters;
public array $query;
protected $rules = [
'dockerImage' => 'required|string',
'registryUsername' => 'nullable|string',
'registryToken' => 'nullable|string',
'registryUsername' => 'required_with:useCustomRegistry|string',
'registryToken' => 'required_with:useCustomRegistry|string',
'registryUrl' => 'nullable|string',
'useCustomRegistry' => 'boolean'
];
public function mount()
{
$this->parameters = get_route_parameters();
$this->query = request()->query();
$this->registryUrl = 'docker.io';
}
public function submit()
{
$this->validate([
'dockerImage' => 'required',
'registryUsername' => 'required_with:registryToken',
'registryToken' => 'required_with:registryUsername',
'registryUsername' => 'required_with:useCustomRegistry',
'registryToken' => 'required_with:useCustomRegistry',
]);
// Only save registry settings if useCustomRegistry is true
if (!$this->useCustomRegistry) {
$this->registryUsername = null;
$this->registryToken = null;
$this->registryUrl = 'docker.io';
}
$image = str($this->dockerImage)->before(':');
$tag = str($this->dockerImage)->contains(':') ?
str($this->dockerImage)->after(':') :
@ -70,8 +82,10 @@ 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,
'docker_use_custom_registry' => $this->useCustomRegistry,
'docker_registry_url' => $this->registryUrl,
'docker_registry_username' => $this->registryUsername,
'docker_registry_token' => $this->registryToken ? encrypt($this->registryToken) : null,
]);
$fqdn = generateFqdn($destination->server, $application->uuid);

View file

@ -35,6 +35,10 @@ use Visus\Cuid2\Cuid2;
'git_full_url' => ['type' => 'string', 'nullable' => true, 'description' => 'Git full URL.'],
'docker_registry_image_name' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker registry image name.'],
'docker_registry_image_tag' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker registry image tag.'],
'docker_use_custom_registry' => ['type' => 'boolean', 'description' => 'Use custom registry.'],
'docker_registry_url' => ['type' => 'string', 'nullable' => true, 'description' => 'Registry URL.'],
'docker_registry_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Registry username.'],
'docker_registry_token' => ['type' => 'string', 'nullable' => true, 'description' => 'Registry token.'],
'build_pack' => ['type' => 'string', 'description' => 'Build pack.', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose']],
'static_image' => ['type' => 'string', 'description' => 'Static image used when static site is deployed.'],
'install_command' => ['type' => 'string', 'description' => 'Install command.'],

View file

@ -8,16 +8,20 @@ return new class extends Migration {
public function up(): void
{
Schema::table('applications', function (Blueprint $table) {
$table->string('registry_username')->nullable();
$table->text('registry_token')->nullable();
$table->string('docker_registry_username')->nullable();
$table->text('docker_registry_token')->nullable();
$table->string('docker_registry_url')->nullable();
$table->boolean('docker_use_custom_registry')->default(false);
});
}
public function down(): void
{
Schema::table('applications', function (Blueprint $table) {
$table->dropColumn('registry_username');
$table->dropColumn('registry_token');
$table->dropColumn('docker_registry_username');
$table->dropColumn('docker_registry_token');
$table->dropColumn('docker_registry_url');
$table->dropColumn('docker_use_custom_registry');
});
}
};

View file

@ -101,34 +101,56 @@
target="_blank">here</a>.</div>
@endif
@endif
<div class="flex flex-col gap-2 xl:flex-row">
@if ($application->build_pack === 'dockerimage')
@if ($application->destination->server->isSwarm())
<x-forms.input required id="application.docker_registry_image_name" label="Docker Image" />
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-2 xl:flex-row">
@if ($application->build_pack === 'dockerimage')
@if ($application->destination->server->isSwarm())
<x-forms.input required id="application.docker_registry_image_name"
label="Docker Image" />
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
@else
<x-forms.input id="application.docker_registry_image_name" label="Docker Image" />
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
@endif
@else
<x-forms.input id="application.docker_registry_image_name" label="Docker Image" />
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
@if (
$application->destination->server->isSwarm() ||
$application->additional_servers->count() > 0 ||
$application->settings->is_build_server_enabled)
<x-forms.input id="application.docker_registry_image_name" required label="Docker Image"
placeholder="Required!" />
<x-forms.input id="application.docker_registry_image_tag"
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
placeholder="Empty means latest will be used." label="Docker Image Tag" />
@else
<x-forms.input id="application.docker_registry_image_name"
helper="Empty means it won't push the image to a docker registry."
placeholder="Empty means it won't push the image to a docker registry."
label="Docker Image" />
<x-forms.input id="application.docker_registry_image_tag"
placeholder="Empty means only push commit sha tag."
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
label="Docker Image Tag" />
@endif
@endif
@else
@if (
$application->destination->server->isSwarm() ||
$application->additional_servers->count() > 0 ||
$application->settings->is_build_server_enabled)
<x-forms.input id="application.docker_registry_image_name" required label="Docker Image"
placeholder="Required!" />
<x-forms.input id="application.docker_registry_image_tag"
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
placeholder="Empty means latest will be used." label="Docker Image Tag" />
@else
<x-forms.input id="application.docker_registry_image_name"
helper="Empty means it won't push the image to a docker registry."
placeholder="Empty means it won't push the image to a docker registry."
label="Docker Image" />
<x-forms.input id="application.docker_registry_image_tag"
placeholder="Empty means only push commit sha tag."
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
label="Docker Image Tag" />
</div>
@if ($application->build_pack === 'dockerimage')
<div class="pt-4 w-fit">
<x-forms.checkbox id="application.docker_use_custom_registry"
wire:model.live="application.docker_use_custom_registry"
label="Use Custom Registry Settings" />
</div>
@if ($application->docker_use_custom_registry)
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input id="application.docker_registry_url" label="Registry URL"
placeholder="docker.io" />
<x-forms.input id="application.docker_registry_username" label="Registry Username"
required placeholder="Username for private registry" />
<x-forms.input type="password" id="application.docker_registry_token"
label="Registry Token" placeholder="Token for private registry" />
</div>
@endif
@endif
</div>

View file

@ -8,16 +8,25 @@
</div>
<x-forms.input required id="dockerImage" label="Image" placeholder="nginx:latest" />
<h3 class="pt-4">Registry Authentication</h3>
<div class="flex flex-col gap-4">
<x-forms.input id="registryUsername" required="registryToken" label="Registry Username"
wire:model="registryUsername" placeholder="Username for private registry"
helper="Leave empty for public images or server credentials" />
<x-forms.input type="password" required="registryUsername" id="registryToken"
label="Registry Token/Password" wire:model="registryToken"
placeholder="Token or password for private registry"
helper="Leave empty for public images or server credentials" />
<div class="pt-4 w-fit">
<x-forms.checkbox wire:model.live="useCustomRegistry" id="useCustomRegistry"
label="Use Custom Registry Settings" />
</div>
@if ($useCustomRegistry)
<h3 class="pt-4">Registry Authentication</h3>
<div class="flex flex-col gap-4">
<x-forms.input id="registryUrl" label="Registry URL" placeholder="registry.example.com"
helper="Leave empty for Docker Hub" />
<x-forms.input id="registryUsername" label="Registry Username"
required="required_with:useCustomRegistry" placeholder="Username for private registry"
helper="Leave empty for public images or server credentials" />
<x-forms.input type="password" id="registryToken" label="Registry Token/Password"
required="required_with:useCustomRegistry" placeholder="Token or password for private registry"
helper="Leave empty for public images or server credentials" />
</div>
@endif
</form>
</div>