Add new frontend pages for the multi-tenant OCDP platform: - Charts page (/charts): Browse Harbor OCI registries to list Helm chart repositories and versions, with deploy modal to launch charts on selected clusters - Monitoring page (/monitoring): Display cluster metrics (CPU/Memory/GPU usage) and per-node details with resource utilization bars - Chart References page (/chart-references): CRUD for chart metadata references - Values Templates page (/templates): CRUD for Helm values templates with version history and rollback support - Sidebar: Add Charts navigation, update Storage and Templates links - api.ts: Add all API client functions (clusterApi, registryApi, instanceApi, monitoringApi, storageApi, chartReferenceApi, valuesTemplateApi, workspaceApi, userApi) with full TypeScript types Note: deploy flow and values template rollback not yet end-to-end tested.
188 lines
5.4 KiB
Go
188 lines
5.4 KiB
Go
package postgres
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
_ "github.com/lib/pq"
|
|
)
|
|
|
|
// DB 数据库连接包装器
|
|
type DB struct {
|
|
conn *sql.DB
|
|
}
|
|
|
|
// NewDB 创建新的数据库连接
|
|
func NewDB(connString string) (*DB, error) {
|
|
if connString == "" {
|
|
return nil, fmt.Errorf("database connection string cannot be empty")
|
|
}
|
|
|
|
conn, err := sql.Open("postgres", connString)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open database: %w", err)
|
|
}
|
|
|
|
// 配置连接池
|
|
conn.SetMaxOpenConns(25)
|
|
conn.SetMaxIdleConns(5)
|
|
conn.SetConnMaxLifetime(5 * time.Minute)
|
|
|
|
// 测试连接
|
|
if err := conn.Ping(); err != nil {
|
|
return nil, fmt.Errorf("failed to ping database: %w", err)
|
|
}
|
|
|
|
return &DB{conn: conn}, nil
|
|
}
|
|
|
|
// Close 关闭数据库连接
|
|
func (db *DB) Close() error {
|
|
if db.conn != nil {
|
|
return db.conn.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetConn 获取底层连接(用于事务等高级操作)
|
|
func (db *DB) GetConn() *sql.DB {
|
|
return db.conn
|
|
}
|
|
|
|
// InitSchema 初始化数据库 schema
|
|
func (db *DB) InitSchema() error {
|
|
schema := `
|
|
-- Users 表
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
username VARCHAR(255) NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
email VARCHAR(255) NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
|
|
|
-- Clusters 表
|
|
CREATE TABLE IF NOT EXISTS clusters (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
host TEXT NOT NULL,
|
|
ca_data TEXT,
|
|
cert_data TEXT,
|
|
key_data TEXT,
|
|
token TEXT,
|
|
description TEXT,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_clusters_name ON clusters(name);
|
|
|
|
-- Registries 表
|
|
CREATE TABLE IF NOT EXISTS registries (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
url TEXT NOT NULL,
|
|
description TEXT,
|
|
username VARCHAR(255),
|
|
password TEXT,
|
|
insecure BOOLEAN DEFAULT FALSE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_registries_name ON registries(name);
|
|
|
|
-- Instances 表
|
|
CREATE TABLE IF NOT EXISTS instances (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
cluster_id VARCHAR(36) NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
namespace VARCHAR(255) NOT NULL,
|
|
registry_id VARCHAR(36) NOT NULL,
|
|
repository TEXT NOT NULL,
|
|
chart VARCHAR(255) NOT NULL,
|
|
version VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
values JSONB,
|
|
values_yaml TEXT,
|
|
status VARCHAR(50) NOT NULL,
|
|
status_reason TEXT,
|
|
last_operation VARCHAR(50),
|
|
last_error TEXT,
|
|
revision INTEGER NOT NULL DEFAULT 1,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT fk_cluster FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE,
|
|
CONSTRAINT fk_registry FOREIGN KEY (registry_id) REFERENCES registries(id) ON DELETE CASCADE,
|
|
CONSTRAINT unique_cluster_name UNIQUE (cluster_id, name, namespace)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_instances_cluster ON instances(cluster_id);
|
|
CREATE INDEX IF NOT EXISTS idx_instances_registry ON instances(registry_id);
|
|
CREATE INDEX IF NOT EXISTS idx_instances_name ON instances(name);
|
|
|
|
-- Storage Backends 表
|
|
CREATE TABLE IF NOT EXISTS storage_backends (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
workspace_id VARCHAR(36),
|
|
owner_id VARCHAR(36),
|
|
name VARCHAR(255) NOT NULL,
|
|
type VARCHAR(50) NOT NULL,
|
|
config JSONB NOT NULL,
|
|
description TEXT,
|
|
is_default BOOLEAN DEFAULT FALSE,
|
|
is_shared BOOLEAN DEFAULT FALSE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_storage_workspace ON storage_backends(workspace_id);
|
|
|
|
-- Chart References 表
|
|
CREATE TABLE IF NOT EXISTS chart_references (
|
|
id VARCHAR(36) PRIMARY KEY,
|
|
workspace_id VARCHAR(36),
|
|
registry_id VARCHAR(36),
|
|
repository VARCHAR(500) NOT NULL,
|
|
chart_name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
is_enabled BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_chart_workspace ON chart_references(workspace_id);
|
|
CREATE INDEX IF NOT EXISTS idx_chart_registry ON chart_references(registry_id);
|
|
|
|
-- Values Templates 表 - 使用复合唯一键替代主键,允许同一模板的多个版本
|
|
CREATE TABLE IF NOT EXISTS values_templates (
|
|
id VARCHAR(36),
|
|
workspace_id VARCHAR(36),
|
|
owner_id VARCHAR(36),
|
|
chart_reference_id VARCHAR(36),
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
values_yaml TEXT NOT NULL,
|
|
version INTEGER NOT NULL DEFAULT 1,
|
|
is_default BOOLEAN DEFAULT FALSE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE (chart_reference_id, name, version)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_values_template_chart ON values_templates(chart_reference_id);
|
|
CREATE INDEX IF NOT EXISTS idx_values_template_workspace ON values_templates(workspace_id);
|
|
`
|
|
|
|
_, err := db.conn.Exec(schema)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to initialize schema: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|