Add Icinga2 input plugin (#4559)
This commit is contained in:
parent
a8496f87b2
commit
e72fab7cbe
|
@ -168,6 +168,7 @@ configuration options.
|
|||
* [http_listener](./plugins/inputs/http_listener)
|
||||
* [http](./plugins/inputs/http) (generic HTTP plugin, supports using input data formats)
|
||||
* [http_response](./plugins/inputs/http_response)
|
||||
* [icinga2](./plugins/inputs/icinga2)
|
||||
* [influxdb](./plugins/inputs/influxdb)
|
||||
* [internal](./plugins/inputs/internal)
|
||||
* [interrupts](./plugins/inputs/interrupts)
|
||||
|
|
|
@ -42,6 +42,7 @@ import (
|
|||
_ "github.com/influxdata/telegraf/plugins/inputs/http_listener"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/http_response"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/httpjson"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/icinga2"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/influxdb"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/internal"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/interrupts"
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
# Icinga2 Input Plugin
|
||||
|
||||
This plugin gather services & hosts status using Icinga2 Remote API.
|
||||
|
||||
The icinga2 plugin uses the icinga2 remote API to gather status on running
|
||||
services and hosts. You can read Icinga2's documentation for their remote API
|
||||
[here](https://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/icinga2-api)
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Description
|
||||
[[inputs.icinga2]]
|
||||
## Required Icinga2 server address (default: "https://localhost:5665")
|
||||
# server = "https://localhost:5665"
|
||||
|
||||
## Required Icinga2 object type ("services" or "hosts, default "services")
|
||||
# object_type = "services"
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
### Measurements & Fields:
|
||||
|
||||
- All measurements have the following fields:
|
||||
- name (string)
|
||||
- state_code (int)
|
||||
|
||||
### Tags:
|
||||
|
||||
- All measurements have the following tags:
|
||||
- check_command
|
||||
- display_name
|
||||
- state
|
||||
- source
|
||||
- port
|
||||
- scheme
|
||||
|
||||
### Sample Queries:
|
||||
|
||||
```
|
||||
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:
|
||||
|
||||
```
|
||||
$ ./telegraf -config telegraf.conf -input-filter icinga2 -test
|
||||
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
|
||||
```
|
|
@ -0,0 +1,170 @@
|
|||
package icinga2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/internal"
|
||||
"github.com/influxdata/telegraf/internal/tls"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type Icinga2 struct {
|
||||
Server string
|
||||
ObjectType string
|
||||
Username string
|
||||
Password string
|
||||
ResponseTimeout internal.Duration
|
||||
tls.ClientConfig
|
||||
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Results []Object `json:"results"`
|
||||
}
|
||||
|
||||
type Object struct {
|
||||
Attrs Attribute `json:"attrs"`
|
||||
Name string `json:"name"`
|
||||
Joins struct{} `json:"joins"`
|
||||
Meta struct{} `json:"meta"`
|
||||
Type ObjectType `json:"type"`
|
||||
}
|
||||
|
||||
type Attribute struct {
|
||||
CheckCommand string `json:"check_command"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Name string `json:"name"`
|
||||
State int `json:"state"`
|
||||
}
|
||||
|
||||
var levels = []string{"ok", "warning", "critical", "unknown"}
|
||||
|
||||
type ObjectType string
|
||||
|
||||
var sampleConfig = `
|
||||
## Required Icinga2 server address (default: "https://localhost:5665")
|
||||
# server = "https://localhost:5665"
|
||||
|
||||
## Required Icinga2 object type ("services" or "hosts, default "services")
|
||||
# object_type = "services"
|
||||
|
||||
## 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
|
||||
`
|
||||
|
||||
func (i *Icinga2) Description() string {
|
||||
return "Gather Icinga2 status"
|
||||
}
|
||||
|
||||
func (i *Icinga2) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (i *Icinga2) GatherStatus(acc telegraf.Accumulator, checks []Object) {
|
||||
for _, check := range checks {
|
||||
fields := make(map[string]interface{})
|
||||
tags := make(map[string]string)
|
||||
|
||||
url, err := url.Parse(i.Server)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fields["name"] = check.Attrs.Name
|
||||
fields["state_code"] = check.Attrs.State
|
||||
|
||||
tags["display_name"] = check.Attrs.DisplayName
|
||||
tags["check_command"] = check.Attrs.CheckCommand
|
||||
tags["state"] = levels[check.Attrs.State]
|
||||
tags["source"] = url.Hostname()
|
||||
tags["scheme"] = url.Scheme
|
||||
tags["port"] = url.Port()
|
||||
|
||||
acc.AddFields(fmt.Sprintf("icinga2_%s", i.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: i.ResponseTimeout.Duration,
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (i *Icinga2) Gather(acc telegraf.Accumulator) error {
|
||||
if i.ResponseTimeout.Duration < time.Second {
|
||||
i.ResponseTimeout.Duration = time.Second * 5
|
||||
}
|
||||
|
||||
if i.client == nil {
|
||||
client, err := i.createHttpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.client = client
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/v1/objects/%s?attrs=name&attrs=display_name&attrs=state&attrs=check_command", i.Server, i.ObjectType)
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i.Username != "" {
|
||||
req.SetBasicAuth(i.Username, i.Password)
|
||||
}
|
||||
|
||||
resp, err := i.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
result := Result{}
|
||||
json.NewDecoder(resp.Body).Decode(&result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.GatherStatus(acc, result.Results)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("icinga2", func() telegraf.Input {
|
||||
return &Icinga2{
|
||||
Server: "https://localhost:5665",
|
||||
ObjectType: "services",
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package icinga2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
func TestGatherServicesStatus(t *testing.T) {
|
||||
|
||||
s := `{"results":[
|
||||
{
|
||||
"attrs": {
|
||||
"check_command": "check-bgp-juniper-netconf",
|
||||
"display_name": "eq-par.dc2.fr",
|
||||
"name": "ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe",
|
||||
"state": 0
|
||||
},
|
||||
"joins": {},
|
||||
"meta": {},
|
||||
"name": "eq-par.dc2.fr!ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe",
|
||||
"type": "Service"
|
||||
}
|
||||
]}`
|
||||
|
||||
checks := Result{}
|
||||
json.Unmarshal([]byte(s), &checks)
|
||||
fields := map[string]interface{}{
|
||||
"name": "ef017af8-c684-4f3f-bb20-0dfe9fcd3dbe",
|
||||
"state_code": 0,
|
||||
}
|
||||
tags := map[string]string{
|
||||
"display_name": "eq-par.dc2.fr",
|
||||
"check_command": "check-bgp-juniper-netconf",
|
||||
"state": "ok",
|
||||
"source": "localhost",
|
||||
"port": "5665",
|
||||
"scheme": "https",
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
icinga2 := new(Icinga2)
|
||||
icinga2.ObjectType = "services"
|
||||
icinga2.Server = "https://localhost:5665"
|
||||
icinga2.GatherStatus(&acc, checks.Results)
|
||||
acc.AssertContainsTaggedFields(t, "icinga2_services", fields, tags)
|
||||
}
|
||||
|
||||
func TestGatherHostsStatus(t *testing.T) {
|
||||
|
||||
s := `{"results":[
|
||||
{
|
||||
"attrs": {
|
||||
"name": "webserver",
|
||||
"address": "192.168.1.1",
|
||||
"check_command": "ping",
|
||||
"display_name": "apache",
|
||||
"state": 2
|
||||
},
|
||||
"joins": {},
|
||||
"meta": {},
|
||||
"name": "webserver",
|
||||
"type": "Host"
|
||||
}
|
||||
]}`
|
||||
|
||||
checks := Result{}
|
||||
json.Unmarshal([]byte(s), &checks)
|
||||
fields := map[string]interface{}{
|
||||
"name": "webserver",
|
||||
"state_code": 2,
|
||||
}
|
||||
tags := map[string]string{
|
||||
"display_name": "apache",
|
||||
"check_command": "ping",
|
||||
"state": "critical",
|
||||
"source": "localhost",
|
||||
"port": "5665",
|
||||
"scheme": "https",
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
icinga2 := new(Icinga2)
|
||||
icinga2.ObjectType = "hosts"
|
||||
icinga2.Server = "https://localhost:5665"
|
||||
icinga2.GatherStatus(&acc, checks.Results)
|
||||
acc.AssertContainsTaggedFields(t, "icinga2_hosts", fields, tags)
|
||||
}
|
Loading…
Reference in New Issue