Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
b3dd24e
- PROGRESS 迁移状态暂存#1
ChesterNotChest Aug 17, 2026
febe506
- PROGRESS 迁移状态暂存|分包基本完成|已通过回归 #2
ChesterNotChest Aug 18, 2026
3338bf7
- PROGRESS 迁移状态暂存|WSS和HTTPS的SSL基本搭建 - machine管理模式变动(降低人工输入工作量) #3
ChesterNotChest Aug 19, 2026
e520b86
- PROGRESS blueprints -> api、FastAPI 外壳、machine router、schema #4
ChesterNotChest Aug 19, 2026
67ed671
- PROGRESS 迁移状态暂存| #5
ChesterNotChest Aug 19, 2026
0565ec5
- REFACTOR 完成了FastAPI和WSS的迁移
ChesterNotChest Aug 20, 2026
88329d5
- PROGRESS 迁移状态暂存|深度清理Flask与heartbeat残留 #6
ChesterNotChest Aug 20, 2026
79cef54
- REFACTOR 完成了 FastAPI 的DB、runtime操作的迁移
ChesterNotChest Aug 21, 2026
30dee9d
- FIX 修复了状态机相关问题
ChesterNotChest Aug 21, 2026
8a22ed7
- NEW 补充了SSL协议的完整工序
ChesterNotChest Aug 21, 2026
8396975
- FIX 修复了“重启中”状态不正常显示的问题
ChesterNotChest Aug 23, 2026
08a55a4
- NEW 更新了list逻辑,使得能够搜索和groupBy
ChesterNotChest Aug 23, 2026
ad16ada
- NEW 权限的RBAC设计实装
ChesterNotChest Aug 23, 2026
751c009
- FIX 修复了空快照带来的雪崩问题
ChesterNotChest Aug 24, 2026
7eacce0
- NEW 新增了收集失败的短暂派生异常
ChesterNotChest Aug 24, 2026
0b5761a
- FIX 修复为无机器权限的用户创建容器的问题
ChesterNotChest Aug 25, 2026
ce978cc
- NEW 镜像基本CRUD
ChesterNotChest Aug 25, 2026
54a6fa7
- NEW 设置数据库 settings 基本后端实现
ChesterNotChest Aug 25, 2026
78c574c
- PROGRESS 进一步完成镜像部分
ChesterNotChest Aug 29, 2026
d5ab96b
- REMOVE 移除了"pre_build"设计
ChesterNotChest Aug 29, 2026
7603ff0
- FIX 修复了构建过程造成的假终止问题
ChesterNotChest Aug 29, 2026
6f3e0be
- NEW GPU 三集合建模(gpu_list 事实 / gpu_allow_list 许可 / gpu_chosen_list 分配,…
ChesterNotChest Aug 31, 2026
c103144
- NEW 设置页面构建
ChesterNotChest Sep 1, 2026
bed222b
- NEW 新实现了容器删除后恢复的能力
ChesterNotChest Sep 1, 2026
881f309
- NEW RBAC权限管理页面后端支撑
ChesterNotChest Sep 2, 2026
e196180
- NEW 新增了 RBAC 权限实体去 DB 化(auth_entities 退役、组绑定直接存 code)
ChesterNotChest Sep 3, 2026
d92c92b
- NEW 更好的轮询
ChesterNotChest Sep 3, 2026
5700d1c
- FIX 修复了镜像带来的权限问题
ChesterNotChest Sep 3, 2026
9c690ce
- FIX 修复了镜像带来的权限问题
ChesterNotChest Sep 3, 2026
551ac00
Merge branch 'chester-next' of github.com:TRM-coding/FuxiYu_CtrKernel…
ChesterNotChest Sep 3, 2026
f57812d
- CI 补充环境缺失
ChesterNotChest Sep 4, 2026
fbe6a13
- AMEND 清退旧的定时任务启动器
ChesterNotChest Sep 4, 2026
2691b69
- FIX 修复了不完整磁盘采集导致的显示不符,避免把不完整挂载用量当 0 评估
ChesterNotChest Sep 9, 2026
3f48405
- FIX 跳过不完整磁盘快照并补充容器日志身份字段
ChesterNotChest Sep 9, 2026
e731a57
- RESTORE 恢复了错误删去的自动清理和冻结机制
ChesterNotChest Sep 9, 2026
4872486
- FIX 补充了顺延机制,使得机器OFFLINE/MAINTENANCE的时候不计入ssh online的时钟推进
ChesterNotChest Sep 9, 2026
4752c5d
- NEW 容器软删除:删除改为标记 is_valid=false(保留原行与原 id),唯一约束 (name,machine_id) →…
ChesterNotChest Sep 10, 2026
8a52194
- FIX dotenv 依赖声明修正
ChesterNotChest Sep 10, 2026
cef76e4
ENHANCEMENT op-log 全路径审计收口
ChesterNotChest Sep 10, 2026
9880a16
- REFACTOR 整理了 container 的代码布局
ChesterNotChest Sep 10, 2026
45d4de5
- REFACTOR 变更了WSS拨号方向
ChesterNotChest Sep 12, 2026
2a5ae31
- REFACTOR 变更了WSS拨号方向
ChesterNotChest Sep 12, 2026
ada6ba2
Merge branch 'chester-next' of github.com:TRM-coding/FuxiYu_CtrKernel…
ChesterNotChest Sep 12, 2026
74a59cd
- NEW 统一了定时任务的门禁功能
ChesterNotChest Sep 12, 2026
662f31b
- AMEND 去掉了多余的派生DB字段valid_name
ChesterNotChest Sep 13, 2026
f90da8d
- NEW 增加了Node允许调整宿主机节点程序暴露的端口的选项
ChesterNotChest Sep 13, 2026
264f23b
- FIX 动作通道的 pin 校验口径与链路拉平
ChesterNotChest Sep 13, 2026
372f23d
- FIX 修复了顺延只计算已结算窗口的问题——现在会计算正在进行的非ONLINE窗口
ChesterNotChest Sep 13, 2026
966f9e9
- FIX 修复了顺延只覆盖SSH刷新的问题——现在也覆盖磁盘清理和容器清理机制
ChesterNotChest Sep 13, 2026
e088578
- FIX 删掉了旧的字段max_gpu_number,防止歧义产生
ChesterNotChest Sep 13, 2026
60a9d53
- DEBUG 增加了连接调试能力
ChesterNotChest Sep 13, 2026
a641e57
- SAFE 补上了一个Node被冒充的安全风险
ChesterNotChest Sep 13, 2026
8ddc77b
- FIX 修复了由Proxy导致的回环API异常
ChesterNotChest Sep 13, 2026
1316513
- DEBUG 补上了机器管理的一些异常映射缺失
ChesterNotChest Sep 13, 2026
18cba06
Merge branch 'chester-next' of github.com:TRM-coding/FuxiYu_CtrKernel…
ChesterNotChest Sep 13, 2026
d6ba2fa
- FIX 修复了顺延期间反复发送提醒邮件的恶性bug
ChesterNotChest Sep 14, 2026
1f418db
- CI 防抖动修复-(不是回归失败)
ChesterNotChest Sep 15, 2026
b808fc6
- SAFE 防误提交:*.bak-* 加入 gitignore,dev 数据库备份移出版本控制
ChesterNotChest Sep 15, 2026
85b5a21
- NEW 容器镜像归属收口:归属凭 image_id 外键,标签改由推导、不再落库
ChesterNotChest Sep 15, 2026
a9cd7b8
- COMMENT 注释修正
ChesterNotChest Sep 15, 2026
46d13a0
- FIX 修复了子进程不能优雅结束的问题
ChesterNotChest Sep 15, 2026
5fff8ca
- FIX 修复了image的build缓存无法命中的问题
ChesterNotChest Sep 18, 2026
1ad9d8c
- NEW 显式补充了系统的ENTRYPOINT能力
ChesterNotChest Sep 19, 2026
474d607
- FIX 去除了带有歧义的tag的字段;转为展示确定的image_name等信息
ChesterNotChest Sep 19, 2026
35a5239
- FIX 修复了需要顺延的时候grace(宽恕计时)照走的问题
ChesterNotChest Sep 19, 2026
3370024
- AMEND 优化了settings表述断言
ChesterNotChest Sep 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 15 additions & 37 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ NODE_PORT=5789
WEB_IP=127.0.0.1
WEB_PORT=5173

# ── Node 链路旁挂 ──
# Ctrl 主动拨各 Node 的 /ws/ctrl 取快照(machines 表即链路清单)。
# 关掉则没有任何快照落库、机器状态不再更新,仅调试时使用。
CTRL_WSS_ENABLED=true
# 链路调优(缺省即下方值,一般无需配置)
# CTRL_LINK_SYNC_INTERVAL=5 # machines 表 → 运行中链路的集合对齐周期(秒)
# CTRL_LINK_BACKOFF_INITIAL=1 # 单机重连退避起始(秒)
# CTRL_LINK_BACKOFF_MAX=30 # 单机重连退避上限(秒),即离线机器的检查周期
# CTRL_WSS_READ_TIMEOUT=30 # 半开连接防护:多久收不到帧判链路失效(秒)

# Database
DATABASE_URL=sqlite:///dev_database.db
# or MySQL:
Expand All @@ -27,46 +37,14 @@ MAIL_TIMEOUT=15
# Test recipient
MAIL_TEST_TO=22301131@bjtu.edu.cn

# Settings
LONG_TERM_CONTAINER_LIMIT=1
CONTAINER_CLEANUP_REMINDER_HOURS=72,24,12
CONTAINER_DISK_CHECK_ENABLED=false

# 已删除容器的挂载备份清理:开关 + 扫描间隔 + 保留天数(默认关闭;开启后每天扫描清理一次)
CONTAINER_MOUNT_CLEANUP_ENABLED=false
CONTAINER_MOUNT_CLEANUP_INTERVAL_SECONDS=86400
CONTAINER_MOUNT_CLEANUP_AFTER_DAYS=14

# 容器自动清理:SSH 未登录 N 天后清理(提醒档位见下)
CONTAINER_CLEANUP_AFTER_DAYS=7

# 磁盘检测:开关 + 扫描间隔 + 软/硬限位 + 响应处置
CONTAINER_DISK_CHECK_INTERVAL_SECONDS=900
CONTAINER_DISK_SOFT_LIMIT_PERCENT=80
CONTAINER_DISK_HARD_LIMIT_PERCENT=100
CONTAINER_DISK_RESPONSE_ENABLED=false
# 磁盘超限冻结升级:冻结 N 天后升级处置;宽限期天数;解冻回退阈值
CONTAINER_DISK_FREEZE_ESCALATION_DAYS=7
CONTAINER_DISK_FREEZE_GRACE_DAYS=3
CONTAINER_DISK_FREEZE_RESET_PERCENT=95

# Node 通信并行与连接池
NODE_PARALLEL_ENABLED_MACHINES=true
NODE_PARALLEL_ENABLED_CONTAINERS=true
NODE_PARALLEL_ENABLED_SSH_REFRESH=true
NODE_REQUEST_POOL_SIZE=8

# 公告系统
ANNOUNCEMENT_MAX_RECIPIENTS=200
ANNOUNCEMENT_SEND_COOLDOWN_SECONDS=60
ANNOUNCEMENT_BATCH_SEND_MAX=20

# 密钥路径(默认仓库根目录的 public_A.pem / private_A.pem,一般无需修改)
#PRIVATE_KEY_PATH=private_A.pem
#PUBLIC_KEY_PATH=public_A.pem
SSL_CERT_PATH=certs/localhost.pem
SSL_KEY_PATH=certs/localhost-key.pem
SSL_CERT_PATH=certs/ctrl.pem
SSL_KEY_PATH=certs/ctrl-key.pem
CTRL_CA_CERT_FILE=certs/ctrl_ca.pem
CTRL_CA_KEY_FILE=certs/ctrl_ca-key.pem

# Flask
# 应用
SECRET_KEY=dev
ENABLE_SSL=true
26 changes: 19 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
**/.pytest_cache/
**/__pycache__/
*/.pytest_cache/
*/__pycache__/

venv/

# ignore locally-generated TLS certs (mkcert)
certs/*.pem
certs/*-key.pem
certs/*.key
*.log
.env
.env*
!.env.example
.mysql-fix-*.sql

# 运行时备份文件(.env.bak-*、*.bak-*.sql、dev_database.db.bak-* 等),一律不入库
*.bak-*

/logs/*
!/logs/.gitkeep

/certs/*
!/certs/.gitkeep

# 信任锚(各机器的 Node 证书)是运行时状态,只留目录占位;与 certs/ 同一写法
/pinned_certs/*
!/pinned_certs/.gitkeep
/runtime_cache/

docs/audit/*

*.db
*.db
*.sqlite
*.sqlite3
*.log
100 changes: 100 additions & 0 deletions .init_next_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""初始化 ~/FuxiYu_Next 三套 .env:删死键 + 补注释。

只按**键名**增删,不读取也不改写任何值(SQLPASSWORD / SECRET_KEY 等原样保留),
其余行逐字节不动。执行前先备份。

"死键" = 全仓已无读取处。判定依据是本地三仓的 grep 结果;这些是 WSS 方向反转前
的残留——那时 Node 要主动拨 Ctrl,所以需要知道 Ctrl 的地址。
"""

import datetime
import pathlib
import shutil
import sys

ROOT = pathlib.Path.home() / "FuxiYu_Next"

# 每个仓库:要删的键
DEAD_KEYS = {
"FuxiYu_CtrKernel": ["CTRL_WSS_PORT"],
"FuxiYu_NodeKernel": ["CTRL_IP", "CTRL_PORT", "NODE_WSS_ENABLED", "NODE_CTRL_WSS_URL"],
"FuxiYu_Web": [],
}

# 要在某键之前插入的注释(键名 -> 注释文本)
ANNOTATIONS = {
"CTRL_WSS_ENABLED": (
"# 链路旁挂进程开关(名字是 WSS 时代的遗留,语义已是「Ctrl→Node 拨号管理器」)。\n"
"# 置 0 会导致一台机器都不被拨、全线离线——不要因为名字里带 WSS 就删它。"
),
}

# 追加到文件末尾的说明(仓库 -> 文本)
FOOTERS = {
"FuxiYu_NodeKernel": (
"\n# 方向已反转:Ctrl 主动拨入 Node,Node 是被动端点。\n"
"# 因此 Node 不需要知道 Ctrl 的地址——CTRL_IP / CTRL_PORT / NODE_CTRL_WSS_URL\n"
"# 等键已无读取处,已于本次初始化中移除,别再按旧文档加回来。\n"
),
}


def rewrite(repo: str) -> tuple[list[str], list[str]]:
path = ROOT / repo / ".env"
original = path.read_text(encoding="utf-8")
dead = set(DEAD_KEYS[repo])
removed, kept = [], []

out_lines: list[str] = []
for line in original.splitlines():
stripped = line.strip()
if stripped and not stripped.startswith("#") and "=" in stripped:
key = stripped.split("=", 1)[0].strip()
if key in dead:
removed.append(key)
continue
if key in ANNOTATIONS:
out_lines.append(ANNOTATIONS[key])
out_lines.append(line)

text = "\n".join(out_lines)
if not text.endswith("\n"):
text += "\n"
if FOOTERS.get(repo):
text += FOOTERS[repo]

stamp = datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S")
shutil.copy2(path, path.with_name(f".env.bak-{stamp}"))
path.write_text(text, encoding="utf-8")

live = [
line.strip().split("=", 1)[0].strip()
for line in text.splitlines()
if line.strip() and not line.strip().startswith("#") and "=" in line
]
return removed, live


def main() -> None:
dry = "--apply" not in sys.argv
for repo in DEAD_KEYS:
path = ROOT / repo / ".env"
if not path.exists():
print(f"!! {repo}/.env 不存在,跳过")
continue
if dry:
before = [
line.strip().split("=", 1)[0].strip()
for line in path.read_text(encoding="utf-8").splitlines()
if line.strip() and not line.strip().startswith("#") and "=" in line
]
print(f"{repo}: 现有 {len(before)} 键;将删除 {DEAD_KEYS[repo] or '(无)'}")
continue
removed, live = rewrite(repo)
print(f"{repo}: 删除 {removed or '(无)'} → 剩余 {len(live)} 键 {live}")

if dry:
print("\ndry run:未写入。加 --apply 落地(会先备份为 .env.bak-<时间戳>)。")


main()
133 changes: 57 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,105 +1,86 @@
# 伏羲-御
# 伏羲 · Fuxi-Yu

## 伏羲・御・Fuxi-Yu
Fuxi-Yu 是面向高校与实验室算力管理场景的容器化平台。CtrlKernel 是伏羲平台的控制端服务,负责用户、机器、容器、公告、审计日志、权限与 Node 通信编排。

面向算力平台的 Docker 化集群管理与自助使用系统。将物理服务器纳入统一 “控制面”,用户以申请到的 Docker 实例直控实体机,配套可视化的基础环境配置(网络、用户等),免去繁琐安装与踩坑,友好地面向 Linux 新手与多用户场景
当前版本使用 FastAPI 提供 HTTP API 与 Swagger 文档,使用 SQLAlchemy 管理数据库访问

```
config.py # 配置
extensions.py # 第三方扩展初始化
__init__.py # create_app 工厂
run.py # 开发直接运行入口
wsgi.py # 生产/WSGI 入口
models/ # 数据模型层
repositories/ # 数据访问仓储层
services/ # 业务服务层
schemas/ # 序列化/反序列化层 (Marshmallow)
blueprints/ # 路由蓝图 (接口层)
```
## 快速上手

## 功能点
- App 工厂模式 (`create_app`)
- 配置分环境 (development / production / testing)
- SQLAlchemy + Migrate 数据迁移能力
- Caching / LoginManager 预置
- 用户模型 + 仓储 + 服务 + Schema + API 示例
- Marshmallow 进行序列化
### 1. 安装依赖

## 快速开始
建议在项目约定的 Python 环境中安装:

### 1. 克隆与安装依赖
```bash
pip install -r requirements.txt
```

### 2. 初始化数据库
### 2. 配置环境

可参考 `.env.example` 创建 `.env`。常用配置:

```bash
# 生成迁移仓库
flask --app compute_cluster_manage_web:create_app db init
# 生成迁移脚本
flask --app compute_cluster_manage_web:create_app db migrate -m "init"
# 应用迁移
flask --app compute_cluster_manage_web:create_app db upgrade
DATABASE_URL=sqlite:///app.db
CTRL_PORT=5000
SECRET_KEY=change-me
```
> 若你直接使用 sqlite,默认文件为 `app.db`。

### 3. 运行开发服务器
未设置 `DATABASE_URL` 时,默认使用当前目录下的 `app.db`。

### 3. 初始化基础数据

```bash
python -m compute_cluster_manage_web.run
# 或
flask --app compute_cluster_manage_web:create_app run --debug
python seed.py
```
访问: http://127.0.0.1:5000/api/users

### 4. 示例 API
数据库表会在应用启动时按当前模型创建;手写迁移脚本位于 `migrations/`。

### 4. 启动服务

#### 创建用户
```bash
curl -X POST http://127.0.0.1:5000/api/users \
-H 'Content-Type: application/json' \
-d '{"username":"alice","email":"alice@example.com","password":"123456"}'
python run.py
```

默认访问地址:

```text
http://127.0.0.1:5000
```
响应:
```json
{
"id": 1,
"username": "alice",
"email": "alice@example.com",
"created_at": "2025-01-01T00:00:00"
}

Swagger 文档:

```text
http://127.0.0.1:5000/docs
```

#### 列表用户
### 5. 运行测试

默认测试不会访问真实 Node、Docker、SMTP 或生产数据库:

```bash
curl http://127.0.0.1:5000/api/users
pytest
```

### 5. 目录/分层说明
| 层 | 说明 | 关注点 |
|----|------|--------|
| model | `models/` | ORM 定义,仅包含字段和关系 |
| repository | `repositories/` | 封装数据库 CRUD |
| service | `services/` | 业务逻辑、组合多个仓储 |
| schema | `schemas/` | 输入校验与输出序列化 |
| blueprint(API) | `blueprints/` | HTTP 路由 / 参数获取 / 返回 |

## 配置
环境通过环境变量 `FLASK_ENV` / 自定义传入 `create_app("production")` 选择。
可用变量:
- `DATABASE_URL` (默认 sqlite:///app.db)
- `SECRET_KEY`
- `CACHE_TYPE` (默认 SimpleCache)

## 部署 (Gunicorn 示例)
需要验证真实外部链路时,再单独运行集成测试:

```bash
gunicorn 'compute_cluster_manage_web.wsgi:app' -b 0.0.0.0:8000 --workers 4
pytest -m integration
```

## 后续可扩展建议
- 使用 `python-dotenv` 加载 `.env`
- 引入 Alembic 版本号命名策略 / 预置 seed 脚本
- 集成单元测试 (pytest + factory-boy)
- 使用真实密码哈希: `from werkzeug.security import generate_password_hash`
- 增加 JWT 或 Session 认证流程
## 目录结构

```text
api/ # FastAPI 路由与依赖
schemas/ # API 请求与响应结构
models/ # 数据模型
repositories/ # 数据访问
services/ # 业务逻辑
schedulers/ # 后台任务
utils/ # 通用工具
migrations/ # 数据库迁移脚本
run.py # 本地启动入口
asgi.py # ASGI 应用入口
```

## 开发约定

数据库事务边界放在 service/tasks 层,repository 只接收显式传入的 session 并执行数据读写。这个约定主要是为了让 API、后台任务和 WSS 使用同一套数据库访问方式,降低排错成本。
Loading
Loading