123 lines
5.4 KiB
PHP
123 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace classes;
|
|
|
|
class replication_schema_bootstrap
|
|
{
|
|
private static bool $initialized = false;
|
|
|
|
public static function ensureTables(): void
|
|
{
|
|
if (self::$initialized) {
|
|
return;
|
|
}
|
|
|
|
global $db;
|
|
|
|
$queries = [
|
|
"CREATE TABLE IF NOT EXISTS replication_hosts (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
kind VARCHAR(16) NOT NULL,
|
|
label VARCHAR(128) NOT NULL,
|
|
host VARCHAR(255) NOT NULL,
|
|
port INT UNSIGNED NOT NULL,
|
|
database_name VARCHAR(128) NULL,
|
|
database_index INT NULL,
|
|
username VARCHAR(128) NULL,
|
|
password_secret TEXT NULL,
|
|
admin_username VARCHAR(128) NULL,
|
|
admin_password_secret TEXT NULL,
|
|
replication_username VARCHAR(128) NULL,
|
|
replication_password_secret TEXT NULL,
|
|
role VARCHAR(16) NOT NULL DEFAULT 'replica',
|
|
status VARCHAR(16) NOT NULL DEFAULT 'unknown',
|
|
replication_source_id BIGINT UNSIGNED NULL,
|
|
ssl_mode VARCHAR(32) NULL,
|
|
options_json LONGTEXT NULL,
|
|
last_status_json LONGTEXT NULL,
|
|
last_checked_at DATETIME NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
deleted_at DATETIME NULL,
|
|
INDEX idx_replication_hosts_kind_role (kind, role),
|
|
INDEX idx_replication_hosts_kind_status (kind, status),
|
|
INDEX idx_replication_hosts_source (replication_source_id),
|
|
INDEX idx_replication_hosts_deleted_at (deleted_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
"CREATE TABLE IF NOT EXISTS replication_operations (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
kind VARCHAR(16) NOT NULL,
|
|
host_id BIGINT UNSIGNED NOT NULL,
|
|
operation VARCHAR(32) NOT NULL,
|
|
status VARCHAR(16) NOT NULL,
|
|
progress_percent DECIMAL(5,2) NOT NULL DEFAULT 0.00,
|
|
message VARCHAR(512) NULL,
|
|
error_message TEXT NULL,
|
|
context_json LONGTEXT NULL,
|
|
actor_user_id INT NULL,
|
|
started_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
completed_at DATETIME NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
INDEX idx_replication_operations_host (host_id),
|
|
INDEX idx_replication_operations_kind_status (kind, status),
|
|
INDEX idx_replication_operations_operation (operation)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
"CREATE TABLE IF NOT EXISTS replication_status_snapshots (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
host_id BIGINT UNSIGNED NOT NULL,
|
|
kind VARCHAR(16) NOT NULL,
|
|
status VARCHAR(16) NOT NULL,
|
|
replication_percent DECIMAL(5,2) NOT NULL DEFAULT 0.00,
|
|
lag_seconds INT NULL,
|
|
blockers_json LONGTEXT NULL,
|
|
raw_status_json LONGTEXT NULL,
|
|
checked_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
INDEX idx_replication_status_host_checked (host_id, checked_at),
|
|
INDEX idx_replication_status_kind_checked (kind, checked_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
"CREATE TABLE IF NOT EXISTS replication_audit_logs (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
kind VARCHAR(16) NOT NULL,
|
|
host_id BIGINT UNSIGNED NULL,
|
|
action VARCHAR(64) NOT NULL,
|
|
actor_user_id INT NULL,
|
|
severity VARCHAR(16) NOT NULL DEFAULT 'info',
|
|
context_json LONGTEXT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
INDEX idx_replication_audit_kind_host (kind, host_id),
|
|
INDEX idx_replication_audit_action (action),
|
|
INDEX idx_replication_audit_created_at (created_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
];
|
|
|
|
foreach ($queries as $sql) {
|
|
$db->query($sql);
|
|
}
|
|
|
|
self::ensureColumn('replication_operations', 'progress_percent', "DECIMAL(5,2) NOT NULL DEFAULT 0.00");
|
|
self::ensureColumn('replication_operations', 'message', 'VARCHAR(512) NULL');
|
|
self::ensureColumn('replication_operations', 'context_json', 'LONGTEXT NULL');
|
|
|
|
self::$initialized = true;
|
|
}
|
|
|
|
private static function ensureColumn(string $table, string $column, string $definition): void
|
|
{
|
|
global $db;
|
|
|
|
$table = preg_replace('/[^a-zA-Z0-9_]/', '', $table);
|
|
$column = preg_replace('/[^a-zA-Z0-9_]/', '', $column);
|
|
if ($table === '' || $column === '') {
|
|
return;
|
|
}
|
|
|
|
$result = $db->query("SHOW COLUMNS FROM `$table` LIKE '$column'");
|
|
if ($result !== false && $result->num_rows > 0) {
|
|
return;
|
|
}
|
|
|
|
$db->query("ALTER TABLE `$table` ADD COLUMN `$column` $definition");
|
|
}
|
|
}
|