This commit is contained in:
ryan
2026-06-19 15:13:24 +08:00
parent 0b34792709
commit 32861c5db9
376 changed files with 3648 additions and 19957 deletions
+98 -52
View File
@@ -1,3 +1,4 @@
// Package nginx manages OpenResty configuration, runtime, and supporting assets.
package nginx
import (
@@ -26,10 +27,26 @@ import (
"github.com/Rain-kl/Wavelet/internal/apps/agent/protocol"
)
// RuntimeConfigDirPlaceholder is substituted into generated configs at apply time.
const RuntimeConfigDirPlaceholder = "__OPENFLARE_RUNTIME_CONFIG_DIR__"
const ResolverDirectivePlaceholder = "__OPENFLARE_RESOLVER_DIRECTIVE__"
const WAFIPGroupsConfigFileName = "waf_ip_groups.json"
// ResolverDirectivePlaceholder is substituted into generated configs at apply time.
const ResolverDirectivePlaceholder = "__OPENFLARE_RESOLVER_DIRECTIVE__"
// WAFIPGroupsConfigFileName is the runtime filename for synced WAF IP group data.
const WAFIPGroupsConfigFileName = "waf_ip_groups.json"
const powConfigFileName = "pow_config.json"
const (
nginxConfigFilePerm = 0o644
nginxPrivateKeyFilePerm = 0o600
nginxDirPerm = 0o755
stubStatusCheckTimeout = 1500 * time.Millisecond
nginxVersionSubmatchCount = 2
resolverAddressCapacity = 2
)
// Executor controls OpenResty validation, reload, health, and lifecycle operations.
type Executor interface {
Test(ctx context.Context) error
Reload(ctx context.Context) error
@@ -38,44 +55,49 @@ type Executor interface {
Restart(ctx context.Context) error
}
// CommandRunner executes external commands on behalf of an Executor.
type CommandRunner interface {
Run(ctx context.Context, name string, args ...string) ([]byte, error)
}
// OSCommandRunner runs commands using the host operating system.
type OSCommandRunner struct{}
// Run executes the named command and returns its combined output.
func (r *OSCommandRunner) Run(ctx context.Context, name string, args ...string) ([]byte, error) {
slog.Debug("OSCommandRunner starting command", "name", name, "args", args)
tmpFile, err := os.CreateTemp("", "openflare-cmd-*")
if err != nil {
slog.Error("OSCommandRunner failed to create temp file, falling back to CombinedOutput", "error", err)
cmd := exec.CommandContext(ctx, name, args...)
cmd := exec.CommandContext(ctx, name, args...) //nolint:gosec // command name and args come from trusted OpenResty management paths
output, outErr := cmd.CombinedOutput()
slog.Debug("OSCommandRunner finished CombinedOutput", "name", name, "error", outErr)
return output, outErr
}
defer os.Remove(tmpFile.Name())
defer func() { _ = os.Remove(tmpFile.Name()) }()
cmd := exec.CommandContext(ctx, name, args...)
cmd := exec.CommandContext(ctx, name, args...) //nolint:gosec // command name and args come from trusted OpenResty management paths
cmd.Stdout = tmpFile
cmd.Stderr = tmpFile
slog.Debug("OSCommandRunner executing cmd.Run()", "name", name)
runErr := cmd.Run()
slog.Debug("OSCommandRunner cmd.Run() returned", "name", name, "error", runErr)
tmpFile.Close()
_ = tmpFile.Close()
output, _ := os.ReadFile(tmpFile.Name())
slog.Debug("OSCommandRunner command complete", "name", name, "output_len", len(output))
return output, runErr
}
// PathExecutor runs OpenResty using a configured binary and config path.
type PathExecutor struct {
Path string
ConfigPath string
Runner CommandRunner
}
// Test validates the current OpenResty configuration.
func (e *PathExecutor) Test(ctx context.Context) error {
slog.Debug("running openresty test with binary", "path", e.Path, "config", e.ConfigPath)
output, err := e.Runner.Run(ctx, e.Path, "-t", "-c", e.ConfigPath)
@@ -86,6 +108,7 @@ func (e *PathExecutor) Test(ctx context.Context) error {
return nil
}
// Reload reloads OpenResty or starts it when no runtime process is running.
func (e *PathExecutor) Reload(ctx context.Context) error {
slog.Debug("running openresty reload with binary", "path", e.Path, "config", e.ConfigPath)
output, err := e.Runner.Run(ctx, e.Path, "-s", "reload", "-c", e.ConfigPath)
@@ -104,6 +127,7 @@ func (e *PathExecutor) Reload(ctx context.Context) error {
return nil
}
// EnsureRuntime validates configuration and reloads the OpenResty runtime.
func (e *PathExecutor) EnsureRuntime(ctx context.Context, _ bool) error {
if err := e.Test(ctx); err != nil {
return err
@@ -111,10 +135,12 @@ func (e *PathExecutor) EnsureRuntime(ctx context.Context, _ bool) error {
return e.Reload(ctx)
}
// CheckHealth reports whether the OpenResty configuration is valid.
func (e *PathExecutor) CheckHealth(ctx context.Context) error {
return e.Test(ctx)
}
// Restart stops and starts the OpenResty runtime process.
func (e *PathExecutor) Restart(ctx context.Context) error {
slog.Info("restarting openresty with binary", "path", e.Path, "config", e.ConfigPath)
output, err := e.Runner.Run(ctx, e.Path, "-s", "quit", "-c", e.ConfigPath)
@@ -132,6 +158,7 @@ func (e *PathExecutor) Restart(ctx context.Context) error {
return nil
}
// Manager applies OpenResty configuration and manages runtime assets.
type Manager struct {
MainConfigPath string
RouteConfigPath string
@@ -148,9 +175,12 @@ type Manager struct {
Executor Executor
}
// ApplyStatus reports the outcome of an OpenResty configuration apply.
type ApplyStatus string
// Apply outcome status values.
const (
// ApplyStatusSuccess indicates the configuration was applied successfully.
ApplyStatusSuccess ApplyStatus = "success"
ApplyStatusWarning ApplyStatus = "warning"
ApplyStatusFatal ApplyStatus = "fatal"
@@ -188,6 +218,7 @@ const safeDefaultFallbackObservabilityServerBlock = `
}
`
// ApplyOutcome contains the status and message from a configuration apply.
type ApplyOutcome struct {
Status ApplyStatus
Message string
@@ -197,6 +228,7 @@ type wafIPGroupsRuntimeConfig struct {
Groups map[string]protocol.WAFIPGroup `json:"groups"`
}
// Apply writes, validates, and activates new OpenResty configuration files.
func (m *Manager) Apply(ctx context.Context, mainConfig string, routeConfig string, supportFiles []protocol.SupportFile) ApplyOutcome {
slog.Info("openresty apply started", "main_config", m.MainConfigPath, "route_config", m.RouteConfigPath, "cert_files", len(supportFiles))
backup, err := m.backup()
@@ -236,11 +268,11 @@ func (m *Manager) writeTargetFiles(mainConfig string, routeConfig string, suppor
slog.Warn("runtime-resolved hostname upstreams detected without available resolvers; hostname origin requests may fail until resolvers are configured")
}
renderedMainConfig := m.renderMainConfig(mainConfig)
if err := os.WriteFile(m.MainConfigPath, []byte(renderedMainConfig), 0o644); err != nil {
if err := os.WriteFile(m.MainConfigPath, []byte(renderedMainConfig), nginxConfigFilePerm); err != nil {
return err
}
renderedRouteConfig := m.renderRouteConfig(routeConfig)
if err := os.WriteFile(m.RouteConfigPath, []byte(renderedRouteConfig), 0o644); err != nil {
if err := os.WriteFile(m.RouteConfigPath, []byte(renderedRouteConfig), nginxConfigFilePerm); err != nil {
return err
}
return nil
@@ -293,6 +325,7 @@ func fatalApplyOutcome(err error) ApplyOutcome {
}
}
// EnsureLuaAssets synchronizes managed Lua and static assets to the runtime directory.
func (m *Manager) EnsureLuaAssets() error {
if strings.TrimSpace(m.LuaDir) == "" {
return nil
@@ -317,12 +350,13 @@ func (m *Manager) EnsureLuaAssets() error {
files = append(files, managedFile{
Path: filepath.ToSlash(relativePath),
Content: []byte(file.Content),
Mode: 0o644,
Mode: nginxConfigFilePerm,
})
}
return syncManagedFiles(m.LuaDir, files)
}
// EnsureRuntime validates and reloads the current OpenResty runtime configuration.
func (m *Manager) EnsureRuntime(ctx context.Context, recreate bool) error {
if m.Executor == nil {
return errors.New("executor 未配置")
@@ -331,6 +365,7 @@ func (m *Manager) EnsureRuntime(ctx context.Context, recreate bool) error {
return m.Executor.EnsureRuntime(ctx, recreate)
}
// EnsureSafeFallbackRuntime starts a minimal safe default OpenResty runtime.
func (m *Manager) EnsureSafeFallbackRuntime(ctx context.Context, reason string) error {
if m.Executor == nil {
return errors.New("executor 未配置")
@@ -350,6 +385,7 @@ func (m *Manager) EnsureSafeFallbackRuntime(ctx context.Context, reason string)
return nil
}
// CheckHealth verifies that OpenResty configuration and health endpoints are available.
func (m *Manager) CheckHealth(ctx context.Context) error {
if m.Executor == nil {
return errors.New("executor 未配置")
@@ -365,6 +401,7 @@ func (m *Manager) CheckHealth(ctx context.Context) error {
return m.checkStubStatus(ctx)
}
// Restart restarts the OpenResty runtime process.
func (m *Manager) Restart(ctx context.Context) error {
if m.Executor == nil {
return errors.New("executor 未配置")
@@ -373,6 +410,7 @@ func (m *Manager) Restart(ctx context.Context) error {
return m.Executor.Restart(ctx)
}
// CurrentChecksum returns a stable checksum for the active OpenResty configuration bundle.
func (m *Manager) CurrentChecksum() (string, error) {
if m.RouteConfigPath == "" {
return "", errors.New("route config path 不能为空")
@@ -435,6 +473,7 @@ func (m *Manager) CurrentChecksum() (string, error) {
return result, nil
}
// WAFIPGroupChecksums returns checksums for locally synced WAF IP groups.
func (m *Manager) WAFIPGroupChecksums() (map[string]string, error) {
config, err := m.readWAFIPGroupsRuntimeConfig()
if err != nil {
@@ -449,6 +488,7 @@ func (m *Manager) WAFIPGroupChecksums() (map[string]string, error) {
return result, nil
}
// SyncWAFIPGroups writes WAF IP group definitions to the runtime config directory.
func (m *Manager) SyncWAFIPGroups(groups []protocol.WAFIPGroup) error {
if m.RuntimeConfigDir == "" || len(groups) == 0 {
return nil
@@ -470,11 +510,11 @@ func (m *Manager) SyncWAFIPGroups(groups []protocol.WAFIPGroup) error {
if err != nil {
return err
}
if err := os.MkdirAll(m.RuntimeConfigDir, 0o755); err != nil {
if err := os.MkdirAll(m.RuntimeConfigDir, nginxDirPerm); err != nil {
return err
}
path := filepath.Join(m.RuntimeConfigDir, WAFIPGroupsConfigFileName)
if err := os.WriteFile(path, data, 0o644); err != nil {
if err := os.WriteFile(path, data, nginxConfigFilePerm); err != nil {
return fmt.Errorf("write %s: %w", WAFIPGroupsConfigFileName, err)
}
slog.Info("synced waf ip groups", "path", path, "group_count", len(groups))
@@ -487,7 +527,7 @@ func (m *Manager) readWAFIPGroupsRuntimeConfig() (*wafIPGroupsRuntimeConfig, err
return config, nil
}
path := filepath.Join(m.RuntimeConfigDir, WAFIPGroupsConfigFileName)
data, err := os.ReadFile(path)
data, err := os.ReadFile(path) //nolint:gosec // path is under managed RuntimeConfigDir
if err != nil {
if os.IsNotExist(err) {
return config, nil
@@ -506,6 +546,7 @@ func (m *Manager) readWAFIPGroupsRuntimeConfig() (*wafIPGroupsRuntimeConfig, err
return config, nil
}
// ExecutorOptions configures construction of an OpenResty Executor.
type ExecutorOptions struct {
NginxPath string
MainConfigPath string
@@ -517,6 +558,7 @@ type ExecutorOptions struct {
OpenrestyObservabilityPort int
}
// NewExecutor creates an Executor backed by a configured OpenResty binary.
func NewExecutor(options ExecutorOptions) Executor {
runner := &OSCommandRunner{}
return &PathExecutor{
@@ -526,6 +568,7 @@ func NewExecutor(options ExecutorOptions) Executor {
}
}
// DetectVersion returns the OpenResty version reported by the configured binary.
func DetectVersion(ctx context.Context, options ExecutorOptions) string {
version, err := detectVersion(ctx, options, &OSCommandRunner{})
if err != nil {
@@ -556,7 +599,7 @@ func detectVersion(ctx context.Context, options ExecutorOptions, runner CommandR
func parseExtVersion(output string) string {
matches := nginxVersionPattern.FindStringSubmatch(output)
if len(matches) != 2 {
if len(matches) != nginxVersionSubmatchCount {
return ""
}
return matches[1]
@@ -606,24 +649,24 @@ func (m *Manager) backup() (*backupState, error) {
if m.RouteConfigPath == "" {
return nil, errors.New("route config path 不能为空")
}
if err := os.MkdirAll(filepath.Dir(m.MainConfigPath), 0o755); err != nil {
if err := os.MkdirAll(filepath.Dir(m.MainConfigPath), nginxDirPerm); err != nil {
return nil, err
}
if err := os.MkdirAll(filepath.Dir(m.RouteConfigPath), 0o755); err != nil {
if err := os.MkdirAll(filepath.Dir(m.RouteConfigPath), nginxDirPerm); err != nil {
return nil, err
}
if m.AccessLogPath != "" {
if err := os.MkdirAll(filepath.Dir(m.AccessLogPath), 0o755); err != nil {
if err := os.MkdirAll(filepath.Dir(m.AccessLogPath), nginxDirPerm); err != nil {
return nil, err
}
}
if m.CertDir != "" {
if err := os.MkdirAll(m.CertDir, 0o755); err != nil {
if err := os.MkdirAll(m.CertDir, nginxDirPerm); err != nil {
return nil, err
}
}
if m.RuntimeConfigDir != "" {
if err := os.MkdirAll(m.RuntimeConfigDir, 0o755); err != nil {
if err := os.MkdirAll(m.RuntimeConfigDir, nginxDirPerm); err != nil {
return nil, err
}
}
@@ -672,14 +715,14 @@ func (m *Manager) restore(state *backupState) error {
}
slog.Warn("restoring nginx backup", "main_existed", state.MainExisted, "route_existed", state.RouteExisted, "cert_files", len(state.Files))
if state.MainExisted {
if err := os.WriteFile(m.MainConfigPath, state.MainData, 0o644); err != nil {
if err := os.WriteFile(m.MainConfigPath, state.MainData, nginxConfigFilePerm); err != nil {
return err
}
} else if err := os.Remove(m.MainConfigPath); err != nil && !os.IsNotExist(err) {
return err
}
if state.RouteExisted {
if err := os.WriteFile(m.RouteConfigPath, state.RouteData, 0o644); err != nil {
if err := os.WriteFile(m.RouteConfigPath, state.RouteData, nginxConfigFilePerm); err != nil {
return err
}
} else if err := os.Remove(m.RouteConfigPath); err != nil && !os.IsNotExist(err) {
@@ -690,7 +733,7 @@ func (m *Manager) restore(state *backupState) error {
return err
}
}
if err := m.restoreRuntimeConfig(state.PowConfig, "pow_config.json"); err != nil {
if err := m.restoreRuntimeConfig(state.PowConfig, powConfigFileName); err != nil {
return err
}
if err := m.restoreRuntimeConfig(state.WAFConfig, "waf_config.json"); err != nil {
@@ -710,10 +753,10 @@ func (m *Manager) writePowConfig(supportFiles []protocol.SupportFile) error {
if m.RuntimeConfigDir == "" {
return nil
}
configPath := filepath.Join(m.RuntimeConfigDir, "pow_config.json")
configPath := filepath.Join(m.RuntimeConfigDir, powConfigFileName)
for _, file := range supportFiles {
if file.Path == "pow_config.json" {
if err := os.WriteFile(configPath, []byte(file.Content), 0o644); err != nil {
if file.Path == powConfigFileName {
if err := os.WriteFile(configPath, []byte(file.Content), nginxConfigFilePerm); err != nil {
return fmt.Errorf("write pow_config.json: %w", err)
}
slog.Info("wrote pow config", "path", configPath, "size", len(file.Content))
@@ -723,10 +766,10 @@ func (m *Manager) writePowConfig(supportFiles []protocol.SupportFile) error {
if err := os.Remove(configPath); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("remove pow_config.json: %w", err)
}
if err := removeLegacyPowConfig(filepath.Join(m.LuaDir, "pow_config.json")); err != nil {
if err := removeLegacyPowConfig(filepath.Join(m.LuaDir, powConfigFileName)); err != nil {
return err
}
if err := removeLegacyPowConfig(filepath.Join(m.CertDir, "pow_config.json")); err != nil {
if err := removeLegacyPowConfig(filepath.Join(m.CertDir, powConfigFileName)); err != nil {
return err
}
return nil
@@ -739,7 +782,7 @@ func (m *Manager) writeWAFConfig(supportFiles []protocol.SupportFile) error {
configPath := filepath.Join(m.RuntimeConfigDir, "waf_config.json")
for _, file := range supportFiles {
if file.Path == "waf_config.json" {
if err := os.WriteFile(configPath, []byte(file.Content), 0o644); err != nil {
if err := os.WriteFile(configPath, []byte(file.Content), nginxConfigFilePerm); err != nil {
return fmt.Errorf("write waf_config.json: %w", err)
}
slog.Info("wrote waf config", "path", configPath, "size", len(file.Content))
@@ -759,7 +802,7 @@ func (m *Manager) writeSourceConfig(supportFiles []protocol.SupportFile) error {
configPath := filepath.Join(m.RuntimeConfigDir, openrestyrender.SourceConfigFileName)
for _, file := range supportFiles {
if file.Path == openrestyrender.SourceConfigFileName {
if err := os.WriteFile(configPath, []byte(file.Content), 0o644); err != nil {
if err := os.WriteFile(configPath, []byte(file.Content), nginxConfigFilePerm); err != nil {
return fmt.Errorf("write %s: %w", openrestyrender.SourceConfigFileName, err)
}
slog.Info("wrote openresty source config", "path", configPath, "size", len(file.Content))
@@ -775,7 +818,7 @@ func (m *Manager) writeSourceConfig(supportFiles []protocol.SupportFile) error {
func (m *Manager) writeManagedCertFiles(certFiles []protocol.SupportFile) error {
files := make([]managedFile, 0, len(certFiles))
for _, file := range certFiles {
if file.Path == "pow_config.json" || file.Path == "waf_config.json" || file.Path == openrestyrender.SourceConfigFileName {
if file.Path == powConfigFileName || file.Path == "waf_config.json" || file.Path == openrestyrender.SourceConfigFileName {
continue
}
targetPath, err := m.certFileTargetPath(file.Path)
@@ -817,10 +860,10 @@ func (m *Manager) readCertFiles() ([]protocol.SupportFile, error) {
if err != nil {
return err
}
if filepath.ToSlash(relativePath) == "pow_config.json" {
if filepath.ToSlash(relativePath) == powConfigFileName {
return nil
}
data, err := os.ReadFile(path)
data, err := os.ReadFile(path) //nolint:gosec // path is under managed baseDir walk root
if err != nil {
return err
}
@@ -840,7 +883,7 @@ func (m *Manager) readCertFiles() ([]protocol.SupportFile, error) {
}
func (m *Manager) readPowConfigFile() (*protocol.SupportFile, error) {
return m.readRuntimeConfigFile("pow_config.json")
return m.readRuntimeConfigFile(powConfigFileName)
}
func (m *Manager) readRuntimeConfigFile(name string) (*protocol.SupportFile, error) {
@@ -848,7 +891,7 @@ func (m *Manager) readRuntimeConfigFile(name string) (*protocol.SupportFile, err
return nil, nil
}
configPath := filepath.Join(m.RuntimeConfigDir, name)
data, err := os.ReadFile(configPath)
data, err := os.ReadFile(configPath) //nolint:gosec // configPath is under managed RuntimeConfigDir
if err != nil {
if os.IsNotExist(err) {
return nil, nil
@@ -894,7 +937,7 @@ func (m *Manager) restoreRuntimeConfig(file *protocol.SupportFile, name string)
}
return nil
}
return os.WriteFile(configPath, []byte(file.Content), 0o644)
return os.WriteFile(configPath, []byte(file.Content), nginxConfigFilePerm)
}
func (m *Manager) writeSafeDefaultFallbackFiles() error {
@@ -904,16 +947,16 @@ func (m *Manager) writeSafeDefaultFallbackFiles() error {
if strings.TrimSpace(m.RouteConfigPath) == "" {
return errors.New("route config path 不能为空")
}
if err := os.MkdirAll(filepath.Dir(m.MainConfigPath), 0o755); err != nil {
if err := os.MkdirAll(filepath.Dir(m.MainConfigPath), nginxDirPerm); err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(m.RouteConfigPath), 0o755); err != nil {
if err := os.MkdirAll(filepath.Dir(m.RouteConfigPath), nginxDirPerm); err != nil {
return err
}
if err := os.WriteFile(m.RouteConfigPath, nil, 0o644); err != nil {
if err := os.WriteFile(m.RouteConfigPath, nil, nginxConfigFilePerm); err != nil {
return err
}
if err := os.WriteFile(m.MainConfigPath, []byte(m.safeDefaultFallbackMainConfig()), 0o644); err != nil {
if err := os.WriteFile(m.MainConfigPath, []byte(m.safeDefaultFallbackMainConfig()), nginxConfigFilePerm); err != nil {
return err
}
return nil
@@ -928,10 +971,10 @@ func (m *Manager) safeDefaultFallbackMainConfig() string {
}
func (m *Manager) checkStubStatus(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, 1500*time.Millisecond)
ctx, cancel := context.WithTimeout(ctx, stubStatusCheckTimeout)
defer cancel()
openrestyStubUrl := fmt.Sprintf("http://127.0.0.1:%d/openflare/stub_status", m.OpenrestyObservabilityPort)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, openrestyStubUrl, nil)
openrestyStubURL := fmt.Sprintf("http://127.0.0.1:%d/openflare/stub_status", m.OpenrestyObservabilityPort)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, openrestyStubURL, nil)
if err != nil {
return err
}
@@ -939,11 +982,11 @@ func (m *Manager) checkStubStatus(ctx context.Context) error {
if err != nil {
return fmt.Errorf("openresty health endpoint unreachable: %w", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("openresty health endpoint returned %s", resp.Status)
}
slog.Debug("openresty health endpoint is healthy", "url", openrestyStubUrl)
slog.Debug("openresty health endpoint is healthy", "url", openrestyStubURL)
return nil
}
@@ -986,11 +1029,11 @@ func (m *Manager) certFileTargetPath(relativePath string) (string, error) {
func certFileMode(relativePath string) fs.FileMode {
switch strings.ToLower(filepath.Ext(strings.TrimSpace(relativePath))) {
case ".crt", ".pem":
return 0o644
return nginxConfigFilePerm
case ".key":
return 0o600
return nginxPrivateKeyFilePerm
default:
return 0o644
return nginxConfigFilePerm
}
}
@@ -1029,7 +1072,7 @@ func syncManagedFiles(baseDir string, files []managedFile) error {
} else if err != nil && !os.IsNotExist(err) {
return err
}
if err := os.MkdirAll(baseDir, 0o755); err != nil {
if err := os.MkdirAll(baseDir, nginxDirPerm); err != nil {
return err
}
@@ -1060,14 +1103,14 @@ func syncManagedFiles(baseDir string, files []managedFile) error {
if _, ok := desired[filepath.Clean(relativePath)]; ok {
return nil
}
return os.Remove(path)
return os.Remove(path) //nolint:gosec // path is resolved under the managed baseDir walk root
}); err != nil {
return err
}
for _, file := range desired {
targetPath := filepath.Join(baseDir, file.Path)
if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil {
if err := os.MkdirAll(filepath.Dir(targetPath), nginxDirPerm); err != nil {
return err
}
if err := os.WriteFile(targetPath, file.Content, file.Mode); err != nil {
@@ -1119,10 +1162,10 @@ func (m *Manager) ensureMimeTypes() error {
} else if !os.IsNotExist(err) {
return err
}
if err := os.MkdirAll(configDir, 0o755); err != nil {
if err := os.MkdirAll(configDir, nginxDirPerm); err != nil {
return err
}
return os.WriteFile(mimeTypesPath, []byte(DefaultMimeTypes), 0o644)
return os.WriteFile(mimeTypesPath, []byte(DefaultMimeTypes), nginxConfigFilePerm)
}
func (m *Manager) renderRouteConfig(content string) string {
@@ -1183,6 +1226,7 @@ func (m *Manager) managedWAFLuaFiles() []protocol.SupportFile {
return files
}
// ObservabilityListenAddress returns the localhost listen address for stub_status.
func ObservabilityListenAddress(port int) string {
if port <= 0 {
return ""
@@ -1190,6 +1234,7 @@ func ObservabilityListenAddress(port int) string {
return fmt.Sprintf("127.0.0.1:%d", port)
}
// ResolverDirective renders the nginx resolver block for runtime upstream lookups.
func ResolverDirective(explicitResolvers []string) string {
resolvers := resolverAddresses(explicitResolvers)
if len(resolvers) == 0 {
@@ -1211,7 +1256,7 @@ func resolverAddresses(explicitResolvers []string) []string {
func parseResolverAddresses(content string, dockerMode bool) []string {
lines := strings.Split(content, "\n")
resolvers := make([]string, 0, 2)
resolvers := make([]string, 0, resolverAddressCapacity)
seen := make(map[string]struct{})
for _, line := range lines {
fields := strings.Fields(strings.TrimSpace(line))
@@ -1242,6 +1287,7 @@ func isUsableDockerResolver(addr string) bool {
return !ip.IsLoopback() && !ip.IsUnspecified()
}
// RequiresRuntimeResolver reports whether originURL needs a runtime DNS resolver.
func RequiresRuntimeResolver(originURL string) bool {
parsed, err := url.Parse(strings.TrimSpace(originURL))
if err != nil || parsed.Hostname() == "" {
+1
View File
@@ -1,5 +1,6 @@
package nginx
// DefaultMimeTypes is the embedded nginx mime.types map used by generated configs.
const DefaultMimeTypes = `
types {
text/html html htm shtml;
@@ -146,6 +146,7 @@ ngx.header.content_type = "application/json"
ngx.say(cjson.encode(payload))
`
// ManagedObservabilityLuaFiles returns embedded Lua assets for OpenResty observability.
func ManagedObservabilityLuaFiles() []protocol.SupportFile {
return []protocol.SupportFile{
{Path: "init.lua", Content: openRestyObservabilityInitLua},
+2
View File
@@ -542,6 +542,7 @@ end
return M
`
// ManagedPowLuaFiles returns embedded Lua assets for proof-of-work challenges.
func ManagedPowLuaFiles() []protocol.SupportFile {
return []protocol.SupportFile{
{Path: "pow/runtime.lua", Content: openRestyPowRuntimeLua},
@@ -552,6 +553,7 @@ func ManagedPowLuaFiles() []protocol.SupportFile {
}
}
// ManagedPowStaticFiles returns embedded static assets served by the PoW module.
func ManagedPowStaticFiles() ([]protocol.SupportFile, error) {
var files []protocol.SupportFile
entries, err := powStaticFS.ReadDir("pow_static")
+1
View File
@@ -302,6 +302,7 @@ end
return require("waf.runtime").check()
`
// ManagedWAFLuaFiles returns the embedded Lua source files that must be deployed to the WAF runtime directory.
func ManagedWAFLuaFiles() []protocol.SupportFile {
return []protocol.SupportFile{
{Path: "waf/runtime.lua", Content: openRestyWAFRuntimeLua},