Add logrotate conflict detection

This commit is contained in:
Theodor S. Midtlien
2026-05-19 16:04:45 +02:00
parent 16d1a4d550
commit 1e66db8ddb
4 changed files with 114 additions and 2 deletions

View File

@@ -1043,7 +1043,8 @@ func (g *BundleGenerator) addRotatedLogFiles(logDir string) {
return
}
pattern := filepath.Join(logDir, "client-*.log.gz")
// This regex will match both logs rotated by us and logrotate on linux
pattern := filepath.Join(logDir, "client*.log*.gz")
files, err := filepath.Glob(pattern)
if err != nil {
log.Warnf("failed to glob rotated logs: %v", err)

View File

@@ -59,7 +59,18 @@ func InitLogger(logger *log.Logger, logLevel string, logs ...string) error {
case "":
logger.Warnf("empty log path received: %#v", logPath)
default:
writers = append(writers, newRotatedOutput(logPath))
conflict, configPath := FindFirstLogrotateConflict()
if conflict {
logger.Warnf("logrotation conflict detected in: %#v, rotation is disabled", configPath)
file, err := openOrCreateFile(logPath)
if err != nil {
logger.Errorf("Failed opening log file: %s", err)
return err
}
writers = append(writers, file)
} else {
writers = append(writers, newRotatedOutput(logPath))
}
}
}

89
util/logrotate_linux.go Normal file
View File

@@ -0,0 +1,89 @@
//go:build linux
package util
import (
"bufio"
"errors"
"io/fs"
"os"
"path/filepath"
"strings"
log "github.com/sirupsen/logrus"
)
const (
defaultLogrotateConfPath = "/etc/logrotate.conf"
defaultLogrotateConfDir = "/etc/logrotate.d"
netbirdString = "netbird"
)
// FindLogrotateConflicts scans the standard logrotate locations for
// indications of conflict with netbird. It returns true and the config file
// path if a conflict was found.
func FindFirstLogrotateConflict() (bool, string) {
for _, f := range listLogrotateConfigs() {
present, err := scanLogrotateFile(f, netbirdString)
if err != nil {
if !errors.Is(err, fs.ErrNotExist) {
log.Debugf("scan %s: %v", f, err)
}
continue
}
if present {
return present, f
}
}
return false, ""
}
// listLogrotateConfigs returns all config files for logrotate.
func listLogrotateConfigs() []string {
files := []string{defaultLogrotateConfPath}
entries, err := os.ReadDir(defaultLogrotateConfDir)
if err != nil {
return files
}
for _, e := range entries {
if e.IsDir() {
continue
}
files = append(files, filepath.Join(defaultLogrotateConfDir, e.Name()))
}
return files
}
// scanLogrotateFile reads a config and reports if a non-comment line
// contains the given substring.
func scanLogrotateFile(path string, substring string) (bool, error) {
f, err := os.Open(path)
if err != nil {
return false, err
}
defer func() {
if err := f.Close(); err != nil {
log.Debugf("close %s: %v", path, err)
}
}()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := strings.TrimSpace(stripLogrotateComment(scanner.Text()))
if line == "" {
continue
}
if strings.Contains(line, substring) {
return true, nil
}
}
if err := scanner.Err(); err != nil {
return false, err
}
return false, nil
}
func stripLogrotateComment(line string) string {
before, _, _ := strings.Cut(line, "#")
return before
}

View File

@@ -0,0 +1,11 @@
//go:build !linux
package util
// FindLogrotateConflicts scans the standard logrotate locations and returns
// true and the first config file that contains a non-comment line indicating
// it's configured for netbird.
// Will always return false for non-linux device.
func FindFirstLogrotateConflict() (bool, string) {
return false, ""
}