diff --git a/openflare_agent/internal/nginx/manager.go b/openflare_agent/internal/nginx/manager.go index 063f654d..c57991fd 100644 --- a/openflare_agent/internal/nginx/manager.go +++ b/openflare_agent/internal/nginx/manager.go @@ -128,7 +128,18 @@ func (e *DockerExecutor) Test(ctx context.Context) error { } func (e *DockerExecutor) Reload(ctx context.Context) error { - return e.EnsureRuntime(ctx, true) + if err := e.validateMountSources(); err != nil { + return err + } + output, err := e.Runner.Run(ctx, e.DockerBinary, "inspect", "-f", "{{.State.Running}}", e.ContainerName) + if err != nil || strings.TrimSpace(string(output)) != "true" { + return e.EnsureRuntime(ctx, false) + } + output, err = e.Runner.Run(ctx, e.DockerBinary, "exec", e.ContainerName, dockerRuntimeCommand, "-s", "reload") + if err != nil { + return fmt.Errorf("docker exec %s reload failed: %w: %s", dockerRuntimeCommand, err, string(output)) + } + return nil } func (e *DockerExecutor) EnsureRuntime(ctx context.Context, recreate bool) error { @@ -301,11 +312,6 @@ func (m *Manager) Apply(ctx context.Context, mainConfig string, routeConfig stri _ = m.restore(backup) return err } - if err = m.Executor.Test(ctx); err != nil { - slog.Error("openresty test failed after config write, restoring backup", "error", err) - _ = m.restore(backup) - return err - } if err = m.Executor.Reload(ctx); err != nil { slog.Error("openresty reload failed after config write, restoring backup", "error", err) _ = m.restore(backup) diff --git a/openflare_agent/internal/nginx/manager_test.go b/openflare_agent/internal/nginx/manager_test.go index 85b0744b..a6d1da3c 100644 --- a/openflare_agent/internal/nginx/manager_test.go +++ b/openflare_agent/internal/nginx/manager_test.go @@ -217,17 +217,56 @@ func TestDockerExecutorStartsStoppedContainer(t *testing.T) { t.Fatalf("Reload failed: %v", err) } - if len(runner.calls) != 3 { - t.Fatalf("expected 3 calls, got %d", len(runner.calls)) + if len(runner.calls) != 4 { + t.Fatalf("expected 4 calls, got %d", len(runner.calls)) } if runner.calls[0].args[0] != "inspect" { t.Fatalf("expected docker inspect on first call, got %#v", runner.calls[0]) } - if runner.calls[1].args[0] != "rm" { - t.Fatalf("expected docker rm on second call, got %#v", runner.calls[1]) + if runner.calls[1].args[0] != "inspect" { + t.Fatalf("expected docker inspect on second call, got %#v", runner.calls[1]) } - if runner.calls[2].args[0] != "run" { - t.Fatalf("expected docker run on third call, got %#v", runner.calls[2]) + if runner.calls[2].args[0] != "rm" { + t.Fatalf("expected docker rm on third call, got %#v", runner.calls[2]) + } + if runner.calls[3].args[0] != "run" { + t.Fatalf("expected docker run on fourth call, got %#v", runner.calls[3]) + } +} + +func TestDockerExecutorReloadsRunningContainerInPlace(t *testing.T) { + mainConfigPath, routeConfigDir, certDir, luaDir := prepareDockerMountSources(t) + runner := &fakeRunner{ + runFn: func(name string, args ...string) ([]byte, error) { + if len(args) >= 1 && args[0] == "inspect" { + return []byte("true"), nil + } + return []byte("ok"), nil + }, + } + executor := &DockerExecutor{ + DockerBinary: "docker", + ContainerName: "openflare-openresty", + Image: "openresty/openresty:alpine", + MainConfigPath: mainConfigPath, + RouteConfigDir: routeConfigDir, + CertDir: certDir, + NginxCertDir: "/etc/nginx/openflare-certs", + LuaDir: luaDir, + NginxLuaDir: "/etc/nginx/openflare-lua", + Runner: runner, + } + + if err := executor.Reload(context.Background()); err != nil { + t.Fatalf("Reload failed: %v", err) + } + + expected := []runCall{ + {name: "docker", args: []string{"inspect", "-f", "{{.State.Running}}", "openflare-openresty"}}, + {name: "docker", args: []string{"exec", "openflare-openresty", "openresty", "-s", "reload"}}, + } + if !reflect.DeepEqual(runner.calls, expected) { + t.Fatalf("unexpected calls: %#v", runner.calls) } } @@ -676,7 +715,7 @@ func TestManagerRollbackRestoresCertFiles(t *testing.T) { LuaDir: filepath.Join(tempDir, "lua"), NginxLuaDir: "/etc/nginx/openflare-lua", Executor: &fakeExecutor{ - testErr: errors.New("openresty test failed"), + reloadErr: errors.New("openresty reload failed"), }, }