feat(frontend): add Helm chart browser, monitoring, chart-references and values templates pages
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.
This commit is contained in:
257
backend/scripts/migrations/20250409_add_workspace_quotas.sql
Normal file
257
backend/scripts/migrations/20250409_add_workspace_quotas.sql
Normal file
@ -0,0 +1,257 @@
|
||||
-- OCDP 多租户权限系统迁移脚本
|
||||
-- 版本: v2.0.0
|
||||
-- 日期: 2026-04-09
|
||||
|
||||
-- ===== 1. 修改 users 表 =====
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS role VARCHAR(20) NOT NULL DEFAULT 'user';
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS workspace_id VARCHAR(36);
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS is_active BOOLEAN DEFAULT TRUE;
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS must_change_password BOOLEAN DEFAULT FALSE;
|
||||
|
||||
-- 添加索引
|
||||
CREATE INDEX IF NOT EXISTS idx_users_role ON users(role);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_workspace ON users(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_is_active ON users(is_active);
|
||||
|
||||
COMMENT ON COLUMN users.role IS '用户角色: admin, user';
|
||||
COMMENT ON COLUMN users.workspace_id IS '所属工作空间 ID';
|
||||
COMMENT ON COLUMN users.is_active IS '账户是否激活';
|
||||
COMMENT ON COLUMN users.must_change_password IS '首次登录必须修改密码';
|
||||
|
||||
-- ===== 2. 创建 workspaces 表 =====
|
||||
CREATE TABLE IF NOT EXISTS workspaces (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
created_by VARCHAR(36) REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_workspaces_name ON workspaces(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_workspaces_created_by ON workspaces(created_by);
|
||||
|
||||
COMMENT ON TABLE workspaces IS '工作空间/租户表';
|
||||
|
||||
-- ===== 3. 创建 workspace_quotas 表 =====
|
||||
CREATE TABLE IF NOT EXISTS workspace_quotas (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
workspace_id VARCHAR(36) NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
||||
resource_type VARCHAR(50) NOT NULL, -- 'cpu', 'gpu', 'gpu_memory'
|
||||
hard_limit DECIMAL(10,2) NOT NULL DEFAULT 0, -- 硬限制(0表示无限制)
|
||||
soft_limit DECIMAL(10,2) NOT NULL DEFAULT 0, -- 软限制(警告阈值)
|
||||
used DECIMAL(10,2) DEFAULT 0, -- 当前使用量
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(workspace_id, resource_type)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_workspace_quotas_workspace ON workspace_quotas(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_workspace_quotas_type ON workspace_quotas(resource_type);
|
||||
|
||||
COMMENT ON TABLE workspace_quotas IS '工作空间资源配额表';
|
||||
COMMENT ON COLUMN workspace_quotas.resource_type IS '资源类型: cpu, gpu, gpu_memory';
|
||||
COMMENT ON COLUMN workspace_quotas.hard_limit IS '硬限制(0表示无限制)';
|
||||
COMMENT ON COLUMN workspace_quotas.soft_limit IS '软限制(警告阈值)';
|
||||
COMMENT ON COLUMN workspace_quotas.used IS '当前使用量';
|
||||
|
||||
-- ===== 4. 修改 clusters 表 =====
|
||||
ALTER TABLE clusters ADD COLUMN IF NOT EXISTS workspace_id VARCHAR(36) REFERENCES workspaces(id) ON DELETE SET NULL;
|
||||
ALTER TABLE clusters ADD COLUMN IF NOT EXISTS owner_id VARCHAR(36) REFERENCES users(id);
|
||||
ALTER TABLE clusters ADD COLUMN IF NOT EXISTS isolation_mode VARCHAR(20) DEFAULT 'namespace';
|
||||
ALTER TABLE clusters ADD COLUMN IF NOT EXISTS default_namespace VARCHAR(255);
|
||||
ALTER TABLE clusters ADD COLUMN IF NOT EXISTS is_shared BOOLEAN DEFAULT FALSE;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_clusters_workspace ON clusters(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_clusters_owner ON clusters(owner_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_clusters_is_shared ON clusters(is_shared);
|
||||
|
||||
-- 删除旧的唯一约束,添加新的(允许同一workspace内名称唯一)
|
||||
ALTER TABLE clusters DROP CONSTRAINT IF EXISTS clusters_name_key;
|
||||
|
||||
COMMENT ON COLUMN clusters.workspace_id IS '所属工作空间 ID';
|
||||
COMMENT ON COLUMN clusters.owner_id IS '创建者用户 ID';
|
||||
COMMENT ON COLUMN clusters.isolation_mode IS '隔离模式: namespace(共享集群) 或 cluster(独立集群)';
|
||||
COMMENT ON COLUMN clusters.default_namespace IS '默认命名空间前缀';
|
||||
COMMENT ON COLUMN clusters.is_shared IS '是否为共享集群';
|
||||
|
||||
-- ===== 5. 修改 registries 表 =====
|
||||
ALTER TABLE registries ADD COLUMN IF NOT EXISTS workspace_id VARCHAR(36) REFERENCES workspaces(id) ON DELETE SET NULL;
|
||||
ALTER TABLE registries ADD COLUMN IF NOT EXISTS owner_id VARCHAR(36) REFERENCES users(id);
|
||||
ALTER TABLE registries ADD COLUMN IF NOT EXISTS is_shared BOOLEAN DEFAULT FALSE;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_registries_workspace ON registries(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_registries_owner ON registries(owner_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_registries_is_shared ON registries(is_shared);
|
||||
|
||||
-- 删除旧的唯一约束
|
||||
ALTER TABLE registries DROP CONSTRAINT IF EXISTS registries_name_key;
|
||||
|
||||
COMMENT ON COLUMN registries.workspace_id IS '所属工作空间 ID';
|
||||
COMMENT ON COLUMN registries.owner_id IS '创建者用户 ID';
|
||||
COMMENT ON COLUMN registries.is_shared IS '是否为共享注册表';
|
||||
|
||||
-- ===== 6. 创建 storage_backends 表 =====
|
||||
CREATE TABLE IF NOT EXISTS storage_backends (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
workspace_id VARCHAR(36) REFERENCES workspaces(id) ON DELETE CASCADE,
|
||||
owner_id VARCHAR(36) REFERENCES users(id),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(50) NOT NULL, -- 'nfs', 'pv', 'hostPath'
|
||||
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,
|
||||
UNIQUE(workspace_id, name)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_storage_backends_workspace ON storage_backends(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_storage_backends_owner ON storage_backends(owner_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_storage_backends_type ON storage_backends(type);
|
||||
|
||||
COMMENT ON TABLE storage_backends IS '存储后端表 (NFS/PV/HostPath)';
|
||||
COMMENT ON COLUMN storage_backends.type IS '存储类型: nfs, pv, hostPath';
|
||||
COMMENT ON COLUMN storage_backends.config IS '存储配置 (JSON)';
|
||||
|
||||
-- ===== 7. 创建 chart_references 表 =====
|
||||
CREATE TABLE IF NOT EXISTS chart_references (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
workspace_id VARCHAR(36) REFERENCES workspaces(id) ON DELETE CASCADE,
|
||||
registry_id VARCHAR(36) REFERENCES registries(id) ON DELETE CASCADE,
|
||||
repository VARCHAR(500) NOT NULL, -- OCI repository path
|
||||
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,
|
||||
UNIQUE(workspace_id, registry_id, repository)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_chart_references_workspace ON chart_references(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chart_references_registry ON chart_references(registry_id);
|
||||
|
||||
COMMENT ON TABLE chart_references IS 'Helm Chart 引用表';
|
||||
|
||||
-- ===== 8. 创建 values_templates 表 =====
|
||||
CREATE TABLE IF NOT EXISTS values_templates (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
workspace_id VARCHAR(36) REFERENCES workspaces(id) ON DELETE CASCADE,
|
||||
owner_id VARCHAR(36) REFERENCES users(id),
|
||||
chart_reference_id VARCHAR(36) REFERENCES chart_references(id) ON DELETE CASCADE,
|
||||
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(workspace_id, chart_reference_id, name, version)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_values_templates_workspace ON values_templates(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_values_templates_chart ON values_templates(chart_reference_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_values_templates_name ON values_templates(name);
|
||||
|
||||
COMMENT ON TABLE values_templates IS 'Values 模板表(带版本管理)';
|
||||
COMMENT ON COLUMN values_templates.version IS '模板版本号';
|
||||
|
||||
-- ===== 9. 创建 user_config_overrides 表 =====
|
||||
CREATE TABLE IF NOT EXISTS user_config_overrides (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
workspace_id VARCHAR(36) REFERENCES workspaces(id) ON DELETE CASCADE,
|
||||
user_id VARCHAR(36) REFERENCES users(id),
|
||||
target_type VARCHAR(50) NOT NULL, -- 'storage', 'template', 'global'
|
||||
target_id VARCHAR(36),
|
||||
config JSONB NOT NULL, -- 覆盖配置
|
||||
priority INTEGER DEFAULT 0, -- 优先级
|
||||
is_active 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_user_config_overrides_workspace ON user_config_overrides(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_config_overrides_user ON user_config_overrides(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_config_overrides_target ON user_config_overrides(target_type, target_id);
|
||||
|
||||
COMMENT ON TABLE user_config_overrides IS '用户配置覆盖表';
|
||||
COMMENT ON COLUMN user_config_overrides.target_type IS '目标类型: storage, template, global';
|
||||
COMMENT ON COLUMN user_config_overrides.priority IS '优先级(越高越优先)';
|
||||
|
||||
-- ===== 10. 修改 instances 表 =====
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS workspace_id VARCHAR(36) REFERENCES workspaces(id) ON DELETE SET NULL;
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS owner_id VARCHAR(36) REFERENCES users(id);
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS chart_reference_id VARCHAR(36) REFERENCES chart_references(id) ON DELETE SET NULL;
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS values_template_id VARCHAR(36) REFERENCES values_templates(id) ON DELETE SET NULL;
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS user_override_yaml TEXT;
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS cpu_requested DECIMAL(10,2) DEFAULT 0;
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS memory_requested VARCHAR(50) DEFAULT '0Mi';
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS gpu_requested DECIMAL(10,2) DEFAULT 0;
|
||||
ALTER TABLE instances ADD COLUMN IF NOT EXISTS gpu_memory_requested VARCHAR(50) DEFAULT '0Mi';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_instances_workspace ON instances(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_instances_owner ON instances(owner_id);
|
||||
|
||||
COMMENT ON COLUMN instances.workspace_id IS '所属工作空间 ID';
|
||||
COMMENT ON COLUMN instances.owner_id IS '创建者用户 ID';
|
||||
COMMENT ON COLUMN instances.chart_reference_id IS 'Chart 引用 ID';
|
||||
COMMENT ON COLUMN instances.values_template_id IS 'Values 模板 ID';
|
||||
COMMENT ON COLUMN instances.user_override_yaml IS '用户覆盖配置';
|
||||
COMMENT ON COLUMN instances.cpu_requested IS '请求的 CPU 核数';
|
||||
COMMENT ON COLUMN instances.memory_requested IS '请求的内存';
|
||||
COMMENT ON COLUMN instances.gpu_requested IS '请求的 GPU 卡数';
|
||||
COMMENT ON COLUMN instances.gpu_memory_requested IS '请求的 GPU 内存';
|
||||
|
||||
-- ===== 11. 创建 audit_logs 表 =====
|
||||
CREATE TABLE IF NOT EXISTS audit_logs (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
workspace_id VARCHAR(36),
|
||||
user_id VARCHAR(36) REFERENCES users(id),
|
||||
action VARCHAR(100) NOT NULL, -- 'create', 'update', 'delete', 'deploy', 'scale'
|
||||
resource_type VARCHAR(50) NOT NULL, -- 'cluster', 'registry', 'instance', 'quota', 'user', 'workspace'
|
||||
resource_id VARCHAR(36),
|
||||
resource_name VARCHAR(255),
|
||||
details JSONB,
|
||||
ip_address VARCHAR(50),
|
||||
user_agent TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_logs_workspace ON audit_logs(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_logs_user ON audit_logs(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_logs_action ON audit_logs(action);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_logs_resource ON audit_logs(resource_type, resource_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_logs_created ON audit_logs(created_at);
|
||||
|
||||
COMMENT ON TABLE audit_logs IS '审计日志表';
|
||||
COMMENT ON COLUMN audit_logs.action IS '操作类型: create, update, delete, deploy, scale';
|
||||
COMMENT ON COLUMN audit_logs.resource_type IS '资源类型: cluster, registry, instance, quota, user, workspace';
|
||||
|
||||
-- ===== 12. 插入迁移版本 =====
|
||||
INSERT INTO schema_migrations (version) VALUES ('v2.0.0')
|
||||
ON CONFLICT (version) DO NOTHING;
|
||||
|
||||
-- ===== 13. 更新现有 admin 用户为 admin 角色 =====
|
||||
UPDATE users SET role = 'admin', workspace_id = NULL WHERE username = 'admin' AND role = 'user';
|
||||
|
||||
-- ===== 14. 创建默认 workspace(可选,用于旧数据兼容)=====
|
||||
-- 如果需要将现有数据迁移到默认 workspace,取消下面注释
|
||||
-- INSERT INTO workspaces (id, name, description)
|
||||
-- VALUES (gen_random_uuid(), 'default', '默认工作空间')
|
||||
-- ON CONFLICT (name) DO NOTHING;
|
||||
--
|
||||
-- UPDATE clusters SET workspace_id = (SELECT id FROM workspaces WHERE name = 'default')
|
||||
-- WHERE workspace_id IS NULL;
|
||||
--
|
||||
-- UPDATE registries SET workspace_id = (SELECT id FROM workspaces WHERE name = 'default')
|
||||
-- WHERE workspace_id IS NULL;
|
||||
--
|
||||
-- UPDATE instances SET workspace_id = (SELECT id FROM workspaces WHERE name = 'default')
|
||||
-- WHERE workspace_id IS NULL;
|
||||
|
||||
-- ===== 迁移完成 =====
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'Migration v2.0.0 completed successfully!';
|
||||
END $$;
|
||||
Reference in New Issue
Block a user