fix(updater): 忽略容器路径并优先使用 Compose 配置目录
This commit is contained in:
@@ -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 文件
|
||||||
|
|
||||||
### 变更
|
### 变更
|
||||||
|
|
||||||
|
|||||||
@@ -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 仓库:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user