Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
179
plugins/inputs/icinga2/README.md
Normal file
179
plugins/inputs/icinga2/README.md
Normal file
|
@ -0,0 +1,179 @@
|
|||
# Icinga2 Input Plugin
|
||||
|
||||
This plugin gather services and hosts status information using the
|
||||
[Icinga2 remote API][remote_api].
|
||||
|
||||
⭐ Telegraf v1.8.0
|
||||
🏷️ network, server, system
|
||||
💻 all
|
||||
|
||||
[remote_api]: https://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/icinga2-api
|
||||
|
||||
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
|
||||
|
||||
In addition to the plugin-specific configuration settings, plugins support
|
||||
additional global and plugin configuration settings. These settings are used to
|
||||
modify metrics, tags, and field or create aliases and configure ordering, etc.
|
||||
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||
|
||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# Gather Icinga2 status
|
||||
[[inputs.icinga2]]
|
||||
## Required Icinga2 server address
|
||||
# server = "https://localhost:5665"
|
||||
|
||||
## Collected Icinga2 objects ("services", "hosts")
|
||||
## Specify at least one object to collect from /v1/objects endpoint.
|
||||
# objects = ["services"]
|
||||
|
||||
## Collect metrics from /v1/status endpoint
|
||||
## Choose from:
|
||||
## "ApiListener", "CIB", "IdoMysqlConnection", "IdoPgsqlConnection"
|
||||
# status = []
|
||||
|
||||
## Credentials for basic HTTP authentication
|
||||
# username = "admin"
|
||||
# password = "admin"
|
||||
|
||||
## Maximum time to receive response.
|
||||
# response_timeout = "5s"
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
## Use TLS but skip chain & host verification
|
||||
# insecure_skip_verify = true
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
- `icinga2_hosts`
|
||||
- tags
|
||||
- `check_command` - The short name of the check command
|
||||
- `display_name` - The name of the host
|
||||
- `state` - The state: UP/DOWN
|
||||
- `source` - The icinga2 host
|
||||
- `port` - The icinga2 port
|
||||
- `scheme` - The icinga2 protocol (http/https)
|
||||
- `server` - The server the check_command is running for
|
||||
- fields
|
||||
- `name` (string)
|
||||
- `state_code` (int)
|
||||
- `icinga2_services`
|
||||
- tags
|
||||
- `check_command` - The short name of the check command
|
||||
- `display_name` - The name of the service
|
||||
- `state` - The state: OK/WARNING/CRITICAL/UNKNOWN for services
|
||||
- `source` - The icinga2 host
|
||||
- `port` - The icinga2 port
|
||||
- `scheme` - The icinga2 protocol (http/https)
|
||||
- `server` - The server the check_command is running for
|
||||
- fields
|
||||
- `name` (string)
|
||||
- `state_code` (int)
|
||||
- `icinga2_status`
|
||||
- component:
|
||||
- `ApiListener`
|
||||
- tags
|
||||
- `component` name
|
||||
- fields
|
||||
- `api_num_conn_endpoints`
|
||||
- `api_num_endpoint`
|
||||
- `api_num_http_clients`
|
||||
- `api_num_json_rpc_anonymous_clients`
|
||||
- `api_num_json_rpc_relay_queue_item_rate`
|
||||
- `api_num_json_rpc_relay_queue_items`
|
||||
- `api_num_json_rpc_sync_queue_item_rate`
|
||||
- `api_num_json_rpc_sync_queue_items`
|
||||
- `api_num_json_rpc_work_queue_item_rate`
|
||||
- `api_num_not_conn_endpoints`
|
||||
- `CIB`
|
||||
- tags
|
||||
- `component` name
|
||||
- fields
|
||||
- `active_host_checks`
|
||||
- `active_host_checks_15min`
|
||||
- `active_host_checks_1min`
|
||||
- `active_host_checks_5min`
|
||||
- `active_service_checks`
|
||||
- `active_service_checks_15min`
|
||||
- `active_service_checks_1min`
|
||||
- `active_service_checks_5min`
|
||||
- `avg_execution_time`
|
||||
- `avg_latency`
|
||||
- `current_concurrent_checks`
|
||||
- `current_pending_callbacks`
|
||||
- `max_execution_time`
|
||||
- `max_latency`
|
||||
- `min_execution_time`
|
||||
- `min_latency`
|
||||
- `num_hosts_acknowledged`
|
||||
- `num_hosts_down`
|
||||
- `num_hosts_flapping`
|
||||
- `num_hosts_handled`
|
||||
- `num_hosts_in_downtime`
|
||||
- `num_hosts_pending`
|
||||
- `num_hosts_problem`
|
||||
- `num_hosts_unreachable`
|
||||
- `num_hosts_up`
|
||||
- `num_services_acknowledged`
|
||||
- `num_services_critical`
|
||||
- `num_services_flapping`
|
||||
- `num_services_handled`
|
||||
- `num_services_in_downtime`
|
||||
- `num_services_ok`
|
||||
- `num_services_pending`
|
||||
- `num_services_problem`
|
||||
- `num_services_unknown`
|
||||
- `num_services_unreachable`
|
||||
- `num_services_warning`
|
||||
- `passive_host_checks`
|
||||
- `passive_host_checks_15min`
|
||||
- `passive_host_checks_1min`
|
||||
- `passive_host_checks_5min`
|
||||
- `passive_service_checks`
|
||||
- `passive_service_checks_15min`
|
||||
- `passive_service_checks_1min`
|
||||
- `passive_service_checks_5min`
|
||||
- `remote_check_queue`
|
||||
- `uptime`
|
||||
- `IdoMysqlConnection`
|
||||
- tags
|
||||
- `component` name
|
||||
- fields
|
||||
- `mysql_queries_1min`
|
||||
- `mysql_queries_5mins`
|
||||
- `mysql_queries_15mins`
|
||||
- `mysql_queries_rate`
|
||||
- `mysql_query_queue_item_rate`
|
||||
- `mysql_query_queue_items`
|
||||
- `IdoPgsqlConnection`
|
||||
- tags
|
||||
- `component` name
|
||||
- fields
|
||||
- `pgsql_queries_1min`
|
||||
- `pgsql_queries_5mins`
|
||||
- `pgsql_queries_15mins`
|
||||
- `pgsql_queries_rate`
|
||||
- `pgsql_query_queue_item_rate`
|
||||
- `pgsql_query_queue_items`
|
||||
|
||||
## Sample Queries
|
||||
|
||||
```sql
|
||||
SELECT * FROM "icinga2_services" WHERE state_code = 0 AND time > now() - 24h // Service with OK status
|
||||
SELECT * FROM "icinga2_services" WHERE state_code = 1 AND time > now() - 24h // Service with WARNING status
|
||||
SELECT * FROM "icinga2_services" WHERE state_code = 2 AND time > now() - 24h // Service with CRITICAL status
|
||||
SELECT * FROM "icinga2_services" WHERE state_code = 3 AND time > now() - 24h // Service with UNKNOWN status
|
||||
```
|
||||
|
||||
## Example Output
|
||||
|
||||
```text
|
||||
icinga2_hosts,display_name=router-fr.eqx.fr,check_command=hostalive-custom,host=test-vm,source=localhost,port=5665,scheme=https,state=ok name="router-fr.eqx.fr",state=0 1492021603000000000
|
||||
```
|
299
plugins/inputs/icinga2/icinga2.go
Normal file
299
plugins/inputs/icinga2/icinga2.go
Normal file
|
@ -0,0 +1,299 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package icinga2
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/internal/choice"
|
||||
"github.com/influxdata/telegraf/plugins/common/tls"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
var levels = []string{"ok", "warning", "critical", "unknown"}
|
||||
|
||||
type Icinga2 struct {
|
||||
Server string `toml:"server"`
|
||||
Objects []string `toml:"objects"`
|
||||
Status []string `toml:"status"`
|
||||
ObjectType string `toml:"object_type" deprecated:"1.26.0;1.35.0;use 'objects' instead"`
|
||||
Username string `toml:"username"`
|
||||
Password string `toml:"password"`
|
||||
ResponseTimeout config.Duration `toml:"response_timeout"`
|
||||
tls.ClientConfig
|
||||
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
type resultObject struct {
|
||||
Results []struct {
|
||||
Attrs struct {
|
||||
CheckCommand string `json:"check_command"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Name string `json:"name"`
|
||||
State float64 `json:"state"`
|
||||
HostName string `json:"host_name"`
|
||||
} `json:"attrs"`
|
||||
Name string `json:"name"`
|
||||
Joins struct{} `json:"joins"`
|
||||
Meta struct{} `json:"meta"`
|
||||
Type string `json:"type"`
|
||||
} `json:"results"`
|
||||
}
|
||||
|
||||
type resultCIB struct {
|
||||
Results []struct {
|
||||
Status map[string]interface{} `json:"status"`
|
||||
} `json:"results"`
|
||||
}
|
||||
|
||||
type resultPerfdata struct {
|
||||
Results []struct {
|
||||
Perfdata []struct {
|
||||
Label string `json:"label"`
|
||||
Value float64 `json:"value"`
|
||||
} `json:"perfdata"`
|
||||
} `json:"results"`
|
||||
}
|
||||
|
||||
func (*Icinga2) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (i *Icinga2) Init() error {
|
||||
statusEndpoints := []string{"ApiListener", "CIB", "IdoMysqlConnection", "IdoPgsqlConnection"}
|
||||
if err := choice.CheckSlice(i.Status, statusEndpoints); err != nil {
|
||||
return fmt.Errorf("config option 'status': %w", err)
|
||||
}
|
||||
|
||||
if i.ResponseTimeout < config.Duration(time.Second) {
|
||||
i.ResponseTimeout = config.Duration(time.Second * 5)
|
||||
}
|
||||
|
||||
client, err := i.createHTTPClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.client = client
|
||||
|
||||
// For backward config compatibility
|
||||
if i.ObjectType != "" {
|
||||
i.Objects = []string{i.ObjectType}
|
||||
}
|
||||
|
||||
objectEndpoints := []string{"services", "hosts"}
|
||||
if err := choice.CheckSlice(i.Objects, objectEndpoints); err != nil {
|
||||
return fmt.Errorf("config option 'objects': %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Icinga2) Gather(acc telegraf.Accumulator) error {
|
||||
// Collect /v1/objects
|
||||
for _, objectType := range i.Objects {
|
||||
requestURL := "%s/v1/objects/%s?attrs=name&attrs=display_name&attrs=state&attrs=check_command"
|
||||
|
||||
// Note: attrs=host_name is only valid for 'services' requests, using check.Attrs.HostName for the host
|
||||
// 'hosts' requests will need to use attrs=name only, using check.Attrs.Name for the host
|
||||
if objectType == "services" {
|
||||
requestURL += "&attrs=host_name"
|
||||
}
|
||||
|
||||
address := fmt.Sprintf(requestURL, i.Server, objectType)
|
||||
|
||||
resp, err := i.icingaRequest(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result := resultObject{}
|
||||
err = parseObjectResponse(resp, &result)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse object response: %w", err)
|
||||
}
|
||||
|
||||
i.gatherObjects(acc, result, objectType)
|
||||
}
|
||||
|
||||
// Collect /v1/status
|
||||
for _, statusType := range i.Status {
|
||||
address := fmt.Sprintf("%s/v1/status/%s", i.Server, statusType)
|
||||
|
||||
resp, err := i.icingaRequest(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tags := map[string]string{
|
||||
"component": statusType,
|
||||
}
|
||||
var fields map[string]interface{}
|
||||
|
||||
switch statusType {
|
||||
case "ApiListener":
|
||||
fields, err = parsePerfdataResponse(resp)
|
||||
case "CIB":
|
||||
fields, err = parseCIBResponse(resp)
|
||||
case "IdoMysqlConnection":
|
||||
fields, err = parsePerfdataResponse(resp)
|
||||
case "IdoPgsqlConnection":
|
||||
fields, err = parsePerfdataResponse(resp)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse %s response: %w", statusType, err)
|
||||
}
|
||||
|
||||
acc.AddFields("icinga2_status", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Icinga2) gatherObjects(acc telegraf.Accumulator, checks resultObject, objectType string) {
|
||||
for _, check := range checks.Results {
|
||||
serverURL, err := url.Parse(i.Server)
|
||||
if err != nil {
|
||||
i.Log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
state := int64(check.Attrs.State)
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"name": check.Attrs.Name,
|
||||
"state_code": state,
|
||||
}
|
||||
|
||||
// source is dependent on 'services' or 'hosts' check
|
||||
source := check.Attrs.Name
|
||||
if objectType == "services" {
|
||||
source = check.Attrs.HostName
|
||||
}
|
||||
|
||||
tags := map[string]string{
|
||||
"display_name": check.Attrs.DisplayName,
|
||||
"check_command": check.Attrs.CheckCommand,
|
||||
"source": source,
|
||||
"state": levels[state],
|
||||
"server": serverURL.Hostname(),
|
||||
"scheme": serverURL.Scheme,
|
||||
"port": serverURL.Port(),
|
||||
}
|
||||
|
||||
acc.AddFields("icinga2_"+objectType, fields, tags)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Icinga2) createHTTPClient() (*http.Client, error) {
|
||||
tlsCfg, err := i.ClientConfig.TLSConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: tlsCfg,
|
||||
},
|
||||
Timeout: time.Duration(i.ResponseTimeout),
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (i *Icinga2) icingaRequest(address string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("GET", address, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if i.Username != "" {
|
||||
req.SetBasicAuth(i.Username, i.Password)
|
||||
}
|
||||
|
||||
resp, err := i.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func parseObjectResponse(resp *http.Response, result *resultObject) error {
|
||||
err := json.NewDecoder(resp.Body).Decode(&result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = resp.Body.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseCIBResponse(resp *http.Response) (map[string]interface{}, error) {
|
||||
result := resultCIB{}
|
||||
|
||||
err := json.NewDecoder(resp.Body).Decode(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if len(result.Results) == 0 {
|
||||
return nil, errors.New("no results in Icinga2 API response")
|
||||
}
|
||||
|
||||
return result.Results[0].Status, nil
|
||||
}
|
||||
|
||||
func parsePerfdataResponse(resp *http.Response) (map[string]interface{}, error) {
|
||||
result := resultPerfdata{}
|
||||
|
||||
err := json.NewDecoder(resp.Body).Decode(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if len(result.Results) == 0 {
|
||||
return nil, errors.New("no results in Icinga2 API response")
|
||||
}
|
||||
|
||||
fields := make(map[string]interface{})
|
||||
for _, item := range result.Results[0].Perfdata {
|
||||
i := strings.Index(item.Label, "-")
|
||||
if i > 0 {
|
||||
fields[item.Label[i+1:]] = item.Value
|
||||
} else {
|
||||
fields[item.Label] = item.Value
|
||||
}
|
||||
}
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("icinga2", func() telegraf.Input {
|
||||
return &Icinga2{
|
||||
Server: "https://localhost:5665",
|
||||
Objects: []string{"services"},
|
||||
ResponseTimeout: config.Duration(time.Second * 5),
|
||||
}
|
||||
})
|
||||
}
|
304
plugins/inputs/icinga2/icinga2_test.go
Normal file
304
plugins/inputs/icinga2/icinga2_test.go
Normal file
|
@ -0,0 +1,304 @@
|
|||
package icinga2
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
func TestIcinga2Default(t *testing.T) {
|
||||
// This test should succeed with the default initialization.
|
||||
icinga2 := &Icinga2{
|
||||
Server: "https://localhost:5665",
|
||||
Objects: []string{"services"},
|
||||
ResponseTimeout: config.Duration(time.Second * 5),
|
||||
}
|
||||
require.NoError(t, icinga2.Init())
|
||||
|
||||
require.Equal(t, config.Duration(5*time.Second), icinga2.ResponseTimeout)
|
||||
require.Equal(t, "https://localhost:5665", icinga2.Server)
|
||||
require.Equal(t, []string{"services"}, icinga2.Objects)
|
||||
}
|
||||
|
||||
func TestIcinga2DeprecatedHostConfig(t *testing.T) {
|
||||
icinga2 := &Icinga2{
|
||||
ObjectType: "hosts", // deprecated
|
||||
}
|
||||
require.NoError(t, icinga2.Init())
|
||||
|
||||
require.Equal(t, []string{"hosts"}, icinga2.Objects)
|
||||
}
|
||||
|
||||
func TestIcinga2DeprecatedServicesConfig(t *testing.T) {
|
||||
icinga2 := &Icinga2{
|
||||
ObjectType: "services", // deprecated
|
||||
}
|
||||
require.NoError(t, icinga2.Init())
|
||||
|
||||
require.Equal(t, []string{"services"}, icinga2.Objects)
|
||||
}
|
||||
|
||||
const icinga2ServiceResponse = `{
|
||||
"results": [
|
||||
{
|
||||
"attrs": {
|
||||
"check_command": "check-bgp-juniper-netconf",
|
||||
"display_name": "eq-par.dc2.fr",
|
||||
"host_name": "someserverfqdn.net",
|
||||
"name": "ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe",
|
||||
"state": 0
|
||||
},
|
||||
"joins": {},
|
||||
"meta": {},
|
||||
"name": "eq-par.dc2.fr!ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe",
|
||||
"type": "Service"
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
func TestGatherServicesStatus(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/v1/objects/services" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if _, err := w.Write([]byte(icinga2ServiceResponse)); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
t.Logf("Req: %s %s\n", r.Host, r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var icinga2 = &Icinga2{
|
||||
Server: ts.URL,
|
||||
Objects: []string{"services"},
|
||||
}
|
||||
require.NoError(t, icinga2.Init())
|
||||
var acc testutil.Accumulator
|
||||
err := icinga2.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
requestURL, err := url.Parse(ts.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"name": "ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe",
|
||||
"state_code": int64(0),
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"display_name": "eq-par.dc2.fr",
|
||||
"check_command": "check-bgp-juniper-netconf",
|
||||
"state": "ok",
|
||||
"source": "someserverfqdn.net",
|
||||
"server": requestURL.Hostname(),
|
||||
"port": requestURL.Port(),
|
||||
"scheme": "http",
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "icinga2_services", expectedFields, expectedTags)
|
||||
}
|
||||
|
||||
const icinga2HostResponse = `{
|
||||
"results": [
|
||||
{
|
||||
"attrs": {
|
||||
"address": "192.168.1.1",
|
||||
"check_command": "ping",
|
||||
"display_name": "apache",
|
||||
"name": "webserver",
|
||||
"state": 2.0
|
||||
},
|
||||
"joins": {},
|
||||
"meta": {},
|
||||
"name": "webserver",
|
||||
"type": "Host"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
func TestGatherHostsStatus(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/v1/objects/hosts" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if _, err := w.Write([]byte(icinga2HostResponse)); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
t.Logf("Req: %s %s\n", r.Host, r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var icinga2 = &Icinga2{
|
||||
Server: ts.URL,
|
||||
Objects: []string{"hosts"},
|
||||
}
|
||||
require.NoError(t, icinga2.Init())
|
||||
|
||||
requestURL, err := url.Parse(ts.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err = icinga2.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"name": "webserver",
|
||||
"state_code": int64(2),
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"display_name": "apache",
|
||||
"check_command": "ping",
|
||||
"state": "critical",
|
||||
"source": "webserver",
|
||||
"server": requestURL.Hostname(),
|
||||
"port": requestURL.Port(),
|
||||
"scheme": "http",
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "icinga2_hosts", expectedFields, expectedTags)
|
||||
}
|
||||
|
||||
const icinga2StatusCIB = `{
|
||||
"results": [
|
||||
{
|
||||
"name": "CIB",
|
||||
"perfdata": [],
|
||||
"status": {
|
||||
"active_host_checks": 3.6,
|
||||
"avg_latency": 2.187678621145969e-06,
|
||||
"max_latency": 0.001603841781616211
|
||||
}
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
func TestGatherStatusCIB(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/v1/status/CIB" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if _, err := w.Write([]byte(icinga2StatusCIB)); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
t.Logf("Req: %s %s\n", r.Host, r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var icinga2 = &Icinga2{
|
||||
Server: ts.URL,
|
||||
Status: []string{"CIB"},
|
||||
}
|
||||
require.NoError(t, icinga2.Init())
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := icinga2.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"active_host_checks": float64(3.6),
|
||||
"avg_latency": float64(2.187678621145969e-06),
|
||||
"max_latency": float64(0.001603841781616211),
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"component": "CIB",
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "icinga2_status", expectedFields, expectedTags)
|
||||
}
|
||||
|
||||
const icinga2StatusPgsql = `{
|
||||
"results": [
|
||||
{
|
||||
"name": "IdoPgsqlConnection",
|
||||
"perfdata": [
|
||||
{
|
||||
"counter": false,
|
||||
"crit": null,
|
||||
"label": "idopgsqlconnection_ido-pgsql_queries_rate",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"type": "PerfdataValue",
|
||||
"unit": "",
|
||||
"value": 649.8666666666667,
|
||||
"warn": null
|
||||
},
|
||||
{
|
||||
"counter": false,
|
||||
"crit": null,
|
||||
"label": "idopgsqlconnection_ido-pgsql_query_queue_item_rate",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"type": "PerfdataValue",
|
||||
"unit": "",
|
||||
"value": 1295.1166666666666,
|
||||
"warn": null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
func TestGatherStatusPgsql(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/v1/status/IdoPgsqlConnection" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if _, err := w.Write([]byte(icinga2StatusPgsql)); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
t.Logf("Req: %s %s\n", r.Host, r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
var icinga2 = &Icinga2{
|
||||
Server: ts.URL,
|
||||
Status: []string{"IdoPgsqlConnection"},
|
||||
}
|
||||
require.NoError(t, icinga2.Init())
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := icinga2.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"pgsql_queries_rate": float64(649.8666666666667),
|
||||
"pgsql_query_queue_item_rate": float64(1295.1166666666666),
|
||||
}
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"component": "IdoPgsqlConnection",
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "icinga2_status", expectedFields, expectedTags)
|
||||
}
|
27
plugins/inputs/icinga2/sample.conf
Normal file
27
plugins/inputs/icinga2/sample.conf
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Gather Icinga2 status
|
||||
[[inputs.icinga2]]
|
||||
## Required Icinga2 server address
|
||||
# server = "https://localhost:5665"
|
||||
|
||||
## Collected Icinga2 objects ("services", "hosts")
|
||||
## Specify at least one object to collect from /v1/objects endpoint.
|
||||
# objects = ["services"]
|
||||
|
||||
## Collect metrics from /v1/status endpoint
|
||||
## Choose from:
|
||||
## "ApiListener", "CIB", "IdoMysqlConnection", "IdoPgsqlConnection"
|
||||
# status = []
|
||||
|
||||
## Credentials for basic HTTP authentication
|
||||
# username = "admin"
|
||||
# password = "admin"
|
||||
|
||||
## Maximum time to receive response.
|
||||
# response_timeout = "5s"
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
## Use TLS but skip chain & host verification
|
||||
# insecure_skip_verify = true
|
Loading…
Add table
Add a link
Reference in a new issue