opsx
|
36724bba94
|
fix(queries): MySQL 实例误调 Redis 接口 500 + 点表生成 SELECT + 光标多行闪烁
=== 一、/queries 打开 MySQL 实例报 500 ===
现象:GET /api/v1/redis/5/dbs → 500
后端日志 redis: invalid reply: "J\x00\x00\x00\n"
("J\x00\x00\x00" 是 MySQL 握手包,说明用 Redis 协议连了 3306)
根因:SchemaSidebar 是 mysql/redis 共用的组件,其中
const redisDbs = useRedisDbs(Number(instanceId));
是无条件调用(React hooks 不能条件调用),而 useRedisDbs 内部
只看 instanceId 就请求 /redis/{id}/dbs →
MySQL 实例也发 Redis 请求 → 后端用 Redis 协议连 MySQL → 500。
修复(前后端双保险):
1. useRedisDbs 增加 enabled 参数(默认 true),false 时不发请求并复位 [0]/false
2. SchemaSidebar 传 isRedis:useRedisDbs(Number(instanceId), isRedis)
3. redis.go getRedisClient 前置校验 DBType != "redis" 直接返回
4. resp 包新增 UserFacingError / UserFacing(),InternalErr 识别后返回
400 + 可读原因(不再把所有错误笼统包装成 500 "服务器内部错误")
验证:
GET /redis/5/dbs(MySQL)→ 400
{"code":"bad_request","detail":"实例「pre-mysql-只读」的类型是 mysql,
不是 redis。Redis 接口只适用于 redis 实例;MySQL/PostgreSQL 请使用
/api/v1/instances/5/databases 等对应接口"}
GET /instances/5/databases → 200
GET /redis/4/dbs(Redis 集群)→ 200 {"cluster":true,"dbs":[0]}
=== 二、左侧栏点表不生成 SELECT ===
原交互:单击=展开/折叠,双击=执行 SELECT,Alt+点击=插入表名。
需求:单击表 → 在右侧编辑器生成 SELECT * FROM <db>.<table>
修复:
1. SchemaSidebar 表节点:箭头图标包 data-chevron 单独触发展开/折叠;
点表名区域 → onInsert(previewSelectSql(...) + ';\n')
Alt+点击仍为只插表名;双击仍为直接执行
2. QueriesPage onInsert:生成的文本以 SELECT 开头时「替换」编辑器内容
(原来一律追加,会和上一条语句拼成非法 SQL);表名/字段名仍追加
=== 三、SQL 编辑器光标同时在多行闪烁 ===
根因:.cm-cursor 强制了 height:1.25em !important + marginTop:0.15em,
而 .cm-line 行高是 1.55em,光标高度溢出到相邻行,视觉上像两行同时闪。
修复:光标样式只保留颜色与 1.5px 宽度,height/marginTop 交回 CodeMirror 自行计算。
镜像:lghost/opsxsql:latest + v0.1
|
2026-10-27 00:58:22 +00:00 |
|
opsx
|
0427b87412
|
fix(instance): access_mode 值 read/readonly 不一致导致「读」实例被过滤
现象:instance-groups 里给 MySQL 实例授予「只读查询」权限后,
/queries 页面仍然选不到该实例,admin 也无法访问。
根因(枚举值前后端不一致):
前端 CreateInstanceForm「读」按钮写入 access_mode = "read"
后端 AccessibleInstances 只匹配 ["readwrite", "readonly"]
→ "read" 永远不命中,选了「读」的实例(MySQL)被过滤掉;
Redis 实例是 "readwrite" 所以恰好能查,掩盖了该 bug。
修复:后端 readonly 过滤增加 "read",兼容两种历史写法:
[]string{"readwrite", "readonly", "read"}
写过滤仍为 ["readwrite", "write"]("read" 实例正确地不能写)
验证(admin):
GET /instances/accessible?access_type=readonly → 5 个(含 MySQL id=5, access_mode=read)
GET /instances/accessible?access_type=write → 4 个(MySQL 正确排除)
镜像:lghost/opsxsql:latest + v0.1 = sha256:6b1a7121da71
|
2026-10-26 18:30:47 +00:00 |
|
opsx
|
f19a84f37e
|
fix(redis): 集群拓扑解析错误,跨机集群节点被强制指向种子机
【现象】Redis 集群实例查 keys 报 500:
Redis cluster connection failed: dial tcp 172.19.16.16:6005: connect: connection refused
【根因】handler/redis.go 解析 CLUSTER SLOTS:
nodeAddr := slot.Nodes[0].Addr // Redis 上报的真实地址 172.19.16.30:6005
if idx := strings.LastIndex(nodeAddr, ":"); idx >= 0 {
nodeAddr = instance.Host + nodeAddr[idx:] // 强制改写成 种子机主机 + 原端口
}
该逻辑假设「集群所有节点在同一台机器、只是端口不同」。
对跨机集群(16/30/59 三台)会把所有节点地址破坏成
172.19.16.16:6002 / :6003 / :6005 —— 这些端口在 16 上根本不存在 → refused。
【修复】
仅当 Redis 上报空 IP / 127.0.0.1 / 0.0.0.0 时才用配置 host 兜底(NAT/端口映射场景),
其余情况一律保留 Redis 上报的真实主机地址。
【附带数据修复(非代码)】
实例 5 host: pre-mysql.astx.club → 172.19.16.2
原因:pre-mysql.astx.club 公网 DNS 解析到 43.135.53.180(另一环境 MySQL),
认证失败 → 前端数据库下拉为空、无法选择数据库。
【验证】
GET /api/v1/redis/4/keys?db=0&pattern=* → 200
{"cluster":true,"keys":[{"key":"24H_rate_limit_10001_...","type":"string","ttl":42901000},
{"key":"CEX:FOLLOW:FOLLOWERS:TRADFI:97127836","type":"hash"},...]}
GET /api/v1/redis/4/dbs → 200 {"cluster":true,"dbs":[0]}
GET /api/v1/instances/5/databases → 200 返回 25 个库
["cex_activity","cex_admin","cex_agent",...,"cex_user","cex_xxl_job"]
镜像 sha256:165992ef79d5
|
2026-10-26 18:01:44 +00:00 |
|
opsx
|
6b81dbbd4a
|
feat(ldap): LDAP 改为只读接入,彻底移除账号验证与批量导入写入功能
按需求(sql.astx.club/settings):
1. 移除「测试账号验证」按钮
- LdapConfigForm.tsx 删按钮 + onOpenAccountTest prop
- 不再渲染 LdapAccountTestDialog
2. 移除批量导入的 LDAP 写操作(BatchImportModal.tsx)
- TABS 去掉「导入到 LDAP」「从 LDAP 导入」
- 删除对应两个 JSX 代码块(tab === 'to-ldap' / 'from-ldap')
- 删除「创建 OU」子弹窗
- 只保留「本地导入」(CSV 建本地账号,不触碰 LDAP 目录)
3. 移除 LDAP 账号管理面板(含危险写操作)
- 不再渲染 LdapManagePanel(新建 OU / 添加用户 / 删除用户)
- 删除 LdapCreateOuDialog / LdapAddUserDialog / ConfirmDialog 引用
- LdapConfigPage.tsx 421 → 340 行;BatchImportModal.tsx 557 → 329 行
4. 保留(只读用途)
- LDAP 配置表单(服务器 / 绑定 / 搜索 / 属性映射)
- 「测试连接」按钮(验证配置可用,不写 LDAP 目录)
设计原则:LDAP 仅用于域账号登录认证(只读 bind + search),
目录维护请到域控侧操作。
验证(前端 bundle grep,全部归零):
测试账号验证 0 | 导入到 LDAP 0 | 从 LDAP 导入 0
新建 OU 0 | 创建 OU 0 | 危险操作 0 | 此操作不可逆 0
保留:
测试连接 6 | 本地导入 1
镜像 sha256:3970db141d23
/health → {"backend":"go","status":"ok","version":"0.4.0"}
http://sql.astx.club/settings → HTTP 200
|
2026-10-26 17:49:34 +00:00 |
|
opsx
|
e8355e5d5f
|
feat(ldap): LDAP 改为只读接入,移除账号验证测试与批量导入写操作
按需求调整 settings 页 LDAP 区域:
1. 移除「测试账号验证」按钮
- LdapConfigForm.tsx 删除按钮 + onOpenAccountTest prop
- LdapConfigPage.tsx 不再渲染 LdapAccountTestDialog
2. 移除批量导入的 LDAP 写操作
- BatchImportModal.tsx 的 TABS 去掉「导入到 LDAP」「从 LDAP 导入」
- 只保留「本地导入」(CSV 建本地账号,不触碰 LDAP 目录)
3. 移除 LDAP 账号管理面板(危险写操作)
- 不再渲染 LdapManagePanel(新建 OU / 添加用户 / 删除用户)
- 不再渲染 LdapCreateOuDialog / LdapAddUserDialog
- 面板含「此操作不可逆」删除功能,与只读接入原则冲突
4. 保留(只读用途)
- LDAP 配置表单(服务器/绑定/搜索/属性映射)
- 「测试连接」按钮(验证配置是否可用,不写 LDAP)
设计原则:本系统 LDAP 仅用于域账号登录认证(只读 bind + search),
目录维护请在域控侧操作。
验证(前端 bundle 实测):
测试账号验证: 0 导入到 LDAP: 0 从 LDAP 导入: 0
新建 OU: 0 危险操作: 0 此操作不可逆: 0
测试连接: 6(保留) 本地导入: 1(保留)
/health → {"backend":"go","status":"ok","version":"0.4.0"}
http://sql.astx.club/settings → HTTP 200
|
2026-10-26 17:45:46 +00:00 |
|
opsx
|
d584b64813
|
feat(security): 默认账号随机初始密码(不再硬编码 admin123)
参考 lokistack 的实现:
1. 首次启动生成 16 位随机密码(大小写+数字,排除 0/O/1/l/I 易混淆字符)
- 4 个默认账号共用:admin / dba / auditor / developer
- 写入数据目录 initial-admin-password.txt(0600)
- 打印到启动日志(含账号列表、密码、文件路径、docker/kubectl 获取命令)
2. 支持 ADMIN_INIT_PASSWORD 环境变量覆盖(自动化部署 / 需要固定密码时)
3. 生成失败直接 log.Fatalf 退出,不降级到公开默认口令
4. 批量导入用户 BatchImportUsers:空密码不再默认 admin123,
改为随机 14 位(新增 genPassword),保证每个导入用户密码不可预测
5. 幂等:已存在的账号不重建、不改密码;只有缺失的账号才创建
6. imagePullPolicy: IfNotPresent → Always
原因:latest tag 配 IfNotPresent 会导致节点一直复用缓存的旧镜像,
新 push 的镜像不生效(本次实测踩到:Pod imageID 仍是旧 digest)
7. 文档
- README 新增「首次部署获取默认账号密码」章节(含 4 账号角色表 + 3 种获取方式)
- docker-compose.yml 加 ADMIN_INIT_PASSWORD 环境变量
- kubernetes/deployment.yaml 加 env 注释
验证(清空 DB 后全新 seed):
镜像 sha256:eaf0affd8d93
/app/data/initial-admin-password.txt 199B 权限 0600
内容含 "适用账号: [admin dba auditor developer]" + 随机密码
启动日志完整打印获取方式
登录实测:admin / dba / developer 用新密码均返回 access_token;
admin123 登录失败(已失效)
二进制 strings:admin123 命中 0
|
2026-10-26 17:37:21 +00:00 |
|
opsx
|
396df57c9c
|
build+deploy: 编译加 -trimpath,镜像改 lghost/opsxsql,K8s 部署到 sql 命名空间
1. -trimpath(抹除源码绝对路径)
- Dockerfile: go build 加 -trimpath
- run.sh: 两处 go build 加 -trimpath
效果:二进制内 /app/backend/ 绝对路径命中 66 → 0(module 相对路径 sql-platform/ 仍保留,
那是 Go 的正常行为,-trimpath 只去绝对前缀)
2. 镜像
- kubernetes/deployment.yaml: opsxsql:latest → lghost/opsxsql:latest
- kubernetes/install.sh: 默认 IMAGE 改 lghost/opsxsql:latest
- 已构建并推送:lghost/opsxsql:latest (digest 70562a408cae, 25.2MB)
3. K8s 部署验证(namespace: sql)
- Deployment opsxsql 1/1 Running,0 重启
- Pod: opsxsql-695444d6b9-chrzp (node 172.19.0.161)
- Service opsxsql.sql.svc.cluster.local:80
- PVC opsxsql-data Bound 10Gi (cbs)
- Secret opsxsql-secrets 自动生成(SECRET_KEY / JWT_SECRET)
- /health → {"backend":"go","status":"ok","version":"0.4.0"}
- 首页正常,seed 完成(26 条审核规则 + LDAP 默认配置)
部署命令:bash kubernetes/install.sh
|
2026-10-26 17:22:29 +00:00 |
|