mirror of
https://github.com/coollabsio/coolify.git
synced 2026-08-29 10:06:44 -05:00
Integrates Valkey as a new standalone database type. This includes adding the necessary model, updating actions to handle Valkey instances, and documenting the integration process.
303 lines
10 KiB
PHP
303 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Project\Database\Valkey;
|
|
|
|
use App\Actions\Database\StartDatabaseProxy;
|
|
use App\Actions\Database\StopDatabaseProxy;
|
|
use App\Helpers\SslHelper;
|
|
use App\Models\Server;
|
|
use App\Models\StandaloneValkey;
|
|
use App\Support\ValidationPatterns;
|
|
use Carbon\Carbon;
|
|
use Exception;
|
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Livewire\Component;
|
|
|
|
class General extends Component
|
|
{
|
|
use AuthorizesRequests;
|
|
|
|
public ?Server $server = null;
|
|
|
|
public StandaloneValkey $database;
|
|
|
|
public string $name;
|
|
|
|
public ?string $description = null;
|
|
|
|
public ?string $valkeyConf = null;
|
|
|
|
public string $image;
|
|
|
|
public ?string $portsMappings = null;
|
|
|
|
public ?bool $isPublic = null;
|
|
|
|
public ?int $publicPort = null;
|
|
|
|
public bool $isLogDrainEnabled = false;
|
|
|
|
public ?string $customDockerRunOptions = null;
|
|
|
|
public string $valkeyPassword;
|
|
|
|
public string $valkeyVersion;
|
|
|
|
public ?string $dbUrl = null;
|
|
|
|
public ?string $dbUrlPublic = null;
|
|
|
|
public bool $enableSsl = false;
|
|
|
|
public ?Carbon $certificateValidUntil = null;
|
|
|
|
public function getListeners()
|
|
{
|
|
$userId = Auth::id();
|
|
|
|
return [
|
|
"echo-private:user.{$userId},DatabaseStatusChanged" => '$refresh',
|
|
'envsUpdated' => 'refresh',
|
|
];
|
|
}
|
|
|
|
protected function rules(): array
|
|
{
|
|
return [
|
|
'name' => ValidationPatterns::nameRules(),
|
|
'description' => ValidationPatterns::descriptionRules(),
|
|
'valkeyConf' => 'nullable',
|
|
'image' => 'required',
|
|
'portsMappings' => 'nullable',
|
|
'isPublic' => 'nullable|boolean',
|
|
'publicPort' => 'nullable|integer',
|
|
'isLogDrainEnabled' => 'nullable|boolean',
|
|
'customDockerRunOptions' => 'nullable',
|
|
'valkeyPassword' => 'required',
|
|
'enableSsl' => 'boolean',
|
|
];
|
|
}
|
|
|
|
protected function messages(): array
|
|
{
|
|
return array_merge(
|
|
ValidationPatterns::combinedMessages(),
|
|
[
|
|
'name.required' => 'The Name field is required.',
|
|
'name.regex' => 'The Name may only contain letters, numbers, spaces, dashes (-), underscores (_), dots (.), slashes (/), colons (:), and parentheses ().',
|
|
'description.regex' => 'The Description contains invalid characters. Only letters, numbers, spaces, and common punctuation (- _ . : / () \' " , ! ? @ # % & + = [] {} | ~ ` *) are allowed.',
|
|
'image.required' => 'The Docker Image field is required.',
|
|
'publicPort.integer' => 'The Public Port must be an integer.',
|
|
'valkeyPassword.required' => 'The Valkey Password field is required.',
|
|
]
|
|
);
|
|
}
|
|
|
|
protected $validationAttributes = [
|
|
'name' => 'Name',
|
|
'description' => 'Description',
|
|
'valkeyConf' => 'Valkey Configuration',
|
|
'image' => 'Image',
|
|
'portsMappings' => 'Port Mapping',
|
|
'isPublic' => 'Is Public',
|
|
'publicPort' => 'Public Port',
|
|
'customDockerRunOptions' => 'Custom Docker Options',
|
|
'valkeyPassword' => 'Valkey Password',
|
|
'enableSsl' => 'Enable SSL',
|
|
];
|
|
|
|
public function mount()
|
|
{
|
|
try {
|
|
$this->authorize('view', $this->database);
|
|
$this->syncData();
|
|
$this->server = data_get($this->database, 'destination.server');
|
|
if (! $this->server) {
|
|
$this->dispatch('error', 'Database destination server is not configured.');
|
|
|
|
return;
|
|
}
|
|
|
|
$existingCert = $this->database->sslCertificates()->first();
|
|
|
|
if ($existingCert) {
|
|
$this->certificateValidUntil = $existingCert->valid_until;
|
|
}
|
|
} catch (\Throwable $e) {
|
|
return handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
public function syncData(bool $toModel = false)
|
|
{
|
|
if ($toModel) {
|
|
$this->validate();
|
|
$this->database->name = $this->name;
|
|
$this->database->description = $this->description;
|
|
$this->database->valkey_conf = $this->valkeyConf;
|
|
$this->database->image = $this->image;
|
|
$this->database->ports_mappings = $this->portsMappings;
|
|
$this->database->is_public = $this->isPublic;
|
|
$this->database->public_port = $this->publicPort;
|
|
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
|
|
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
|
|
$this->database->enable_ssl = $this->enableSsl;
|
|
$this->database->save();
|
|
|
|
$this->dbUrl = $this->database->internal_db_url;
|
|
$this->dbUrlPublic = $this->database->external_db_url;
|
|
} else {
|
|
$this->name = $this->database->name;
|
|
$this->description = $this->database->description;
|
|
$this->valkeyConf = $this->database->valkey_conf;
|
|
$this->image = $this->database->image;
|
|
$this->portsMappings = $this->database->ports_mappings;
|
|
$this->isPublic = $this->database->is_public;
|
|
$this->publicPort = $this->database->public_port;
|
|
$this->isLogDrainEnabled = $this->database->is_log_drain_enabled;
|
|
$this->customDockerRunOptions = $this->database->custom_docker_run_options;
|
|
$this->enableSsl = $this->database->enable_ssl;
|
|
$this->dbUrl = $this->database->internal_db_url;
|
|
$this->dbUrlPublic = $this->database->external_db_url;
|
|
$this->valkeyVersion = $this->database->getValkeyVersion();
|
|
$this->valkeyPassword = $this->database->valkey_password;
|
|
}
|
|
}
|
|
|
|
public function instantSaveAdvanced()
|
|
{
|
|
try {
|
|
$this->authorize('update', $this->database);
|
|
|
|
if (! $this->server->isLogDrainEnabled()) {
|
|
$this->isLogDrainEnabled = false;
|
|
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
|
|
|
|
return;
|
|
}
|
|
$this->syncData(true);
|
|
$this->dispatch('success', 'Database updated.');
|
|
$this->dispatch('success', 'You need to restart the service for the changes to take effect.');
|
|
} catch (Exception $e) {
|
|
return handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
public function submit()
|
|
{
|
|
try {
|
|
$this->authorize('manageEnvironment', $this->database);
|
|
|
|
$this->syncData(true);
|
|
|
|
$this->database->runtime_environment_variables()->updateOrCreate(
|
|
['key' => 'VALKEY_PASSWORD'],
|
|
['value' => $this->valkeyPassword, 'resourceable_id' => $this->database->id]
|
|
);
|
|
|
|
$this->dispatch('success', 'Database updated.');
|
|
} catch (Exception $e) {
|
|
return handleError($e, $this);
|
|
} finally {
|
|
$this->dispatch('refreshEnvs');
|
|
}
|
|
}
|
|
|
|
public function instantSave()
|
|
{
|
|
try {
|
|
$this->authorize('update', $this->database);
|
|
|
|
if ($this->isPublic && ! $this->publicPort) {
|
|
$this->dispatch('error', 'Public port is required.');
|
|
$this->isPublic = false;
|
|
|
|
return;
|
|
}
|
|
if ($this->isPublic) {
|
|
if (! str($this->database->status)->startsWith('running')) {
|
|
$this->dispatch('error', 'Database must be started to be publicly accessible.');
|
|
$this->isPublic = false;
|
|
|
|
return;
|
|
}
|
|
StartDatabaseProxy::run($this->database);
|
|
$this->dispatch('success', 'Database is now publicly accessible.');
|
|
} else {
|
|
StopDatabaseProxy::run($this->database);
|
|
$this->dispatch('success', 'Database is no longer publicly accessible.');
|
|
}
|
|
$this->dbUrlPublic = $this->database->external_db_url;
|
|
$this->syncData(true);
|
|
} catch (\Throwable $e) {
|
|
$this->isPublic = ! $this->isPublic;
|
|
$this->syncData(true);
|
|
|
|
return handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
public function instantSaveSSL()
|
|
{
|
|
try {
|
|
$this->authorize('update', $this->database);
|
|
|
|
$this->syncData(true);
|
|
$this->dispatch('success', 'SSL configuration updated.');
|
|
} catch (Exception $e) {
|
|
return handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
public function regenerateSslCertificate()
|
|
{
|
|
try {
|
|
$this->authorize('update', $this->database);
|
|
|
|
$existingCert = $this->database->sslCertificates()->first();
|
|
|
|
if (! $existingCert) {
|
|
$this->dispatch('error', 'No existing SSL certificate found for this database.');
|
|
|
|
return;
|
|
}
|
|
|
|
$caCert = $this->server->sslCertificates()->where('is_ca_certificate', true)->first();
|
|
|
|
SslHelper::generateSslCertificate(
|
|
commonName: $existingCert->commonName,
|
|
subjectAlternativeNames: $existingCert->subjectAlternativeNames ?? [],
|
|
resourceType: $existingCert->resource_type,
|
|
resourceId: $existingCert->resource_id,
|
|
serverId: $existingCert->server_id,
|
|
caCert: $caCert->ssl_certificate,
|
|
caKey: $caCert->ssl_private_key,
|
|
configurationDir: $existingCert->configuration_dir,
|
|
mountPath: $existingCert->mount_path,
|
|
isPemKeyFileRequired: true,
|
|
);
|
|
|
|
$this->dispatch('success', 'SSL certificates regenerated. Restart database to apply changes.');
|
|
} catch (Exception $e) {
|
|
handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
public function refresh(): void
|
|
{
|
|
$this->database->refresh();
|
|
$this->syncData();
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.project.database.valkey.general');
|
|
}
|
|
|
|
public function isSharedVariable($name)
|
|
{
|
|
return $this->database->runtime_environment_variables()->where('key', $name)->where('is_shared', true)->exists();
|
|
}
|
|
}
|