调整lsfx-mock默认数据库配置并更新NAS部署环境
This commit is contained in:
@@ -104,6 +104,9 @@ copy_path "${REPO_ROOT}/ruoyi-ui/dist" "${STAGE_ROOT}/frontend/dist"
|
|||||||
copy_path "${REPO_ROOT}/docker-compose.yml" "${STAGE_ROOT}/docker-compose.yml"
|
copy_path "${REPO_ROOT}/docker-compose.yml" "${STAGE_ROOT}/docker-compose.yml"
|
||||||
copy_path "${REPO_ROOT}/.env.example" "${STAGE_ROOT}/.env.example"
|
copy_path "${REPO_ROOT}/.env.example" "${STAGE_ROOT}/.env.example"
|
||||||
copy_path "${REPO_ROOT}/ruoyi-admin/target/ruoyi-admin.jar" "${STAGE_ROOT}/backend/ruoyi-admin.jar"
|
copy_path "${REPO_ROOT}/ruoyi-admin/target/ruoyi-admin.jar" "${STAGE_ROOT}/backend/ruoyi-admin.jar"
|
||||||
|
python3 "${SCRIPT_DIR}/render_nas_env.py" \
|
||||||
|
--template "${REPO_ROOT}/.env.example" \
|
||||||
|
--output "${STAGE_ROOT}/.env"
|
||||||
|
|
||||||
echo "[5/5] 上传并远端部署"
|
echo "[5/5] 上传并远端部署"
|
||||||
ensure_paramiko
|
ensure_paramiko
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ Copy-ItemSafe (Join-Path $repoRoot "ruoyi-ui\\dist") (Join-Path $stageRoot "fron
|
|||||||
Copy-ItemSafe (Join-Path $repoRoot "docker-compose.yml") (Join-Path $stageRoot "docker-compose.yml")
|
Copy-ItemSafe (Join-Path $repoRoot "docker-compose.yml") (Join-Path $stageRoot "docker-compose.yml")
|
||||||
Copy-ItemSafe (Join-Path $repoRoot ".env.example") (Join-Path $stageRoot ".env.example")
|
Copy-ItemSafe (Join-Path $repoRoot ".env.example") (Join-Path $stageRoot ".env.example")
|
||||||
Copy-ItemSafe (Join-Path $repoRoot "ruoyi-admin\\target\\ruoyi-admin.jar") (Join-Path $stageRoot "backend\\ruoyi-admin.jar")
|
Copy-ItemSafe (Join-Path $repoRoot "ruoyi-admin\\target\\ruoyi-admin.jar") (Join-Path $stageRoot "backend\\ruoyi-admin.jar")
|
||||||
|
python (Join-Path $scriptDir "render_nas_env.py") `
|
||||||
|
--template (Join-Path $repoRoot ".env.example") `
|
||||||
|
--output (Join-Path $stageRoot ".env")
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "生成 NAS 部署 .env 失败"
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "[5/5] 上传并远端部署"
|
Write-Host "[5/5] 上传并远端部署"
|
||||||
$paramikoCheck = @'
|
$paramikoCheck = @'
|
||||||
|
|||||||
47
deploy/render_nas_env.py
Normal file
47
deploy/render_nas_env.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
NAS_ENV_OVERRIDES = {
|
||||||
|
"CCDI_DB_HOST": "192.168.0.111",
|
||||||
|
"CCDI_DB_PORT": "40628",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = argparse.ArgumentParser(description="Render NAS deployment .env for CCDI docker compose.")
|
||||||
|
parser.add_argument("--template", required=True)
|
||||||
|
parser.add_argument("--output", required=True)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def render_env_text(template_text: str) -> str:
|
||||||
|
rendered_lines = []
|
||||||
|
replaced_keys = set()
|
||||||
|
|
||||||
|
for line in template_text.splitlines():
|
||||||
|
key, separator, value = line.partition("=")
|
||||||
|
if separator and key in NAS_ENV_OVERRIDES:
|
||||||
|
rendered_lines.append(f"{key}={NAS_ENV_OVERRIDES[key]}")
|
||||||
|
replaced_keys.add(key)
|
||||||
|
continue
|
||||||
|
rendered_lines.append(line)
|
||||||
|
|
||||||
|
for key, value in NAS_ENV_OVERRIDES.items():
|
||||||
|
if key not in replaced_keys:
|
||||||
|
rendered_lines.append(f"{key}={value}")
|
||||||
|
|
||||||
|
return "\n".join(rendered_lines) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
template_path = Path(args.template)
|
||||||
|
output_path = Path(args.output)
|
||||||
|
|
||||||
|
template_text = template_path.read_text(encoding="utf-8")
|
||||||
|
output_path.write_text(render_env_text(template_text), encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# LSFX Mock Server 默认数据库地址调整实施记录
|
||||||
|
|
||||||
|
**日期**: 2026-03-31
|
||||||
|
**范围**: `lsfx-mock-server` 配置
|
||||||
|
|
||||||
|
## 1. 调整内容
|
||||||
|
|
||||||
|
- 在 `lsfx-mock-server/config/settings.py` 中显式固定默认数据库地址:
|
||||||
|
- `CCDI_DB_HOST = 116.62.17.81`
|
||||||
|
- `CCDI_DB_PORT = 3307`
|
||||||
|
- 保持数据库名、用户名、密码继续沿用主工程 `application-dev.yml` 中的默认值读取逻辑
|
||||||
|
|
||||||
|
## 2. 调整原因
|
||||||
|
|
||||||
|
此前 `lsfx-mock-server` 的数据库 host/port 默认值隐式跟随 `ruoyi-admin` 的开发配置。虽然当前主工程配置本身也是 `116.62.17.81:3307`,但这种依赖关系不够直接。
|
||||||
|
|
||||||
|
本次改动后,`lsfx-mock-server` 会在自身配置层明确默认连接到 `116.62.17.81:3307`,避免后续主工程开发配置变化时影响 Mock 服务默认库选择。
|
||||||
|
|
||||||
|
## 3. 验证范围
|
||||||
|
|
||||||
|
- `lsfx-mock-server/tests/test_settings_sync.py`
|
||||||
|
- 校验默认 host/port 固定为 `116.62.17.81:3307`
|
||||||
|
- 校验数据库名、用户名、密码仍沿用主工程开发配置默认值
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# LSFX Mock Server 异常账户基线审计字段纠正实施记录
|
||||||
|
|
||||||
|
**日期**: 2026-03-31
|
||||||
|
**范围**: `lsfx-mock-server` 异常账户基线同步链路
|
||||||
|
|
||||||
|
## 1. 问题说明
|
||||||
|
|
||||||
|
在前一轮排查中,基于 MCP 表结构结果将 `ccdi_account_info` 的审计列误判为 `created_by`、`updated_by`,并据此调整了异常账户基线 upsert SQL。
|
||||||
|
|
||||||
|
随后使用 `mysql` 直连 `116.62.17.81:3307/ccdi` 执行:
|
||||||
|
|
||||||
|
- `SHOW COLUMNS FROM ccdi_account_info LIKE 'create_by';`
|
||||||
|
- `SHOW COLUMNS FROM ccdi_account_info LIKE 'update_by';`
|
||||||
|
- `SHOW COLUMNS FROM ccdi_account_info;`
|
||||||
|
|
||||||
|
确认真实表结构使用的是 `create_by`、`update_by`。
|
||||||
|
|
||||||
|
## 2. 本次纠正内容
|
||||||
|
|
||||||
|
- 修正 `lsfx-mock-server/services/abnormal_account_baseline_service.py`
|
||||||
|
- upsert 字段改回 `create_by`、`update_by`
|
||||||
|
- 更新分支改回 `update_by = VALUES(update_by)`
|
||||||
|
- 修正 `sql/migration/2026-03-31-create-ccdi-account-info-and-abnormal-account-rules.sql`
|
||||||
|
- `ccdi_account_info` 建表字段改回 `create_by`、`update_by`
|
||||||
|
- 规则初始化 SQL 的审计字段改回 `create_by` / `update_by`
|
||||||
|
- 修正 `sql/migration/2026-03-31-add-abnormal-account-rule-test-data.sql`
|
||||||
|
- `ccdi_account_info` 测试数据插入字段改回 `create_by`、`update_by`
|
||||||
|
- 修正 `docs/design/2026-03-31-lsfx-mock-server-abnormal-account-baseline-sync-design.md`
|
||||||
|
- 将设计文档中的账户表审计字段名改回真实库定义
|
||||||
|
|
||||||
|
## 3. 测试调整
|
||||||
|
|
||||||
|
- 更新 `lsfx-mock-server/tests/test_abnormal_account_baseline_service.py`
|
||||||
|
- 锁定 insert SQL 必须包含 `create_by`、`update_by`
|
||||||
|
- 锁定 upsert update 分支必须写 `update_by = VALUES(update_by)`
|
||||||
|
|
||||||
|
## 4. 结果
|
||||||
|
|
||||||
|
- 异常账户基线同步 SQL 已与 `116.62.17.81:3307/ccdi` 的真实表结构重新对齐
|
||||||
|
- 运行时不会再向不存在的 `created_by`、`updated_by` 字段写值
|
||||||
|
- 服务代码、migration、测试数据脚本与设计文档已恢复一致
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# NAS 部署脚本 LSFX Mock 数据库地址调整实施记录
|
||||||
|
|
||||||
|
**日期**: 2026-03-31
|
||||||
|
**范围**: NAS 部署脚本、部署配置
|
||||||
|
|
||||||
|
## 1. 本次调整
|
||||||
|
|
||||||
|
- 新增 `deploy/render_nas_env.py`
|
||||||
|
- 基于根目录 `.env.example` 渲染 NAS 部署专用 `.env`
|
||||||
|
- 固定输出:
|
||||||
|
- `CCDI_DB_HOST=192.168.0.111`
|
||||||
|
- `CCDI_DB_PORT=40628`
|
||||||
|
- 调整 `deploy/deploy-to-nas.sh`
|
||||||
|
- 在组装部署目录阶段生成 `${STAGE_ROOT}/.env`
|
||||||
|
- 调整 `deploy/deploy.ps1`
|
||||||
|
- 与 Shell 部署入口保持一致,在组装部署目录阶段生成 `${stageRoot}\\.env`
|
||||||
|
|
||||||
|
## 2. 调整目的
|
||||||
|
|
||||||
|
确保 NAS 部署后的 `lsfx-mock-server` 读取部署包中的 `.env`,从而连接:
|
||||||
|
|
||||||
|
- Host: `192.168.0.111`
|
||||||
|
- Port: `40628`
|
||||||
|
|
||||||
|
同时保持本地 `docker-compose.yml` 默认值不变,不影响本地开发和手工启动。
|
||||||
|
|
||||||
|
## 3. 验证范围
|
||||||
|
|
||||||
|
- `tests/deploy/test_render_nas_env.py`
|
||||||
|
- 校验渲染后的 `.env` 包含 `CCDI_DB_HOST=192.168.0.111`
|
||||||
|
- 校验渲染后的 `.env` 包含 `CCDI_DB_PORT=40628`
|
||||||
|
- `tests/deploy/test_deploy_to_nas.py`
|
||||||
|
- 校验 `deploy-to-nas.sh` 已接入 `render_nas_env.py`
|
||||||
|
- 校验部署目录会生成 `${STAGE_ROOT}/.env`
|
||||||
@@ -26,6 +26,8 @@ def _load_ruoyi_mysql_defaults() -> dict:
|
|||||||
|
|
||||||
|
|
||||||
MYSQL_DEFAULTS = _load_ruoyi_mysql_defaults()
|
MYSQL_DEFAULTS = _load_ruoyi_mysql_defaults()
|
||||||
|
LSFX_DEFAULT_CCDI_DB_HOST = "116.62.17.81"
|
||||||
|
LSFX_DEFAULT_CCDI_DB_PORT = 3307
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
@@ -50,8 +52,8 @@ class Settings(BaseSettings):
|
|||||||
INITIAL_LOG_ID: int = 10000
|
INITIAL_LOG_ID: int = 10000
|
||||||
|
|
||||||
# 员工库只读配置
|
# 员工库只读配置
|
||||||
CCDI_DB_HOST: str = MYSQL_DEFAULTS.get("host", "")
|
CCDI_DB_HOST: str = LSFX_DEFAULT_CCDI_DB_HOST
|
||||||
CCDI_DB_PORT: int = int(MYSQL_DEFAULTS.get("port", 3306))
|
CCDI_DB_PORT: int = LSFX_DEFAULT_CCDI_DB_PORT
|
||||||
CCDI_DB_NAME: str = MYSQL_DEFAULTS.get("database", "")
|
CCDI_DB_NAME: str = MYSQL_DEFAULTS.get("database", "")
|
||||||
CCDI_DB_USERNAME: str = MYSQL_DEFAULTS.get("username", "")
|
CCDI_DB_USERNAME: str = MYSQL_DEFAULTS.get("username", "")
|
||||||
CCDI_DB_PASSWORD: str = MYSQL_DEFAULTS.get("password", "")
|
CCDI_DB_PASSWORD: str = MYSQL_DEFAULTS.get("password", "")
|
||||||
|
|||||||
@@ -96,6 +96,10 @@ def test_apply_should_insert_new_account_fact_by_account_no():
|
|||||||
assert len(fake_connection.executed_sql) == 1
|
assert len(fake_connection.executed_sql) == 1
|
||||||
executed = fake_connection.executed_sql[0]
|
executed = fake_connection.executed_sql[0]
|
||||||
assert "INSERT INTO ccdi_account_info" in executed["sql"]
|
assert "INSERT INTO ccdi_account_info" in executed["sql"]
|
||||||
|
assert "create_by" in executed["sql"]
|
||||||
|
assert "update_by" in executed["sql"]
|
||||||
|
assert "created_by" not in executed["sql"]
|
||||||
|
assert "updated_by" not in executed["sql"]
|
||||||
assert executed["params"] == (
|
assert executed["params"] == (
|
||||||
"6222000000000001",
|
"6222000000000001",
|
||||||
"DEBIT",
|
"DEBIT",
|
||||||
@@ -140,6 +144,7 @@ def test_apply_should_update_existing_account_fact_by_account_no():
|
|||||||
assert len(fake_connection.executed_sql) == 1
|
assert len(fake_connection.executed_sql) == 1
|
||||||
executed = fake_connection.executed_sql[0]
|
executed = fake_connection.executed_sql[0]
|
||||||
assert "ON DUPLICATE KEY UPDATE" in executed["sql"]
|
assert "ON DUPLICATE KEY UPDATE" in executed["sql"]
|
||||||
|
assert "update_by = VALUES(update_by)" in executed["sql"]
|
||||||
assert executed["params"][0] == "6222000000000001"
|
assert executed["params"][0] == "6222000000000001"
|
||||||
assert executed["params"][2] == "测试员工结算卡"
|
assert executed["params"][2] == "测试员工结算卡"
|
||||||
assert executed["params"][10] == 1
|
assert executed["params"][10] == 1
|
||||||
|
|||||||
@@ -15,11 +15,14 @@ def test_ruoyi_mysql_defaults_should_follow_application_dev_config():
|
|||||||
assert _load_ruoyi_mysql_defaults()["port"] == match.group("port")
|
assert _load_ruoyi_mysql_defaults()["port"] == match.group("port")
|
||||||
|
|
||||||
|
|
||||||
def test_settings_should_use_ruoyi_mysql_defaults():
|
def test_settings_should_default_to_lsfx_target_mysql_host_and_port():
|
||||||
|
assert settings.CCDI_DB_HOST == "116.62.17.81"
|
||||||
|
assert settings.CCDI_DB_PORT == 3307
|
||||||
|
|
||||||
|
|
||||||
|
def test_settings_should_still_use_ruoyi_mysql_defaults_for_db_name_and_credentials():
|
||||||
defaults = _load_ruoyi_mysql_defaults()
|
defaults = _load_ruoyi_mysql_defaults()
|
||||||
|
|
||||||
assert settings.CCDI_DB_HOST == defaults["host"]
|
|
||||||
assert settings.CCDI_DB_PORT == int(defaults["port"])
|
|
||||||
assert settings.CCDI_DB_NAME == defaults["database"]
|
assert settings.CCDI_DB_NAME == defaults["database"]
|
||||||
assert settings.CCDI_DB_USERNAME == defaults["username"]
|
assert settings.CCDI_DB_USERNAME == defaults["username"]
|
||||||
assert settings.CCDI_DB_PASSWORD == defaults["password"]
|
assert settings.CCDI_DB_PASSWORD == defaults["password"]
|
||||||
|
|||||||
@@ -43,3 +43,10 @@ def test_sh_dry_run_accepts_override_arguments():
|
|||||||
assert "Port: 2222" in result.stdout
|
assert "Port: 2222" in result.stdout
|
||||||
assert "Username: deploy-user" in result.stdout
|
assert "Username: deploy-user" in result.stdout
|
||||||
assert "RemoteRoot: /volume2/custom/app" in result.stdout
|
assert "RemoteRoot: /volume2/custom/app" in result.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_sh_script_should_render_nas_env_into_stage_package():
|
||||||
|
script_text = SCRIPT_PATH.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert 'render_nas_env.py' in script_text
|
||||||
|
assert '"${STAGE_ROOT}/.env"' in script_text
|
||||||
|
|||||||
37
tests/deploy/test_render_nas_env.py
Normal file
37
tests/deploy/test_render_nas_env.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
SCRIPT_PATH = REPO_ROOT / "deploy" / "render_nas_env.py"
|
||||||
|
ENV_TEMPLATE = REPO_ROOT / ".env.example"
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_nas_env_should_generate_lsfx_mock_db_override_file():
|
||||||
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||||
|
output_path = Path(tmp_dir) / ".env"
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
[
|
||||||
|
"python3",
|
||||||
|
str(SCRIPT_PATH),
|
||||||
|
"--template",
|
||||||
|
str(ENV_TEMPLATE),
|
||||||
|
"--output",
|
||||||
|
str(output_path),
|
||||||
|
],
|
||||||
|
cwd=REPO_ROOT,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.returncode == 0
|
||||||
|
assert output_path.exists()
|
||||||
|
|
||||||
|
env_text = output_path.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert "CCDI_DB_HOST=192.168.0.111" in env_text
|
||||||
|
assert "CCDI_DB_PORT=40628" in env_text
|
||||||
|
assert "CCDI_DB_NAME=ccdi" in env_text
|
||||||
|
|
||||||
Reference in New Issue
Block a user