mirror of
https://github.com/tiennm99/coolify.git
synced 2026-04-17 17:21:04 +00:00
Added ClickHouse Migration Support (#7392)
This commit is contained in:
@@ -51,7 +51,7 @@ class StartClickhouse
|
|||||||
],
|
],
|
||||||
'labels' => defaultDatabaseLabels($this->database)->toArray(),
|
'labels' => defaultDatabaseLabels($this->database)->toArray(),
|
||||||
'healthcheck' => [
|
'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',
|
'interval' => '5s',
|
||||||
'timeout' => '5s',
|
'timeout' => '5s',
|
||||||
'retries' => 10,
|
'retries' => 10,
|
||||||
@@ -152,12 +152,16 @@ class StartClickhouse
|
|||||||
$environment_variables->push("$env->key=$env->real_value");
|
$environment_variables->push("$env->key=$env->real_value");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_USER'))->isEmpty()) {
|
if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_USER'))->isEmpty()) {
|
||||||
$environment_variables->push("CLICKHOUSE_ADMIN_USER={$this->database->clickhouse_admin_user}");
|
$environment_variables->push("CLICKHOUSE_USER={$this->database->clickhouse_admin_user}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_PASSWORD'))->isEmpty()) {
|
if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_PASSWORD'))->isEmpty()) {
|
||||||
$environment_variables->push("CLICKHOUSE_ADMIN_PASSWORD={$this->database->clickhouse_admin_password}");
|
$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);
|
add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class StandaloneClickhouse extends BaseModel
|
|||||||
static::created(function ($database) {
|
static::created(function ($database) {
|
||||||
LocalPersistentVolume::create([
|
LocalPersistentVolume::create([
|
||||||
'name' => 'clickhouse-data-'.$database->uuid,
|
'name' => 'clickhouse-data-'.$database->uuid,
|
||||||
'mount_path' => '/bitnami/clickhouse',
|
'mount_path' => '/var/lib/clickhouse',
|
||||||
'host_path' => null,
|
'host_path' => null,
|
||||||
'resource_id' => $database->id,
|
'resource_id' => $database->id,
|
||||||
'resource_type' => $database->getMorphClass(),
|
'resource_type' => $database->getMorphClass(),
|
||||||
@@ -246,8 +246,8 @@ class StandaloneClickhouse extends BaseModel
|
|||||||
get: function () {
|
get: function () {
|
||||||
$encodedUser = rawurlencode($this->clickhouse_admin_user);
|
$encodedUser = rawurlencode($this->clickhouse_admin_user);
|
||||||
$encodedPass = rawurlencode($this->clickhouse_admin_password);
|
$encodedPass = rawurlencode($this->clickhouse_admin_password);
|
||||||
|
$database = $this->clickhouse_db ?? 'default';
|
||||||
return "clickhouse://{$encodedUser}:{$encodedPass}@{$this->uuid}:9000/{$this->clickhouse_db}";
|
return "clickhouse://{$encodedUser}:{$encodedPass}@{$this->uuid}:9000/{$database}";
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -263,8 +263,8 @@ class StandaloneClickhouse extends BaseModel
|
|||||||
}
|
}
|
||||||
$encodedUser = rawurlencode($this->clickhouse_admin_user);
|
$encodedUser = rawurlencode($this->clickhouse_admin_user);
|
||||||
$encodedPass = rawurlencode($this->clickhouse_admin_password);
|
$encodedPass = rawurlencode($this->clickhouse_admin_password);
|
||||||
|
$database = $this->clickhouse_db ?? 'default';
|
||||||
return "clickhouse://{$encodedUser}:{$encodedPass}@{$serverIp}:{$this->public_port}/{$this->clickhouse_db}";
|
return "clickhouse://{$encodedUser}:{$encodedPass}@{$serverIp}:{$this->public_port}/{$database}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\LocalPersistentVolume;
|
||||||
|
use App\Models\StandaloneClickhouse;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* Migrates existing ClickHouse instances from Bitnami/BinamiLegacy images
|
||||||
|
* to the official clickhouse/clickhouse-server image.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// Add clickhouse_db column if it doesn't exist
|
||||||
|
if (! Schema::hasColumn('standalone_clickhouses', 'clickhouse_db')) {
|
||||||
|
Schema::table('standalone_clickhouses', function (Blueprint $table) {
|
||||||
|
$table->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']);
|
||||||
|
}
|
||||||
|
};
|
||||||
55
tests/Unit/ClickhouseOfficialImageMigrationTest.php
Normal file
55
tests/Unit/ClickhouseOfficialImageMigrationTest.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\StandaloneClickhouse;
|
||||||
|
|
||||||
|
test('clickhouse uses clickhouse_db field in internal connection string', function () {
|
||||||
|
$clickhouse = new StandaloneClickhouse();
|
||||||
|
$clickhouse->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');
|
||||||
|
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user