diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:20 +0000 |
commit | 87d772a7d708fec12f48cd8adc0dedff6e1025da (patch) | |
tree | 1fee344c64cc3f43074a01981e21126c8482a522 /src/go/plugin/go.d/modules/portcheck | |
parent | Adding upstream version 1.46.3. (diff) | |
download | netdata-87d772a7d708fec12f48cd8adc0dedff6e1025da.tar.xz netdata-87d772a7d708fec12f48cd8adc0dedff6e1025da.zip |
Adding upstream version 1.47.0.upstream/1.47.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/go/plugin/go.d/modules/portcheck')
l--------- | src/go/plugin/go.d/modules/portcheck/README.md | 1 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/charts.go | 75 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/collect.go | 77 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/config_schema.json | 66 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/init.go | 49 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/integrations/tcp_endpoints.md | 252 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/metadata.yaml | 162 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/portcheck.go | 101 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/portcheck_test.go | 169 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/testdata/config.json | 8 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/portcheck/testdata/config.yaml | 5 |
11 files changed, 965 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/portcheck/README.md b/src/go/plugin/go.d/modules/portcheck/README.md new file mode 120000 index 000000000..4bee556ef --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/README.md @@ -0,0 +1 @@ +integrations/tcp_endpoints.md
\ No newline at end of file diff --git a/src/go/plugin/go.d/modules/portcheck/charts.go b/src/go/plugin/go.d/modules/portcheck/charts.go new file mode 100644 index 000000000..6797f00a6 --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/charts.go @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package portcheck + +import ( + "fmt" + "strconv" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" +) + +const ( + prioCheckStatus = module.Priority + iota + prioCheckInStatusDuration + prioCheckLatency +) + +var chartsTmpl = module.Charts{ + checkStatusChartTmpl.Copy(), + checkInStateDurationChartTmpl.Copy(), + checkConnectionLatencyChartTmpl.Copy(), +} + +var checkStatusChartTmpl = module.Chart{ + ID: "port_%d_status", + Title: "TCP Check Status", + Units: "boolean", + Fam: "status", + Ctx: "portcheck.status", + Priority: prioCheckStatus, + Dims: module.Dims{ + {ID: "port_%d_success", Name: "success"}, + {ID: "port_%d_failed", Name: "failed"}, + {ID: "port_%d_timeout", Name: "timeout"}, + }, +} + +var checkInStateDurationChartTmpl = module.Chart{ + ID: "port_%d_current_state_duration", + Title: "Current State Duration", + Units: "seconds", + Fam: "status duration", + Ctx: "portcheck.state_duration", + Priority: prioCheckInStatusDuration, + Dims: module.Dims{ + {ID: "port_%d_current_state_duration", Name: "time"}, + }, +} + +var checkConnectionLatencyChartTmpl = module.Chart{ + ID: "port_%d_connection_latency", + Title: "TCP Connection Latency", + Units: "ms", + Fam: "latency", + Ctx: "portcheck.latency", + Priority: prioCheckLatency, + Dims: module.Dims{ + {ID: "port_%d_latency", Name: "time"}, + }, +} + +func newPortCharts(host string, port int) *module.Charts { + charts := chartsTmpl.Copy() + for _, chart := range *charts { + chart.Labels = []module.Label{ + {Key: "host", Value: host}, + {Key: "port", Value: strconv.Itoa(port)}, + } + chart.ID = fmt.Sprintf(chart.ID, port) + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, port) + } + } + return charts +} diff --git a/src/go/plugin/go.d/modules/portcheck/collect.go b/src/go/plugin/go.d/modules/portcheck/collect.go new file mode 100644 index 000000000..dab45ec41 --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/collect.go @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package portcheck + +import ( + "fmt" + "sync" + "time" +) + +type checkState string + +const ( + checkStateSuccess checkState = "success" + checkStateTimeout checkState = "timeout" + checkStateFailed checkState = "failed" +) + +func (pc *PortCheck) collect() (map[string]int64, error) { + wg := &sync.WaitGroup{} + + for _, p := range pc.ports { + wg.Add(1) + go func(p *port) { pc.checkPort(p); wg.Done() }(p) + } + wg.Wait() + + mx := make(map[string]int64) + + for _, p := range pc.ports { + mx[fmt.Sprintf("port_%d_current_state_duration", p.number)] = int64(p.inState) + mx[fmt.Sprintf("port_%d_latency", p.number)] = int64(p.latency) + mx[fmt.Sprintf("port_%d_%s", p.number, checkStateSuccess)] = 0 + mx[fmt.Sprintf("port_%d_%s", p.number, checkStateTimeout)] = 0 + mx[fmt.Sprintf("port_%d_%s", p.number, checkStateFailed)] = 0 + mx[fmt.Sprintf("port_%d_%s", p.number, p.state)] = 1 + } + + return mx, nil +} + +func (pc *PortCheck) checkPort(p *port) { + start := time.Now() + conn, err := pc.dial("tcp", fmt.Sprintf("%s:%d", pc.Host, p.number), pc.Timeout.Duration()) + dur := time.Since(start) + + defer func() { + if conn != nil { + _ = conn.Close() + } + }() + + if err != nil { + v, ok := err.(interface{ Timeout() bool }) + if ok && v.Timeout() { + pc.setPortState(p, checkStateTimeout) + } else { + pc.setPortState(p, checkStateFailed) + } + return + } + pc.setPortState(p, checkStateSuccess) + p.latency = durationToMs(dur) +} + +func (pc *PortCheck) setPortState(p *port, s checkState) { + if p.state != s { + p.inState = pc.UpdateEvery + p.state = s + } else { + p.inState += pc.UpdateEvery + } +} + +func durationToMs(duration time.Duration) int { + return int(duration) / (int(time.Millisecond) / int(time.Nanosecond)) +} diff --git a/src/go/plugin/go.d/modules/portcheck/config_schema.json b/src/go/plugin/go.d/modules/portcheck/config_schema.json new file mode 100644 index 000000000..025b78f85 --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/config_schema.json @@ -0,0 +1,66 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Portcheck collector configuration.", + "description": "Collector for monitoring TCP service availability and response time.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 5 + }, + "timeout": { + "title": "Timeout", + "description": "Timeout for establishing a connection, including domain name resolution, in seconds.", + "type": "number", + "minimum": 0.5, + "default": 2 + }, + "host": { + "title": "Network host", + "description": "The IP address or domain name of the network host.", + "type": "string" + }, + "ports": { + "title": "Ports", + "description": "A list of ports to monitor for TCP service availability and response time.", + "type": [ + "array", + "null" + ], + "items": { + "title": "Port", + "type": "integer", + "minimum": 1 + }, + "minItems": 1, + "uniqueItems": true + } + }, + "required": [ + "host", + "ports" + ], + "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)." + }, + "host": { + "ui:placeholder": "127.0.0.1" + }, + "ports": { + "ui:listFlavour": "list" + } + } +} diff --git a/src/go/plugin/go.d/modules/portcheck/init.go b/src/go/plugin/go.d/modules/portcheck/init.go new file mode 100644 index 000000000..17b402340 --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/init.go @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package portcheck + +import ( + "errors" + "net" + "time" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" +) + +type dialFunc func(network, address string, timeout time.Duration) (net.Conn, error) + +type port struct { + number int + state checkState + inState int + latency int +} + +func (pc *PortCheck) validateConfig() error { + if pc.Host == "" { + return errors.New("'host' parameter not set") + } + if len(pc.Ports) == 0 { + return errors.New("'ports' parameter not set") + } + return nil +} + +func (pc *PortCheck) initCharts() (*module.Charts, error) { + charts := module.Charts{} + + for _, port := range pc.Ports { + if err := charts.Add(*newPortCharts(pc.Host, port)...); err != nil { + return nil, err + } + } + + return &charts, nil +} + +func (pc *PortCheck) initPorts() (ports []*port) { + for _, p := range pc.Ports { + ports = append(ports, &port{number: p}) + } + return ports +} diff --git a/src/go/plugin/go.d/modules/portcheck/integrations/tcp_endpoints.md b/src/go/plugin/go.d/modules/portcheck/integrations/tcp_endpoints.md new file mode 100644 index 000000000..9259afd3b --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/integrations/tcp_endpoints.md @@ -0,0 +1,252 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/plugin/go.d/modules/portcheck/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/plugin/go.d/modules/portcheck/metadata.yaml" +sidebar_label: "TCP Endpoints" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/Synthetic Checks" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# TCP Endpoints + + +<img src="https://netdata.cloud/img/globe.svg" width="150"/> + + +Plugin: go.d.plugin +Module: portcheck + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +This collector monitors TCP services availability and response time. + + + + +This collector is supported on all platforms. + +This collector supports collecting metrics from multiple instances of this integration, including remote instances. + + +### Default Behavior + +#### Auto-Detection + +This integration doesn't support auto-detection. + +#### Limits + +The default configuration for this integration does not impose any limits on data collection. + +#### Performance Impact + +The default configuration for this integration is not expected to impose a significant performance impact on the system. + + +## Metrics + +Metrics grouped by *scope*. + +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels. + + + +### Per tcp endpoint + +These metrics refer to the TCP endpoint. + +Labels: + +| Label | Description | +|:-----------|:----------------| +| host | host | +| port | port | + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| portcheck.status | success, failed, timeout | boolean | +| portcheck.state_duration | time | seconds | +| portcheck.latency | time | ms | + + + +## Alerts + + +The following alerts are available: + +| Alert name | On metric | Description | +|:------------|:----------|:------------| +| [ portcheck_service_reachable ](https://github.com/netdata/netdata/blob/master/src/health/health.d/portcheck.conf) | portcheck.status | TCP host ${label:host} port ${label:port} liveness status | +| [ portcheck_connection_timeouts ](https://github.com/netdata/netdata/blob/master/src/health/health.d/portcheck.conf) | portcheck.status | percentage of timed-out TCP connections to host ${label:host} port ${label:port} in the last 5 minutes | +| [ portcheck_connection_fails ](https://github.com/netdata/netdata/blob/master/src/health/health.d/portcheck.conf) | portcheck.status | percentage of failed TCP connections to host ${label:host} port ${label:port} in the last 5 minutes | + + +## Setup + +### Prerequisites + +No action required. + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/portcheck.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/portcheck.conf +``` +#### Options + +The following options can be defined globally: update_every, autodetection_retry. + + +<details open><summary>Config options</summary> + +| Name | Description | Default | Required | +|:----|:-----------|:-------|:--------:| +| update_every | Data collection frequency. | 5 | no | +| autodetection_retry | Recheck interval in seconds. Zero means no recheck will be scheduled. | 0 | no | +| host | Remote host address in IPv4, IPv6 format, or DNS name. | | yes | +| ports | Remote host ports. Must be specified in numeric format. | | yes | +| timeout | HTTP request timeout. | 2 | no | + +</details> + +#### Examples + +##### Check SSH and telnet + +An example configuration. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: server1 + host: 127.0.0.1 + ports: + - 22 + - 23 + +``` +</details> + +##### Check webserver with IPv6 address + +An example configuration. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: server2 + host: "[2001:DB8::1]" + ports: + - 80 + - 8080 + +``` +</details> + +##### Multi-instance + +> **Note**: When you define multiple jobs, their names must be unique. + +Multiple instances. + + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: server1 + host: 127.0.0.1 + ports: + - 22 + - 23 + + - name: server2 + host: 203.0.113.10 + ports: + - 22 + - 23 + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +**Important**: Debug mode is not supported for data collection jobs created via the UI using the Dyncfg feature. + +To troubleshoot issues with the `portcheck` collector, run the `go.d.plugin` with the debug option enabled. The output +should give you clues as to why the collector isn't working. + +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`. + + ```bash + cd /usr/libexec/netdata/plugins.d/ + ``` + +- Switch to the `netdata` user. + + ```bash + sudo -u netdata -s + ``` + +- Run the `go.d.plugin` to debug the collector: + + ```bash + ./go.d.plugin -d -m portcheck + ``` + +### Getting Logs + +If you're encountering problems with the `portcheck` collector, follow these steps to retrieve logs and identify potential issues: + +- **Run the command** specific to your system (systemd, non-systemd, or Docker container). +- **Examine the output** for any warnings or error messages that might indicate issues. These messages should provide clues about the root cause of the problem. + +#### System with systemd + +Use the following command to view logs generated since the last Netdata service restart: + +```bash +journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata --grep portcheck +``` + +#### System without systemd + +Locate the collector log file, typically at `/var/log/netdata/collector.log`, and use `grep` to filter for collector's name: + +```bash +grep portcheck /var/log/netdata/collector.log +``` + +**Note**: This method shows logs from all restarts. Focus on the **latest entries** for troubleshooting current issues. + +#### Docker Container + +If your Netdata runs in a Docker container named "netdata" (replace if different), use this command: + +```bash +docker logs netdata 2>&1 | grep portcheck +``` + + diff --git a/src/go/plugin/go.d/modules/portcheck/metadata.yaml b/src/go/plugin/go.d/modules/portcheck/metadata.yaml new file mode 100644 index 000000000..c0ccfde1d --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/metadata.yaml @@ -0,0 +1,162 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-portcheck + plugin_name: go.d.plugin + module_name: portcheck + monitored_instance: + name: TCP Endpoints + link: "" + icon_filename: globe.svg + categories: + - data-collection.synthetic-checks + keywords: [] + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + most_popular: false + overview: + data_collection: + metrics_description: | + This collector monitors TCP services availability and response time. + method_description: "" + supported_platforms: + include: [] + exclude: [] + multi_instance: true + additional_permissions: + description: "" + default_behavior: + auto_detection: + description: "" + limits: + description: "" + performance_impact: + description: "" + setup: + prerequisites: + list: [] + configuration: + file: + name: go.d/portcheck.conf + options: + description: | + The following options can be defined globally: update_every, autodetection_retry. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 5 + required: false + - name: autodetection_retry + description: Recheck interval in seconds. Zero means no recheck will be scheduled. + default_value: 0 + required: false + - name: host + description: Remote host address in IPv4, IPv6 format, or DNS name. + default_value: "" + required: true + - name: ports + description: Remote host ports. Must be specified in numeric format. + default_value: "" + required: true + - name: timeout + description: HTTP request timeout. + default_value: 2 + required: false + examples: + folding: + title: Config + enabled: true + list: + - name: Check SSH and telnet + description: An example configuration. + config: | + jobs: + - name: server1 + host: 127.0.0.1 + ports: + - 22 + - 23 + - name: Check webserver with IPv6 address + description: An example configuration. + config: | + jobs: + - name: server2 + host: "[2001:DB8::1]" + ports: + - 80 + - 8080 + - name: Multi-instance + description: | + > **Note**: When you define multiple jobs, their names must be unique. + + Multiple instances. + config: | + jobs: + - name: server1 + host: 127.0.0.1 + ports: + - 22 + - 23 + + - name: server2 + host: 203.0.113.10 + ports: + - 22 + - 23 + troubleshooting: + problems: + list: [] + alerts: + - name: portcheck_service_reachable + metric: portcheck.status + info: "TCP host ${label:host} port ${label:port} liveness status" + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/portcheck.conf + - name: portcheck_connection_timeouts + metric: portcheck.status + info: "percentage of timed-out TCP connections to host ${label:host} port ${label:port} in the last 5 minutes" + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/portcheck.conf + - name: portcheck_connection_fails + metric: portcheck.status + info: "percentage of failed TCP connections to host ${label:host} port ${label:port} in the last 5 minutes" + link: https://github.com/netdata/netdata/blob/master/src/health/health.d/portcheck.conf + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: tcp endpoint + description: These metrics refer to the TCP endpoint. + labels: + - name: host + description: host + - name: port + description: port + metrics: + - name: portcheck.status + description: TCP Check Status + unit: boolean + chart_type: line + dimensions: + - name: success + - name: failed + - name: timeout + - name: portcheck.state_duration + description: Current State Duration + unit: seconds + chart_type: line + dimensions: + - name: time + - name: portcheck.latency + description: TCP Connection Latency + unit: ms + chart_type: line + dimensions: + - name: time diff --git a/src/go/plugin/go.d/modules/portcheck/portcheck.go b/src/go/plugin/go.d/modules/portcheck/portcheck.go new file mode 100644 index 000000000..3a6da78ac --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/portcheck.go @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package portcheck + +import ( + _ "embed" + "net" + "time" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("portcheck", module.Creator{ + JobConfigSchema: configSchema, + Defaults: module.Defaults{ + UpdateEvery: 5, + }, + Create: func() module.Module { return New() }, + Config: func() any { return &Config{} }, + }) +} + +func New() *PortCheck { + return &PortCheck{ + Config: Config{ + Timeout: web.Duration(time.Second * 2), + }, + dial: net.DialTimeout, + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + Host string `yaml:"host" json:"host"` + Ports []int `yaml:"ports" json:"ports"` + Timeout web.Duration `yaml:"timeout,omitempty" json:"timeout"` +} + +type PortCheck struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + dial dialFunc + + ports []*port +} + +func (pc *PortCheck) Configuration() any { + return pc.Config +} + +func (pc *PortCheck) Init() error { + if err := pc.validateConfig(); err != nil { + pc.Errorf("config validation: %v", err) + return err + } + + charts, err := pc.initCharts() + if err != nil { + pc.Errorf("init charts: %v", err) + return err + } + pc.charts = charts + + pc.ports = pc.initPorts() + + pc.Debugf("using host: %s", pc.Host) + pc.Debugf("using ports: %v", pc.Ports) + pc.Debugf("using TCP connection timeout: %s", pc.Timeout) + + return nil +} + +func (pc *PortCheck) Check() error { + return nil +} + +func (pc *PortCheck) Charts() *module.Charts { + return pc.charts +} + +func (pc *PortCheck) Collect() map[string]int64 { + mx, err := pc.collect() + if err != nil { + pc.Error(err) + } + + if len(mx) == 0 { + return nil + } + return mx +} + +func (pc *PortCheck) Cleanup() {} diff --git a/src/go/plugin/go.d/modules/portcheck/portcheck_test.go b/src/go/plugin/go.d/modules/portcheck/portcheck_test.go new file mode 100644 index 000000000..86a2c9679 --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/portcheck_test.go @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package portcheck + +import ( + "errors" + "net" + "os" + "strings" + "testing" + "time" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/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") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + } { + require.NotNil(t, data, name) + } +} + +func TestPortCheck_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &PortCheck{}, dataConfigJSON, dataConfigYAML) +} + +func TestPortCheck_Init(t *testing.T) { + job := New() + + job.Host = "127.0.0.1" + job.Ports = []int{39001, 39002} + assert.NoError(t, job.Init()) + assert.Len(t, job.ports, 2) +} +func TestPortCheck_InitNG(t *testing.T) { + job := New() + + assert.Error(t, job.Init()) + job.Host = "127.0.0.1" + assert.Error(t, job.Init()) + job.Ports = []int{39001, 39002} + assert.NoError(t, job.Init()) +} + +func TestPortCheck_Check(t *testing.T) { + assert.NoError(t, New().Check()) +} + +func TestPortCheck_Cleanup(t *testing.T) { + New().Cleanup() +} + +func TestPortCheck_Charts(t *testing.T) { + job := New() + job.Ports = []int{1, 2} + job.Host = "localhost" + require.NoError(t, job.Init()) + assert.Len(t, *job.Charts(), len(chartsTmpl)*len(job.Ports)) +} + +func TestPortCheck_Collect(t *testing.T) { + job := New() + + job.Host = "127.0.0.1" + job.Ports = []int{39001, 39002} + job.UpdateEvery = 5 + job.dial = testDial(nil) + require.NoError(t, job.Init()) + require.NoError(t, job.Check()) + + copyLatency := func(dst, src map[string]int64) { + for k := range dst { + if strings.HasSuffix(k, "latency") { + dst[k] = src[k] + } + } + } + + expected := map[string]int64{ + "port_39001_current_state_duration": int64(job.UpdateEvery), + "port_39001_failed": 0, + "port_39001_latency": 0, + "port_39001_success": 1, + "port_39001_timeout": 0, + "port_39002_current_state_duration": int64(job.UpdateEvery), + "port_39002_failed": 0, + "port_39002_latency": 0, + "port_39002_success": 1, + "port_39002_timeout": 0, + } + collected := job.Collect() + copyLatency(expected, collected) + + assert.Equal(t, expected, collected) + + expected = map[string]int64{ + "port_39001_current_state_duration": int64(job.UpdateEvery) * 2, + "port_39001_failed": 0, + "port_39001_latency": 0, + "port_39001_success": 1, + "port_39001_timeout": 0, + "port_39002_current_state_duration": int64(job.UpdateEvery) * 2, + "port_39002_failed": 0, + "port_39002_latency": 0, + "port_39002_success": 1, + "port_39002_timeout": 0, + } + collected = job.Collect() + copyLatency(expected, collected) + + assert.Equal(t, expected, collected) + + job.dial = testDial(errors.New("checkStateFailed")) + + expected = map[string]int64{ + "port_39001_current_state_duration": int64(job.UpdateEvery), + "port_39001_failed": 1, + "port_39001_latency": 0, + "port_39001_success": 0, + "port_39001_timeout": 0, + "port_39002_current_state_duration": int64(job.UpdateEvery), + "port_39002_failed": 1, + "port_39002_latency": 0, + "port_39002_success": 0, + "port_39002_timeout": 0, + } + collected = job.Collect() + copyLatency(expected, collected) + + assert.Equal(t, expected, collected) + + job.dial = testDial(timeoutError{}) + + expected = map[string]int64{ + "port_39001_current_state_duration": int64(job.UpdateEvery), + "port_39001_failed": 0, + "port_39001_latency": 0, + "port_39001_success": 0, + "port_39001_timeout": 1, + "port_39002_current_state_duration": int64(job.UpdateEvery), + "port_39002_failed": 0, + "port_39002_latency": 0, + "port_39002_success": 0, + "port_39002_timeout": 1, + } + collected = job.Collect() + copyLatency(expected, collected) + + assert.Equal(t, expected, collected) +} + +func testDial(err error) dialFunc { + return func(_, _ string, _ time.Duration) (net.Conn, error) { return &net.TCPConn{}, err } +} + +type timeoutError struct{} + +func (timeoutError) Error() string { return "timeout" } +func (timeoutError) Timeout() bool { return true } diff --git a/src/go/plugin/go.d/modules/portcheck/testdata/config.json b/src/go/plugin/go.d/modules/portcheck/testdata/config.json new file mode 100644 index 000000000..a69a6ac38 --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/testdata/config.json @@ -0,0 +1,8 @@ +{ + "update_every": 123, + "host": "ok", + "ports": [ + 123 + ], + "timeout": 123.123 +} diff --git a/src/go/plugin/go.d/modules/portcheck/testdata/config.yaml b/src/go/plugin/go.d/modules/portcheck/testdata/config.yaml new file mode 100644 index 000000000..72bdfd549 --- /dev/null +++ b/src/go/plugin/go.d/modules/portcheck/testdata/config.yaml @@ -0,0 +1,5 @@ +update_every: 123 +host: "ok" +ports: + - 123 +timeout: 123.123 |