diff options
author | Ilya Mashchenko <ilya@netdata.cloud> | 2024-04-23 19:37:20 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-23 19:37:20 +0300 |
commit | 355753638683af0036d4626c3a3a7ce68dcc531e (patch) | |
tree | c3156f4ce21502276b00aa60682117d1eec339a0 | |
parent | ae783041d93b67ca7c4c8d9425aff45dc04515a7 (diff) |
add go.d fail2ban (#17501)
* add go.d fail2ban
* update contexts
17 files changed, 833 insertions, 2 deletions
diff --git a/src/go/collectors/go.d.plugin/README.md b/src/go/collectors/go.d.plugin/README.md index b7f35a1e54..de64966164 100644 --- a/src/go/collectors/go.d.plugin/README.md +++ b/src/go/collectors/go.d.plugin/README.md @@ -72,6 +72,7 @@ see the appropriate collector readme. | [energid](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/energid) | Energi Core | | [envoy](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/envoy) | Envoy | | [example](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/example) | - | +| [fail2ban](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/fail2ban) | Fail2Ban Jails | | [filecheck](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/filecheck) | Files and Directories | | [fluentd](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/fluentd) | Fluentd | | [freeradius](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/freeradius) | FreeRADIUS | diff --git a/src/go/collectors/go.d.plugin/config/go.d.conf b/src/go/collectors/go.d.plugin/config/go.d.conf index 928cb15a06..4d143b1cf9 100644 --- a/src/go/collectors/go.d.plugin/config/go.d.conf +++ b/src/go/collectors/go.d.plugin/config/go.d.conf @@ -35,6 +35,7 @@ modules: # elasticsearch: yes # envoy: yes # example: no +# fail2ban: yes # filecheck: yes # fluentd: yes # freeradius: yes diff --git a/src/go/collectors/go.d.plugin/config/go.d/fail2ban.conf b/src/go/collectors/go.d.plugin/config/go.d/fail2ban.conf new file mode 100644 index 0000000000..56f4a59e51 --- /dev/null +++ b/src/go/collectors/go.d.plugin/config/go.d/fail2ban.conf @@ -0,0 +1,5 @@ +## All available configuration options, their descriptions and default values: +## https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/fail2ban#readme + +jobs: + - name: fail2ban diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/charts.go b/src/go/collectors/go.d.plugin/modules/fail2ban/charts.go new file mode 100644 index 0000000000..d203e7864d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/charts.go @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package fail2ban + +import ( + "fmt" + "strings" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" +) + +const ( + prioJailBannedIPs = module.Priority + iota + prioJailActiveFailures +) + +var jailChartsTmpl = module.Charts{ + jailCurrentBannedIPs.Copy(), + jailActiveFailures.Copy(), +} + +var ( + jailCurrentBannedIPs = module.Chart{ + ID: "jail_%s_banned_ips", + Title: "Fail2Ban Jail banned IPs", + Units: "addresses", + Fam: "bans", + Ctx: "fail2ban.jail_banned_ips", + Type: module.Line, + Priority: prioJailBannedIPs, + Dims: module.Dims{ + {ID: "jail_%s_currently_banned", Name: "banned"}, + }, + } + jailActiveFailures = module.Chart{ + ID: "jail_%s_active_failures", + Title: "Fail2Ban Jail active failures", + Units: "failures", + Fam: "failures", + Ctx: "fail2ban.jail_active_failures", + Type: module.Line, + Priority: prioJailActiveFailures, + Dims: module.Dims{ + {ID: "jail_%s_currently_failed", Name: "active_failures"}, + }, + } +) + +func (f *Fail2Ban) addJailCharts(jail string) { + charts := jailChartsTmpl.Copy() + + for _, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, jail) + chart.Labels = []module.Label{ + {Key: "jail", Value: jail}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, jail) + } + } + + if err := f.Charts().Add(*charts...); err != nil { + f.Warning(err) + } +} + +func (f *Fail2Ban) removeJailCharts(jail string) { + px := fmt.Sprintf("jail_%s_", jail) + for _, chart := range *f.Charts() { + if strings.HasPrefix(chart.ID, px) { + chart.MarkRemove() + chart.MarkNotCreated() + } + } +} diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/collect.go b/src/go/collectors/go.d.plugin/modules/fail2ban/collect.go new file mode 100644 index 0000000000..8ca413c3b8 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/collect.go @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package fail2ban + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "strconv" + "strings" + "time" +) + +func (f *Fail2Ban) collect() (map[string]int64, error) { + now := time.Now() + + if now.Sub(f.lastDiscoverTime) > f.discoverEvery || f.forceDiscover { + jails, err := f.discoverJails() + if err != nil { + return nil, err + } + f.jails = jails + f.lastDiscoverTime = now + f.forceDiscover = false + } + + mx := make(map[string]int64) + + if err := f.collectJails(mx); err != nil { + return nil, err + } + + return mx, nil +} + +func (f *Fail2Ban) discoverJails() ([]string, error) { + bs, err := f.exec.status() + if err != nil { + return nil, err + } + + jails, err := parseFail2banStatus(bs) + if err != nil { + return nil, err + } + + if len(jails) == 0 { + return nil, errors.New("no jails found") + } + + f.Debugf("discovered %d jails: %v", len(jails), jails) + + return jails, nil +} + +func (f *Fail2Ban) collectJails(mx map[string]int64) error { + seen := make(map[string]bool) + + for _, jail := range f.jails { + f.Debugf("querying status for jail '%s'", jail) + bs, err := f.exec.jailStatus(jail) + if err != nil { + if errors.Is(err, errJailNotExist) { + f.forceDiscover = true + continue + } + return err + } + + failed, banned, err := parseFail2banJailStatus(bs) + if err != nil { + return err + } + + if !f.seenJails[jail] { + f.seenJails[jail] = true + f.addJailCharts(jail) + } + seen[jail] = true + + px := fmt.Sprintf("jail_%s_", jail) + + mx[px+"currently_failed"] = failed + mx[px+"currently_banned"] = banned + } + + for jail := range f.seenJails { + if !seen[jail] { + delete(f.seenJails, jail) + f.removeJailCharts(jail) + } + } + + return nil +} + +func parseFail2banJailStatus(jailStatus []byte) (failed, banned int64, err error) { + const ( + failedSub = "Currently failed:" + bannedSub = "Currently banned:" + ) + + var failedFound, bannedFound bool + + sc := bufio.NewScanner(bytes.NewReader(jailStatus)) + + for sc.Scan() && !(failedFound && bannedFound) { + text := strings.TrimSpace(sc.Text()) + if text == "" { + continue + } + + if !failedFound { + if i := strings.Index(text, failedSub); i != -1 { + failedFound = true + s := strings.TrimSpace(text[i+len(failedSub):]) + if failed, err = strconv.ParseInt(s, 10, 64); err != nil { + return 0, 0, fmt.Errorf("failed to parse currently failed value (%s): %v", s, err) + } + } + } + if !bannedFound { + if i := strings.Index(text, bannedSub); i != -1 { + bannedFound = true + s := strings.TrimSpace(text[i+len(bannedSub):]) + if banned, err = strconv.ParseInt(s, 10, 64); err != nil { + return 0, 0, fmt.Errorf("failed to parse currently banned value (%s): %v", s, err) + } + } + } + } + + if !failedFound || !bannedFound { + return 0, 0, errors.New("failed to find failed and banned values") + } + + return failed, banned, nil +} + +func parseFail2banStatus(status []byte) ([]string, error) { + const sub = "Jail list:" + + var jails []string + + sc := bufio.NewScanner(bytes.NewReader(status)) + + for sc.Scan() { + text := strings.TrimSpace(sc.Text()) + + if i := strings.Index(text, sub); i != -1 { + s := strings.ReplaceAll(text[i+len(sub):], ",", "") + jails = strings.Fields(s) + break + } + } + + if len(jails) == 0 { + return nil, errors.New("failed to find jails") + } + + return jails, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/config_schema.json b/src/go/collectors/go.d.plugin/modules/fail2ban/config_schema.json new file mode 100644 index 0000000000..7fd0d91aff --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/config_schema.json @@ -0,0 +1,35 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Fail2Ban collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 10 + }, + "timeout": { + "title": "Timeout", + "description": "Timeout for executing the binary, specified in seconds.", + "type": "number", + "minimum": 0.5, + "default": 2 + } + }, + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "uiOptions": { + "fullPage": true + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + } + } +} diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/exec.go b/src/go/collectors/go.d.plugin/modules/fail2ban/exec.go new file mode 100644 index 0000000000..06b5841e73 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/exec.go @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package fail2ban + +import ( + "context" + "errors" + "fmt" + "os/exec" + "strings" + "time" + + "github.com/netdata/netdata/go/go.d.plugin/logger" +) + +var errJailNotExist = errors.New("jail not exist") + +func newFail2BanClientCliExec(ndsudoPath string, timeout time.Duration, log *logger.Logger) *fail2banClientCliExec { + return &fail2banClientCliExec{ + Logger: log, + ndsudoPath: ndsudoPath, + timeout: timeout, + } +} + +type fail2banClientCliExec struct { + *logger.Logger + + ndsudoPath string + timeout time.Duration +} + +func (e *fail2banClientCliExec) status() ([]byte, error) { + return e.execute("fail2ban-client-status") +} + +func (e *fail2banClientCliExec) jailStatus(jail string) ([]byte, error) { + return e.execute("fail2ban-client-status-jail", "--jail", jail) +} + +func (e *fail2banClientCliExec) execute(args ...string) ([]byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), e.timeout) + defer cancel() + + cmd := exec.CommandContext(ctx, e.ndsudoPath, args...) + e.Debugf("executing '%s'", cmd) + + bs, err := cmd.Output() + if err != nil { + if strings.HasPrefix(strings.TrimSpace(string(bs)), "Sorry but the jail") { + return nil, errJailNotExist + } + return nil, fmt.Errorf("error on '%s': %v", cmd, err) + } + + return bs, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/fail2ban.go b/src/go/collectors/go.d.plugin/modules/fail2ban/fail2ban.go new file mode 100644 index 0000000000..b746f88960 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/fail2ban.go @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package fail2ban + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("fail2ban", module.Creator{ + JobConfigSchema: configSchema, + Defaults: module.Defaults{ + UpdateEvery: 10, + }, + Create: func() module.Module { return New() }, + }) +} + +func New() *Fail2Ban { + return &Fail2Ban{ + Config: Config{ + Timeout: web.Duration(time.Second * 2), + }, + charts: &module.Charts{}, + discoverEvery: time.Minute * 5, + seenJails: make(map[string]bool), + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every" json:"update_every"` + Timeout web.Duration `yaml:"timeout" json:"timeout"` +} + +type ( + Fail2Ban struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + exec fail2banClientCli + + discoverEvery time.Duration + lastDiscoverTime time.Time + forceDiscover bool + jails []string + + seenJails map[string]bool + } + fail2banClientCli interface { + status() ([]byte, error) + jailStatus(s string) ([]byte, error) + } +) + +func (f *Fail2Ban) Configuration() any { + return f.Config +} + +func (f *Fail2Ban) Init() error { + f2bClientExec, err := f.initFail2banClientCliExec() + if err != nil { + f.Errorf("fail2ban-client exec initialization: %v", err) + return err + } + f.exec = f2bClientExec + + return nil +} + +func (f *Fail2Ban) Check() error { + mx, err := f.collect() + if err != nil { + f.Error(err) + return err + } + + if len(mx) == 0 { + return errors.New("no metrics collected") + } + + return nil +} + +func (f *Fail2Ban) Charts() *module.Charts { + return f.charts +} + +func (f *Fail2Ban) Collect() map[string]int64 { + mx, err := f.collect() + if err != nil { + f.Error(err) + } + + if len(mx) == 0 { + return nil + } + + return mx +} + +func (f *Fail2Ban) Cleanup() {} diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/fail2ban_test.go b/src/go/collectors/go.d.plugin/modules/fail2ban/fail2ban_test.go new file mode 100644 index 0000000000..7d1988bd21 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/fail2ban_test.go @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package fail2ban + +import ( + "errors" + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataStatus, _ = os.ReadFile("testdata/fail2ban-status.txt") + dataJailStatus, _ = os.ReadFile("testdata/fail2ban-jail-status.txt") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + + "dataStatus": dataStatus, + "dataJailStatus": dataJailStatus, + } { + require.NotNil(t, data, name) + + } +} + +func TestFail2Ban_Configuration(t *testing.T) { + module.TestConfigurationSerialize(t, &Fail2Ban{}, dataConfigJSON, dataConfigYAML) +} + +func TestFail2Ban_Init(t *testing.T) { + tests := map[string]struct { + config Config + wantFail bool + }{ + "fails if failed to locate ndsudo": { + wantFail: true, + config: New().Config, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + f2b := New() + f2b.Config = test.config + + if test.wantFail { + assert.Error(t, f2b.Init()) + } else { + assert.NoError(t, f2b.Init()) + } + }) + } +} + +func TestFail2Ban_Cleanup(t *testing.T) { + tests := map[string]struct { + prepare func() *Fail2Ban + }{ + "not initialized exec": { + prepare: func() *Fail2Ban { + return New() + }, + }, + "after check": { + prepare: func() *Fail2Ban { + f2b := New() + f2b.exec = prepareMockOk() + _ = f2b.Check() + return f2b + }, + }, + "after collect": { + prepare: func() *Fail2Ban { + f2b := New() + f2b.exec = prepareMockOk() + _ = f2b.Collect() + return f2b + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + f2b := test.prepare() + + assert.NotPanics(t, f2b.Cleanup) + }) + } +} + +func TestFail2Ban_Charts(t *testing.T) { + assert.NotNil(t, New().Charts()) +} + +func TestFail2Ban_Check(t *testing.T) { + tests := map[string]struct { + prepareMock func() *mockFail2BanClientCliExec + wantFail bool + }{ + "success multiple jails": { + wantFail: false, + prepareMock: prepareMockOk, + }, + "error on status": { + wantFail: true, + prepareMock: prepareMockErrOnStatus, + }, + "empty response (no jails)": { + prepareMock: prepareMockEmptyResponse, + wantFail: true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + f2b := New() + mock := test.prepareMock() + f2b.exec = mock + + if test.wantFail { + assert.Error(t, f2b.Check()) + } else { + assert.NoError(t, f2b.Check()) + } + }) + } +} + +func TestFail2Ban_Collect(t *testing.T) { + tests := map[string]struct { + prepareMock func() *mockFail2BanClientCliExec + wantMetrics map[string]int64 + }{ + "success multiple jails": { + prepareMock: prepareMockOk, + wantMetrics: map[string]int64{ + "jail_dovecot_currently_banned": 30, + "jail_dovecot_currently_failed": 10, + "jail_sshd_currently_banned": 30, + "jail_sshd_currently_failed": 10, + }, + }, + "error on status": { + prepareMock: prepareMockErrOnStatus, + wantMetrics: nil, + }, + "empty response (no jails)": { + prepareMock: prepareMockEmptyResponse, + wantMetrics: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + f2b := New() + mock := test.prepareMock() + f2b.exec = mock + + mx := f2b.Collect() + + assert.Equal(t, test.wantMetrics, mx) + if len(test.wantMetrics) > 0 { + assert.Len(t, *f2b.Charts(), len(jailChartsTmpl)*2) + testMetricsHasAllChartsDims(t, f2b, mx) + } + }) + } +} + +func testMetricsHasAllChartsDims(t *testing.T, f2b *Fail2Ban, mx map[string]int64) { + for _, chart := range *f2b.Charts() { + if chart.Obsolete { + continue + } + for _, dim := range chart.Dims { + _, ok := mx[dim.ID] + assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := mx[v.ID] + assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) + } + } +} + +func prepareMockOk() *mockFail2BanClientCliExec { + return &mockFail2BanClientCliExec{ + statusData: dataStatus, + jailStatusData: dataJailStatus, + } +} + +func prepareMockErrOnStatus() *mockFail2BanClientCliExec { + return &mockFail2BanClientCliExec{ + errOnStatus: true, + statusData: dataStatus, + jailStatusData: dataJailStatus, + } +} + +func prepareMockEmptyResponse() *mockFail2BanClientCliExec { + return &mockFail2BanClientCliExec{} +} + +type mockFail2BanClientCliExec struct { + errOnStatus bool + statusData []byte + + errOnJailStatus bool + jailStatusData []byte +} + +func (m *mockFail2BanClientCliExec) status() ([]byte, error) { + if m.errOnStatus { + return nil, errors.New("mock.status() error") + } + + return m.statusData, nil +} + +func (m *mockFail2BanClientCliExec) jailStatus(_ string) ([]byte, error) { + if m.errOnJailStatus { + return nil, errors.New("mock.jailStatus() error") + } + + return m.jailStatusData, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/init.go b/src/go/collectors/go.d.plugin/modules/fail2ban/init.go new file mode 100644 index 0000000000..938c9697ab --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/init.go @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package fail2ban + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/netdata/netdata/go/go.d.plugin/agent/executable" +) + +func (f *Fail2Ban) initFail2banClientCliExec() (fail2banClientCli, error) { + ndsudoPath := filepath.Join(executable.Directory, "ndsudo") + if _, err := os.Stat(ndsudoPath); err != nil { + return nil, fmt.Errorf("ndsudo executable not found: %v", err) + + } + + f2bClientExec := newFail2BanClientCliExec(ndsudoPath, f.Timeout.Duration(), f.Logger) + + return f2bClientExec, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/metadata.yaml b/src/go/collectors/go.d.plugin/modules/fail2ban/metadata.yaml new file mode 100644 index 0000000000..87a5732a12 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/metadata.yaml @@ -0,0 +1,105 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-fail2ban + plugin_name: go.d.plugin + module_name: fail2ban + monitored_instance: + name: Fail2ban + link: "https://github.com/fail2ban/fail2ban#readme" + icon_filename: fail2ban.png + categories: + - data-collection.authentication-and-authorization + keywords: + - fail2ban + - security + - authentication + - authorization + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + most_popular: false + overview: + data_collection: + metrics_description: > + This collector tracks two main metrics for each jail: currently banned IPs and active failure incidents. + It relies on the [`fail2ban-client`](https://linux.die.net/man/1/fail2ban-client) CLI tool but avoids directly executing the binary. + Instead, it utilizes `ndsudo`, a Netdata helper specifically designed to run privileged commands securely within the Netdata environment. + This approach eliminates the need to use `sudo`, improving security and potentially simplifying permission management. + method_description: "" + supported_platforms: + include: [] + exclude: [] + multi_instance: false + additional_permissions: + description: "" + default_behavior: + auto_detection: + description: "" + limits: + description: "" + performance_impact: + description: "" + setup: + prerequisites: + list: [] + configuration: + file: + name: go.d/fail2ban.conf + options: + description: | + The following options can be defined globally: update_every. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 10 + required: false + - name: timeout + description: fail2ban-client binary execution timeout. + default_value: 2 + required: false + examples: + folding: + title: Config + enabled: true + list: + - name: Custom update_every + description: Allows you to override the default data collection interval. + config: | + jobs: + - name: fail2ban + update_every: 5 # Collect Fail2Ban jails statistics every 5 seconds + troubleshooting: + problems: + list: [] + alerts: [] + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: jail + description: These metrics refer to the Jail. + labels: + - name: jail + description: Jail's name + metrics: + - name: fail2ban.jail_banned_ips + description: Fail2Ban Jail banned IPs + unit: addresses + chart_type: line + dimensions: + - name: banned + - name: fail2ban.jail_active_failures + description: Fail2Ban Jail active failures + unit: failures + chart_type: line + dimensions: + - name: active_failures diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/config.json b/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/config.json new file mode 100644 index 0000000000..291ecee3d6 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/config.json @@ -0,0 +1,4 @@ +{ + "update_every": 123, + "timeout": 123.123 +} diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/config.yaml new file mode 100644 index 0000000000..25b0b4c780 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/config.yaml @@ -0,0 +1,2 @@ +update_every: 123 +timeout: 123.123 diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/fail2ban-jail-status.txt b/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/fail2ban-jail-status.txt new file mode 100644 index 0000000000..17a3f53c12 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/fail2ban-jail-status.txt @@ -0,0 +1,9 @@ +Status for the jail: JAIL +|- Filter +| |- Currently failed: 10 +| |- Total failed: 20 +| `- File list: /var/log/auth.log +`- Actions + |- Currently banned: 30 + |- Total banned: 40 + `- Banned IP list: diff --git a/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/fail2ban-status.txt b/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/fail2ban-status.txt new file mode 100644 index 0000000000..1e65a78cf2 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/fail2ban/testdata/fail2ban-status.txt @@ -0,0 +1,3 @@ +Status +|- Number of jail: 1 +`- Jail list: sshd, dovecot
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/init.go b/src/go/collectors/go.d.plugin/modules/init.go index 8691ca024d..b0f1f9e838 100644 --- a/src/go/collectors/go.d.plugin/modules/init.go +++ b/src/go/collectors/go.d.plugin/modules/init.go @@ -24,6 +24,7 @@ import ( _ "github.com/netdata/netdata/go/go.d.plugin/modules/elasticsearch" _ "github.com/netdata/netdata/go/go.d.plugin/modules/envoy" _ "github.com/netdata/netdata/go/go.d.plugin/modules/example" + _ "github.com/netdata/netdata/go/go.d.plugin/modules/fail2ban" _ "github.com/netdata/netdata/go/go.d.plugin/modules/filecheck" _ "github.com/netdata/netdata/go/go.d.plugin/modules/fluentd" _ "github.com/netdata/netdata/go/go.d.plugin/modules/freeradius" diff --git a/src/go/collectors/go.d.plugin/modules/lvm/lvm_test.go b/src/go/collectors/go.d.plugin/modules/lvm/lvm_test.go index 46bc8a8d1e..db85fc7dfd 100644 --- a/src/go/collectors/go.d.plugin/modules/lvm/lvm_test.go +++ b/src/go/collectors/go.d.plugin/modules/lvm/lvm_test.go @@ -61,7 +61,6 @@ func TestLVM_ |