-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Only start Journald input with supported systemd versions #39605
Changes from all commits
3d60072
f3c4091
6329e84
4793347
ff71181
47a057c
fd998fd
1dab86d
3a83fa3
2111c20
ace2e17
2ec481a
381012c
1b77913
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -20,8 +20,15 @@ | |||||
package journald | ||||||
|
||||||
import ( | ||||||
"context" | ||||||
"errors" | ||||||
"flag" | ||||||
"fmt" | ||||||
"regexp" | ||||||
"strconv" | ||||||
"time" | ||||||
|
||||||
"github.com/coreos/go-systemd/v22/dbus" | ||||||
"github.com/coreos/go-systemd/v22/sdjournal" | ||||||
"github.com/urso/sderr" | ||||||
|
||||||
|
@@ -37,6 +44,15 @@ import ( | |||||
"github.com/elastic/elastic-agent-libs/logp" | ||||||
) | ||||||
|
||||||
var noVersionCheck bool | ||||||
|
||||||
func init() { | ||||||
flag.BoolVar(&noVersionCheck, | ||||||
"ignore-journald-version", | ||||||
false, | ||||||
"Does not check Journald version when starting the Journald input. This might cause Filebeat to crash!") | ||||||
} | ||||||
|
||||||
type journald struct { | ||||||
Backoff time.Duration | ||||||
MaxBackoff time.Duration | ||||||
|
@@ -63,21 +79,54 @@ const localSystemJournalID = "LOCAL_SYSTEM_JOURNAL" | |||||
|
||||||
const pluginName = "journald" | ||||||
|
||||||
// ErrSystemdVersionNotSupported is returned by the plugin manager when the | ||||||
// Systemd version is not supported. | ||||||
var ErrSystemdVersionNotSupported = errors.New("systemd version must be >= 255") | ||||||
|
||||||
// ErrCannotGetSystemdVersion is returned by the plugin manager when it is | ||||||
// not possible to get the Systemd version via D-Bus. | ||||||
var ErrCannotGetSystemdVersion = errors.New("cannot get systemd version") | ||||||
|
||||||
// Plugin creates a new journald input plugin for creating a stateful input. | ||||||
func Plugin(log *logp.Logger, store cursor.StateStore) input.Plugin { | ||||||
return input.Plugin{ | ||||||
m := &cursor.InputManager{ | ||||||
Logger: log, | ||||||
StateStore: store, | ||||||
Type: pluginName, | ||||||
Configure: configure, | ||||||
} | ||||||
p := input.Plugin{ | ||||||
Name: pluginName, | ||||||
Stability: feature.Experimental, | ||||||
Deprecated: false, | ||||||
Info: "journald input", | ||||||
Doc: "The journald input collects logs from the local journald service", | ||||||
Manager: &cursor.InputManager{ | ||||||
Logger: log, | ||||||
StateStore: store, | ||||||
Type: pluginName, | ||||||
Configure: configure, | ||||||
}, | ||||||
Manager: m, | ||||||
} | ||||||
|
||||||
if noVersionCheck { | ||||||
log.Warn("Journald version check has been DISABLED! Filebeat might crash if Journald version is < 255.") | ||||||
return p | ||||||
} | ||||||
|
||||||
version, err := systemdVersion() | ||||||
if err != nil { | ||||||
configErr := fmt.Errorf("%w: %s", ErrCannotGetSystemdVersion, err) | ||||||
m.Configure = func(_ *conf.C) ([]cursor.Source, cursor.Input, error) { | ||||||
return nil, nil, configErr | ||||||
} | ||||||
return p | ||||||
} | ||||||
|
||||||
if version < 255 { | ||||||
configErr := fmt.Errorf("%w. Systemd version: %d", ErrSystemdVersionNotSupported, version) | ||||||
m.Configure = func(_ *conf.C) ([]cursor.Source, cursor.Input, error) { | ||||||
return nil, nil, configErr | ||||||
} | ||||||
return p | ||||||
} | ||||||
|
||||||
return p | ||||||
} | ||||||
|
||||||
type pathSource string | ||||||
|
@@ -303,3 +352,64 @@ func (r *readerAdapter) Next() (reader.Message, error) { | |||||
|
||||||
return m, nil | ||||||
} | ||||||
|
||||||
// parseSystemdVersion parses the string version from Systemd fetched via D-Bus. | ||||||
// The function will parse and return the 3 digit major version, minor version | ||||||
// and patch are ignored. | ||||||
func parseSystemdVersion(ver string) (int, error) { | ||||||
re := regexp.MustCompile(`(v)?(?P<version>\d\d\d)(\.)?`) | ||||||
matches := re.FindStringSubmatch(ver) | ||||||
if len(matches) == 0 { | ||||||
return 0, fmt.Errorf("unsupported Systemd version format '%s'", ver) | ||||||
} | ||||||
|
||||||
// This should never fail because the regexp ensures we're getting a 3-digt | ||||||
// integer, however, better safe than sorry. | ||||||
version, err := strconv.Atoi(matches[2]) | ||||||
if err != nil { | ||||||
return 0, fmt.Errorf("could not convert '%s' to int: %w", matches[2], err) | ||||||
} | ||||||
|
||||||
return version, nil | ||||||
} | ||||||
|
||||||
// getSystemdVersionViaDBus gets the Systemd version from sd-bus | ||||||
// | ||||||
// The Systemd D-Bus documentation states: | ||||||
// | ||||||
// Version encodes the version string of the running systemd | ||||||
// instance. Note that the version string is purely informational, | ||||||
// it should not be parsed, one may not assume the version to be | ||||||
// formatted in any particular way. We take the liberty to change | ||||||
// the versioning scheme at any time and it is not part of the API. | ||||||
// Source: https://www.freedesktop.org/wiki/Software/systemd/dbus/ | ||||||
Comment on lines
+376
to
+385
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Question] |
||||||
func getSystemdVersionViaDBus() (string, error) { | ||||||
// Get a context with timeout just to be on the safe side | ||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||||||
defer cancel() | ||||||
conn, err := dbus.NewSystemConnectionContext(ctx) | ||||||
if err != nil { | ||||||
return "", fmt.Errorf("cannot connect to sd-bus: %w", err) | ||||||
} | ||||||
|
||||||
version, err := conn.GetManagerProperty("Version") | ||||||
if err != nil { | ||||||
return "", fmt.Errorf("cannot get version property: %w", err) | ||||||
} | ||||||
|
||||||
return version, nil | ||||||
} | ||||||
|
||||||
func systemdVersion() (int, error) { | ||||||
versionStr, err := getSystemdVersionViaDBus() | ||||||
if err != nil { | ||||||
return 0, fmt.Errorf("caanot get Systemd version: %w", err) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo
Suggested change
|
||||||
} | ||||||
|
||||||
version, err := parseSystemdVersion(versionStr) | ||||||
if err != nil { | ||||||
return 0, fmt.Errorf("cannot parse Systemd version: %w", err) | ||||||
} | ||||||
|
||||||
return version, nil | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ import ( | |
|
||
devtools "github.com/elastic/beats/v7/dev-tools/mage" | ||
"github.com/elastic/beats/v7/dev-tools/mage/target/build" | ||
"github.com/elastic/beats/v7/dev-tools/mage/target/unittest" | ||
filebeat "github.com/elastic/beats/v7/filebeat/scripts/mage" | ||
|
||
//mage:import | ||
|
@@ -33,6 +34,7 @@ import ( | |
func init() { | ||
common.RegisterCheckDeps(Update) | ||
test.RegisterDeps(IntegTest) | ||
unittest.RegisterGoTestDeps(TestJournaldInput) | ||
|
||
devtools.BeatDescription = "Filebeat sends log files to Logstash or directly to Elasticsearch." | ||
devtools.BeatLicense = "Elastic License" | ||
|
@@ -187,3 +189,16 @@ func PythonIntegTest(ctx context.Context) error { | |
mg.Deps(Fields, Dashboards, devtools.BuildSystemTestBinary) | ||
return devtools.PythonIntegTestFromHost(devtools.DefaultPythonTestIntegrationFromHostArgs()) | ||
} | ||
|
||
// TestJournald executes the Journald input tests | ||
// Use TEST_COVERAGE=true to enable code coverage profiling. | ||
// Use RACE_DETECTOR=true to enable the race detector. | ||
func TestJournaldInput(ctx context.Context) error { | ||
utArgs := devtools.DefaultGoTestUnitArgs() | ||
utArgs.Packages = []string{"../../filebeat/input/journald"} | ||
if devtools.Platform.GOOS == "linux" { | ||
utArgs.ExtraFlags = append(utArgs.ExtraFlags, "-tags=withjournald") | ||
} | ||
|
||
return devtools.GoTest(ctx, utArgs) | ||
} | ||
Comment on lines
+193
to
+204
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't a way to avoid duplicating that? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the 3 digits makes me a little nervous, if systemd goes to 4 this all breaks.
^(?P<version>\d{3,})
works with the examples provided. thoughts?