Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 62 additions & 8 deletions internal/infra/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,16 +712,55 @@ func (m *Manager) EnsureBaseNginxConfig() error {
if err != nil {
return err
}
if string(nginxConf) == string(existing) {
return nil
changed, err := writeFileIfChanged(confPath, nginxConf, 0644)
if err != nil {
return err
}

if err := os.WriteFile(confPath, nginxConf, 0644); err != nil {
return err
if luaEnabled {
luaDir := filepath.Join(nginxDir, "lua")
if err := os.MkdirAll(luaDir, 0755); err != nil {
return err
}
agentIP := m.GetDockerHostIP()
agentPort := m.GetAgentPort()
securityLua, err := templates.GetNginxSecurityLuaWithConfig(agentIP, agentPort, m.config.Security.InternalAPIToken, m.config.Security.TrustedProxies, m.config.Security.TrustCFHeader)
if err != nil {
return err
}
securityChanged, err := writeFileIfChanged(filepath.Join(luaDir, "security.lua"), securityLua, 0644)
if err != nil {
return err
}
changed = changed || securityChanged

trafficLua, err := templates.GetNginxTrafficLuaWithConfig(agentIP, agentPort)
if err != nil {
return err
}
trafficChanged, err := writeFileIfChanged(filepath.Join(luaDir, "traffic.lua"), trafficLua, 0644)
if err != nil {
return err
}
changed = changed || trafficChanged

errorPage, err := templates.GetErrorPage()
if err != nil {
return err
}
errorPagePath := filepath.Join(nginxDir, "html", ".flatrun", "error.html")
if err := os.MkdirAll(filepath.Dir(errorPagePath), 0755); err != nil {
return err
}
errorPageChanged, err := writeFileIfChanged(errorPagePath, errorPage, 0644)
if err != nil {
return err
}
changed = changed || errorPageChanged
}
if changed {
_ = m.reloadNginx()
}
// Best-effort reload: the rewritten config also takes effect on the next nginx
// restart, so a reload failure here (e.g. container not yet ready) is not fatal.
_ = m.reloadNginx()
return nil
}

Expand Down Expand Up @@ -1456,5 +1495,20 @@ func writeNginxErrorPage(nginxDir string) error {
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return err
}
return os.WriteFile(path, content, 0644)
_, err = writeFileIfChanged(path, content, 0644)
return err
}

func writeFileIfChanged(path string, content []byte, mode os.FileMode) (bool, error) {
existing, err := os.ReadFile(path)
if err == nil && bytes.Equal(existing, content) {
return false, nil
}
if err != nil && !os.IsNotExist(err) {
return false, err
}
if err := os.WriteFile(path, content, mode); err != nil {
return false, err
}
return true, nil
}
49 changes: 49 additions & 0 deletions internal/infra/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/flatrun/agent/pkg/config"
"github.com/flatrun/agent/templates"
)

func TestSetNginxRealtimeCapture(t *testing.T) {
Expand Down Expand Up @@ -240,6 +241,54 @@ func TestEnsureBaseNginxConfig(t *testing.T) {
if !strings.Contains(string(content), "server_names_hash_bucket_size") {
t.Errorf("refreshed config should contain server_names_hash_bucket_size, got:\n%s", content)
}
securityLua, err := os.ReadFile(filepath.Join(nginxDir, "lua", "security.lua"))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(securityLua), "function _M.prepare_error_response()") {
t.Errorf("refreshed security.lua is missing error response support")
}
if _, err := os.Stat(filepath.Join(nginxDir, "lua", "traffic.lua")); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(nginxDir, "html", ".flatrun", "error.html")); err != nil {
t.Fatal(err)
}
})

t.Run("refreshes stale lua beside a current config", func(t *testing.T) {
nginxDir := t.TempDir()
confPath := filepath.Join(nginxDir, "nginx.conf")
current, err := templates.GetNginxConfigWithData(true, templates.NginxConfigData{})
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(confPath, current, 0644); err != nil {
t.Fatal(err)
}
luaDir := filepath.Join(nginxDir, "lua")
if err := os.MkdirAll(luaDir, 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(luaDir, "security.lua"), []byte("return {}\n"), 0644); err != nil {
t.Fatal(err)
}

cfg := &config.Config{
DeploymentsPath: nginxDir,
Nginx: config.NginxConfig{ConfigPath: filepath.Join(nginxDir, "conf.d")},
}
if err := NewManager(cfg).EnsureBaseNginxConfig(); err != nil {
t.Fatalf("EnsureBaseNginxConfig() = %v", err)
}

securityLua, err := os.ReadFile(filepath.Join(luaDir, "security.lua"))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(securityLua), "function _M.prepare_error_response()") {
t.Errorf("stale security.lua was not refreshed")
}
})

t.Run("does not create a config where none exists", func(t *testing.T) {
Expand Down
Loading