feat: filesync 模块 — 从 FOMS 单体拆分出的独立模块
This commit is contained in:
commit
b47ca80eda
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.egg-info/
|
||||
dist/
|
||||
build/
|
||||
py3/
|
||||
models/mysql.ddl.sql
|
||||
.DS_Store
|
||||
17
README.md
Normal file
17
README.md
Normal file
@ -0,0 +1,17 @@
|
||||
# filesync — 运行文件同步模块
|
||||
|
||||
FOMS 平台拆出的独立模块之一。松耦合:表 `cluster_id` 仅存字符串 ID,不建外键,
|
||||
rsync 执行由 Agent 完成,管理中心只存配置、收结果。
|
||||
|
||||
| 功能 | 表 | 说明 |
|
||||
|---|---|---|
|
||||
| 文件目录同步 | `filesync_directories` | rsync 同步配置,原 `sync_directories` |
|
||||
|
||||
端点:
|
||||
- `/filesync/api/agent_report_dir_health.dspy` — Agent 上报 rsync 结果
|
||||
|
||||
加载:
|
||||
```python
|
||||
from filesync.init import load_filesync
|
||||
load_filesync()
|
||||
```
|
||||
1
__init__.py
Normal file
1
__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .init import load_filesync # noqa: F401
|
||||
18
build.sh
Normal file
18
build.sh
Normal file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# filesync 模块 build:生成 DDL + CRUD 页面(xls2ui)
|
||||
set -e
|
||||
cdir=$(pwd)
|
||||
|
||||
if [ -d models ]; then
|
||||
json2ddl mysql models/ > "$cdir/models/mysql.ddl.sql" 2>/dev/null || echo " skip ddl"
|
||||
fi
|
||||
|
||||
if [ -d json ]; then
|
||||
cd "$cdir/json"
|
||||
for f in *.json; do
|
||||
echo " xls2ui $f"
|
||||
xls2ui -m ../models -o ../wwwroot filesync "$f" 2>/dev/null || echo " skipped"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "=== filesync Build Complete ==="
|
||||
1
filesync/__init__.py
Normal file
1
filesync/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# filesync 模块 — 运行文件同步管理
|
||||
97
filesync/init.py
Normal file
97
filesync/init.py
Normal file
@ -0,0 +1,97 @@
|
||||
"""filesync 模块 — 运行文件同步(rsync 目录同步)管理。
|
||||
|
||||
独立模块,松耦合设计:
|
||||
· 表 cluster_id 仅存字符串 ID,不建外键(引用 foms 核心的 clusters 表)。
|
||||
· 不 import foms 核心代码,可独立部署、独立测试。
|
||||
· rsync 实际执行由 Agent 在被管主机完成,管理中心只存配置、收结果。
|
||||
|
||||
表:
|
||||
filesync_directories 文件目录同步配置(原 sync_directories)
|
||||
"""
|
||||
import json
|
||||
from appPublic.uniqueID import getID
|
||||
from appPublic.timeUtils import curDateString
|
||||
from sqlor.dbpools import DBPools, get_sor_context
|
||||
from ahserver.serverenv import ServerEnv
|
||||
|
||||
DBNAME = 'foms'
|
||||
|
||||
|
||||
def _ns(params_kw):
|
||||
ns = dict(params_kw) if hasattr(params_kw, 'items') else {}
|
||||
for k in list(ns.keys()):
|
||||
if k.endswith('_text'):
|
||||
ns.pop(k)
|
||||
return ns
|
||||
|
||||
|
||||
def _get(params_kw, key, default=''):
|
||||
return params_kw.get(key, default) if hasattr(params_kw, 'get') else default
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 目录同步 CRUD
|
||||
# ═══════════════════════════════════════════
|
||||
|
||||
async def create_directory(request, params_kw):
|
||||
env = ServerEnv()
|
||||
async with get_sor_context(env, DBNAME) as sor:
|
||||
ns = _ns(params_kw)
|
||||
ns['id'] = getID()
|
||||
ns['created_at'] = curDateString()
|
||||
ns['updated_at'] = curDateString()
|
||||
await sor.C('filesync_directories', ns)
|
||||
return {'widgettype': 'Message', 'options': {'title': '成功', 'message': '同步配置创建成功', 'type': 'success'}}
|
||||
|
||||
|
||||
async def update_directory(request, params_kw):
|
||||
env = ServerEnv()
|
||||
async with get_sor_context(env, DBNAME) as sor:
|
||||
ns = _ns(params_kw)
|
||||
ns['updated_at'] = curDateString()
|
||||
await sor.U('filesync_directories', ns)
|
||||
return {'widgettype': 'Message', 'options': {'title': '成功', 'message': '同步配置更新成功', 'type': 'success'}}
|
||||
|
||||
|
||||
async def delete_directory(request, params_kw):
|
||||
env = ServerEnv()
|
||||
async with get_sor_context(env, DBNAME) as sor:
|
||||
await sor.D('filesync_directories', {'id': _get(params_kw, 'id')})
|
||||
return {'widgettype': 'Message', 'options': {'title': '成功', 'message': '同步配置已删除', 'type': 'success'}}
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# Agent 上报:同步结果(原 agent_report_health 的 dir 分支)
|
||||
# ═══════════════════════════════════════════
|
||||
|
||||
async def agent_report_dir_health(request, params_kw):
|
||||
"""Agent 上报 rsync 同步结果"""
|
||||
env = ServerEnv()
|
||||
dir_statuses = _get(params_kw, 'dir_statuses', [])
|
||||
if isinstance(dir_statuses, str):
|
||||
dir_statuses = json.loads(dir_statuses)
|
||||
async with get_sor_context(env, DBNAME) as sor:
|
||||
for dir_stat in dir_statuses:
|
||||
await sor.U('filesync_directories', {
|
||||
'id': dir_stat.get('id'),
|
||||
'last_sync_at': curDateString(),
|
||||
'last_sync_result': dir_stat.get('result'),
|
||||
'updated_at': curDateString(),
|
||||
})
|
||||
return {'status': 'ok'}
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 注册
|
||||
# ═══════════════════════════════════════════
|
||||
|
||||
def load_filesync():
|
||||
env = ServerEnv()
|
||||
env.create_directory = create_directory
|
||||
env.create_filesync_directories = create_directory
|
||||
env.update_directory = update_directory
|
||||
env.update_filesync_directories = update_directory
|
||||
env.delete_directory = delete_directory
|
||||
env.delete_filesync_directories = delete_directory
|
||||
env.agent_report_dir_health = agent_report_dir_health
|
||||
return True
|
||||
16
json/filesync_directories_list.json
Normal file
16
json/filesync_directories_list.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"tblname": "filesync_directories",
|
||||
"alias": "filesync_directories_list",
|
||||
"title": "文件目录同步配置",
|
||||
"params": {
|
||||
"sortby": ["updated_at desc"],
|
||||
"browserfields": {
|
||||
"exclouded": ["id"],
|
||||
"alters": {
|
||||
"last_sync_result": {"uitype": "code"},
|
||||
"enabled": {"uitype": "code", "data": [{"value": "1", "text": "启用"}, {"value": "0", "text": "禁用"}]},
|
||||
"cluster_id": {"uitype": "code", "valueField": "id", "textField": "name"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
models/filesync_directories.json
Normal file
33
models/filesync_directories.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"summary": [
|
||||
{
|
||||
"name": "filesync_directories",
|
||||
"title": "文件目录同步配置",
|
||||
"primary": ["id"],
|
||||
"catelog": "entity"
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{"name": "id", "title": "配置ID", "type": "str", "length": 32, "nullable": "no"},
|
||||
{"name": "cluster_id", "title": "所属集群", "type": "str", "length": 32, "nullable": "no"},
|
||||
{"name": "name", "title": "同步任务名称", "type": "str", "length": 128, "nullable": "no"},
|
||||
{"name": "source_host", "title": "源主机", "type": "str", "length": 255},
|
||||
{"name": "source_path", "title": "源目录路径", "type": "str", "length": 512, "nullable": "no"},
|
||||
{"name": "dest_host", "title": "目标主机", "type": "str", "length": 255},
|
||||
{"name": "dest_path", "title": "目标目录路径", "type": "str", "length": 512, "nullable": "no"},
|
||||
{"name": "sync_interval", "title": "同步间隔(秒)", "type": "int", "nullable": "no", "default": "60"},
|
||||
{"name": "exclude_patterns", "title": "排除模式", "type": "str", "length": 512},
|
||||
{"name": "last_sync_at", "title": "上次同步时间", "type": "datetime"},
|
||||
{"name": "last_sync_result", "title": "上次同步结果", "type": "str", "length": 32},
|
||||
{"name": "enabled", "title": "启用", "type": "str", "length": 1, "nullable": "no", "default": "1"},
|
||||
{"name": "created_at", "title": "创建时间", "type": "datetime"},
|
||||
{"name": "updated_at", "title": "更新时间", "type": "datetime"}
|
||||
],
|
||||
"indexes": [
|
||||
{"name": "idx_filesync_dir_cluster", "idxtype": "index", "idxfields": ["cluster_id"]}
|
||||
],
|
||||
"codes": [
|
||||
{"field": "last_sync_result", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='sync_result'"},
|
||||
{"field": "cluster_id", "table": "clusters", "valuefield": "id", "textfield": "name"}
|
||||
]
|
||||
}
|
||||
16
pyproject.toml
Normal file
16
pyproject.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=45", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "filesync"
|
||||
version = "1.0.0"
|
||||
description = "运行文件同步模块 — rsync 目录同步配置与状态管理"
|
||||
requires-python = ">=3.8"
|
||||
dependencies = [
|
||||
"sqlor",
|
||||
]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
include = ["filesync*"]
|
||||
3
wwwroot/api/agent_report_dir_health.dspy
Normal file
3
wwwroot/api/agent_report_dir_health.dspy
Normal file
@ -0,0 +1,3 @@
|
||||
# Agent 上报 rsync 同步结果
|
||||
result = await agent_report_dir_health(request, params_kw)
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
Loading…
x
Reference in New Issue
Block a user