mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-10 17:26:38 +08:00
fix lint
This commit is contained in:
@@ -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() == "" {
|
||||
|
||||
Reference in New Issue
Block a user