fix(updater): 忽略容器路径并优先使用 Compose 配置目录
CI / verify (push) Canceled after 0s

This commit is contained in:
2026-09-28 12:01:39 +08:00
parent 63538ec5b7
commit 49d4af27ca
4 changed files with 40 additions and 3 deletions
+1
View File
@@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
### 修复 ### 修复
- **限流状态损坏时拒绝覆盖**:`readLimitState` 原来忽略 JSON 解析错误并返回空 map,保存任一规则时可能把其他域名的限流配置清空。现在文件不存在仍视为空状态,读取失败、空文件或 JSON 损坏则返回错误,`applyLimitState` / `clearLimitState` 会保留原文件与现有 Nginx zone,不再覆盖 - **限流状态损坏时拒绝覆盖**:`readLimitState` 原来忽略 JSON 解析错误并返回空 map,保存任一规则时可能把其他域名的限流配置清空。现在文件不存在仍视为空状态,读取失败、空文件或 JSON 损坏则返回错误,`applyLimitState` / `clearLimitState` 会保留原文件与现有 Nginx zone,不再覆盖
- **一键升级宿主机目录自动发现**:当 Compose 标签里的 `working_dir` 是 `/workspace` 这类容器路径时,不再直接把它当宿主机目录;优先使用 `project.config_files` 推导真实目录,无法得到宿主机路径时明确报错,避免 helper 挂载 `/workspace:/workspace` 后找不到 Compose 文件
### 变更 ### 变更
+4
View File
@@ -188,6 +188,10 @@ docker compose -f /实际/的/Compose/目录/docker-compose.hub.yml up -d --buil
如果现有 `fonu` 容器不是由 Compose 管理,updater 会拒绝升级,避免新建 `fonu_fonu-data` 等空数据卷。应先按 Compose 方式重新部署,再使用一键升级。 如果现有 `fonu` 容器不是由 Compose 管理,updater 会拒绝升级,避免新建 `fonu_fonu-data` 等空数据卷。应先按 Compose 方式重新部署,再使用一键升级。
### helper 命令里出现 `-v /workspace:/workspace`
说明 Compose 标签只返回了容器内路径。更新后的 updater 会优先从 `project.config_files` 标签推导宿主机目录,并忽略 `/workspace` 这类容器路径。若标签仍无法提供真实宿主机路径,应检查部署工具的 Compose 标签是否完整;正常情况下无需手工设置目录。
### `docker-compose.hub.yml` 模式无法读取远端版本 ### `docker-compose.hub.yml` 模式无法读取远端版本
检查 sidecar 容器内是否可以访问 Git 仓库: 检查 sidecar 容器内是否可以访问 Git 仓库:
+18 -3
View File
@@ -230,7 +230,7 @@ func (s *Server) composeProjectName(ctx context.Context) (string, error) {
} }
func (s *Server) discoverHostCompose(ctx context.Context) (string, string, error) { func (s *Server) discoverHostCompose(ctx context.Context) (string, string, error) {
if s.cfg.HostProjectDir != "" { if s.cfg.HostProjectDir != "" && !isContainerPath(s.cfg.HostProjectDir, s.cfg.ProjectDir) {
if !filepath.IsAbs(s.cfg.HostProjectDir) { if !filepath.IsAbs(s.cfg.HostProjectDir) {
return "", "", fmt.Errorf("FONU_UPDATE_HOST_DIR 必须是绝对路径") return "", "", fmt.Errorf("FONU_UPDATE_HOST_DIR 必须是绝对路径")
} }
@@ -241,17 +241,32 @@ func (s *Server) discoverHostCompose(ctx context.Context) (string, string, error
hostDir := strings.TrimSpace(workingDir) hostDir := strings.TrimSpace(workingDir)
hostCompose := chooseComposeFile(configFiles, filepath.Base(s.cfg.ComposeFile)) hostCompose := chooseComposeFile(configFiles, filepath.Base(s.cfg.ComposeFile))
if hostCompose == "" { if hostCompose == "" {
return "", "", fmt.Errorf("无法从容器标签读取 Compose 文件") if hostDir == "" || isContainerPath(hostDir, s.cfg.ProjectDir) {
return "", "", fmt.Errorf("无法从容器标签读取宿主机 Compose 目录")
} }
if hostDir == "" { hostCompose = filepath.Join(hostDir, filepath.Base(s.cfg.ComposeFile))
}
if hostDir == "" || isContainerPath(hostDir, s.cfg.ProjectDir) {
hostDir = filepath.Dir(hostCompose) hostDir = filepath.Dir(hostCompose)
} }
if !filepath.IsAbs(hostDir) || !filepath.IsAbs(hostCompose) { if !filepath.IsAbs(hostDir) || !filepath.IsAbs(hostCompose) {
return "", "", fmt.Errorf("容器标签中的 Compose 路径不是绝对路径") return "", "", fmt.Errorf("容器标签中的 Compose 路径不是绝对路径")
} }
if isContainerPath(hostDir, s.cfg.ProjectDir) {
return "", "", fmt.Errorf("容器标签只提供了容器内路径 %s,无法定位宿主机 Compose 目录", hostDir)
}
return filepath.Clean(hostDir), filepath.Clean(hostCompose), nil return filepath.Clean(hostDir), filepath.Clean(hostCompose), nil
} }
func isContainerPath(path, containerDir string) bool {
path = filepath.Clean(strings.TrimSpace(path))
containerDir = filepath.Clean(strings.TrimSpace(containerDir))
if path == "" || containerDir == "" || path == "." {
return false
}
return path == containerDir || strings.HasPrefix(path, containerDir+string(filepath.Separator))
}
func (s *Server) dockerLabel(ctx context.Context, label string) (string, error) { func (s *Server) dockerLabel(ctx context.Context, label string) (string, error) {
format := fmt.Sprintf(`{{ index .Config.Labels %q }}`, label) format := fmt.Sprintf(`{{ index .Config.Labels %q }}`, label)
checkCtx, cancel := context.WithTimeout(ctx, 5*time.Second) checkCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
+17
View File
@@ -85,3 +85,20 @@ func TestResolveComposePlanUsesHostProjectDir(t *testing.T) {
t.Fatalf("helper compose 路径不正确: %s", plan.helperComposePath) t.Fatalf("helper compose 路径不正确: %s", plan.helperComposePath)
} }
} }
func TestIsContainerPath(t *testing.T) {
cases := []struct {
path string
want bool
}{
{"/workspace", true},
{"/workspace/docker-compose.yml", true},
{"/vol1/1000/Docker/mafrp", false},
{"/vol1/1000/Docker/mafrp/docker-compose.yml", false},
}
for _, tc := range cases {
if got := isContainerPath(tc.path, "/workspace"); got != tc.want {
t.Fatalf("isContainerPath(%q) = %v, want %v", tc.path, got, tc.want)
}
}
}