diff --git a/app/Actions/Database/StartClickhouse.php b/app/Actions/Database/StartClickhouse.php index 6da5465c6..393906b9b 100644 --- a/app/Actions/Database/StartClickhouse.php +++ b/app/Actions/Database/StartClickhouse.php @@ -51,7 +51,7 @@ public function handle(StandaloneClickhouse $database) ], 'labels' => defaultDatabaseLabels($this->database)->toArray(), 'healthcheck' => [ - 'test' => "clickhouse-client --password {$this->database->clickhouse_admin_password} --query 'SELECT 1'", + 'test' => "clickhouse-client --user {$this->database->clickhouse_admin_user} --password {$this->database->clickhouse_admin_password} --query 'SELECT 1'", 'interval' => '5s', 'timeout' => '5s', 'retries' => 10, @@ -152,12 +152,16 @@ private function generate_environment_variables() $environment_variables->push("$env->key=$env->real_value"); } - if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_USER'))->isEmpty()) { - $environment_variables->push("CLICKHOUSE_ADMIN_USER={$this->database->clickhouse_admin_user}"); + if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_USER'))->isEmpty()) { + $environment_variables->push("CLICKHOUSE_USER={$this->database->clickhouse_admin_user}"); } - if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_PASSWORD'))->isEmpty()) { - $environment_variables->push("CLICKHOUSE_ADMIN_PASSWORD={$this->database->clickhouse_admin_password}"); + if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_PASSWORD'))->isEmpty()) { + $environment_variables->push("CLICKHOUSE_PASSWORD={$this->database->clickhouse_admin_password}"); + } + + if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_DB'))->isEmpty()) { + $environment_variables->push("CLICKHOUSE_DB={$this->database->clickhouse_db}"); } add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables); diff --git a/app/Models/StandaloneClickhouse.php b/app/Models/StandaloneClickhouse.php index f598ef2ea..7acef5aae 100644 --- a/app/Models/StandaloneClickhouse.php +++ b/app/Models/StandaloneClickhouse.php @@ -25,7 +25,7 @@ protected static function booted() static::created(function ($database) { LocalPersistentVolume::create([ 'name' => 'clickhouse-data-'.$database->uuid, - 'mount_path' => '/bitnami/clickhouse', + 'mount_path' => '/var/lib/clickhouse', 'host_path' => null, 'resource_id' => $database->id, 'resource_type' => $database->getMorphClass(), @@ -246,8 +246,8 @@ protected function internalDbUrl(): Attribute get: function () { $encodedUser = rawurlencode($this->clickhouse_admin_user); $encodedPass = rawurlencode($this->clickhouse_admin_password); - - return "clickhouse://{$encodedUser}:{$encodedPass}@{$this->uuid}:9000/{$this->clickhouse_db}"; + $database = $this->clickhouse_db ?? 'default'; + return "clickhouse://{$encodedUser}:{$encodedPass}@{$this->uuid}:9000/{$database}"; }, ); } @@ -263,8 +263,8 @@ protected function externalDbUrl(): Attribute } $encodedUser = rawurlencode($this->clickhouse_admin_user); $encodedPass = rawurlencode($this->clickhouse_admin_password); - - return "clickhouse://{$encodedUser}:{$encodedPass}@{$serverIp}:{$this->public_port}/{$this->clickhouse_db}"; + $database = $this->clickhouse_db ?? 'default'; + return "clickhouse://{$encodedUser}:{$encodedPass}@{$serverIp}:{$this->public_port}/{$database}"; } return null; diff --git a/database/migrations/2025_11_28_000001_migrate_clickhouse_to_official_image.php b/database/migrations/2025_11_28_000001_migrate_clickhouse_to_official_image.php new file mode 100644 index 000000000..56167496c --- /dev/null +++ b/database/migrations/2025_11_28_000001_migrate_clickhouse_to_official_image.php @@ -0,0 +1,69 @@ +string('clickhouse_db') + ->default('default') + ->after('clickhouse_admin_password'); + }); + } + + // Change the default value for the 'image' column to the official image + Schema::table('standalone_clickhouses', function (Blueprint $table) { + $table->string('image')->default('clickhouse/clickhouse-server:25.11')->change(); + }); + + // Update existing ClickHouse instances from Bitnami images to official image + StandaloneClickhouse::where(function ($query) { + $query->where('image', 'like', '%bitnami/clickhouse%') + ->orWhere('image', 'like', '%bitnamilegacy/clickhouse%'); + }) + ->update([ + 'image' => 'clickhouse/clickhouse-server:25.11', + 'clickhouse_db' => DB::raw("COALESCE(clickhouse_db, 'default')"), + ]); + + // Update volume mount paths from Bitnami to official image paths + LocalPersistentVolume::where('resource_type', StandaloneClickhouse::class) + ->where('mount_path', '/bitnami/clickhouse') + ->update(['mount_path' => '/var/lib/clickhouse']); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Revert the default value for the 'image' column + Schema::table('standalone_clickhouses', function (Blueprint $table) { + $table->string('image')->default('bitnamilegacy/clickhouse')->change(); + }); + + // Revert existing ClickHouse instances back to Bitnami image + StandaloneClickhouse::where('image', 'clickhouse/clickhouse-server:25.11') + ->update(['image' => 'bitnamilegacy/clickhouse']); + + // Revert volume mount paths + LocalPersistentVolume::where('resource_type', StandaloneClickhouse::class) + ->where('mount_path', '/var/lib/clickhouse') + ->update(['mount_path' => '/bitnami/clickhouse']); + } +}; diff --git a/tests/Unit/ClickhouseOfficialImageMigrationTest.php b/tests/Unit/ClickhouseOfficialImageMigrationTest.php new file mode 100644 index 000000000..9edf5d09c --- /dev/null +++ b/tests/Unit/ClickhouseOfficialImageMigrationTest.php @@ -0,0 +1,55 @@ +clickhouse_admin_user = 'testuser'; + $clickhouse->clickhouse_admin_password = 'testpass'; + $clickhouse->clickhouse_db = 'mydb'; + $clickhouse->uuid = 'test-uuid'; + + $internalUrl = $clickhouse->internal_db_url; + + expect($internalUrl) + ->toContain('mydb') + ->toContain('testuser') + ->toContain('test-uuid'); +}); + +test('clickhouse defaults to default database when clickhouse_db is null', function () { + $clickhouse = new StandaloneClickhouse(); + $clickhouse->clickhouse_admin_user = 'testuser'; + $clickhouse->clickhouse_admin_password = 'testpass'; + $clickhouse->clickhouse_db = null; + $clickhouse->uuid = 'test-uuid'; + + $internalUrl = $clickhouse->internal_db_url; + + expect($internalUrl)->toContain('/default'); +}); + +test('clickhouse external url uses correct database', function () { + $clickhouse = new StandaloneClickhouse(); + $clickhouse->clickhouse_admin_user = 'admin'; + $clickhouse->clickhouse_admin_password = 'secret'; + $clickhouse->clickhouse_db = 'production'; + $clickhouse->uuid = 'prod-uuid'; + $clickhouse->is_public = true; + $clickhouse->public_port = 8123; + + $clickhouse->destination = new class { + public $server; + public function __construct() { + $this->server = new class { + public function __get($name) { + if ($name === 'getIp') return '1.2.3.4'; + } + }; + } + }; + $externalUrl = $clickhouse->external_db_url; + + expect($externalUrl)->toContain('production'); + +});