Add IPVS input plugin (#4890)

This commit is contained in:
Akshay Moghe 2018-10-25 12:14:19 -07:00 committed by Daniel Nelson
parent 600b468db2
commit b88436c9d7
6 changed files with 174 additions and 0 deletions

24
Gopkg.lock generated
View File

@ -328,6 +328,14 @@
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c" revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
version = "v0.3.3" version = "v0.3.3"
[[projects]]
branch = "master"
digest = "1:809792497a26f3936462cc5787a0d644b4d3cbfd59587e4f8845a9396ca2eb8a"
name = "github.com/docker/libnetwork"
packages = ["ipvs"]
pruneopts = ""
revision = "d7b61745d16675c9f548b19f06fda80d422a74f0"
[[projects]] [[projects]]
digest = "1:6d6672f85a84411509885eaa32f597577873de00e30729b9bb0eb1e1faa49c12" digest = "1:6d6672f85a84411509885eaa32f597577873de00e30729b9bb0eb1e1faa49c12"
name = "github.com/eapache/go-resiliency" name = "github.com/eapache/go-resiliency"
@ -988,6 +996,21 @@
pruneopts = "" pruneopts = ""
revision = "1731857f09b1f38450e2c12409748407822dc6be" revision = "1731857f09b1f38450e2c12409748407822dc6be"
[[projects]]
digest = "1:026b6ceaabbacaa147e94a63579efc3d3c73e00c73b67fa5c43ab46191ed04eb"
name = "github.com/vishvananda/netlink"
packages = ["nl"]
pruneopts = ""
revision = "b2de5d10e38ecce8607e6b438b6d174f389a004e"
[[projects]]
branch = "master"
digest = "1:c09fddfdd491edaa4383396503e57023a26e5a824283a78c2310613a1252c649"
name = "github.com/vishvananda/netns"
packages = ["."]
pruneopts = ""
revision = "13995c7128ccc8e51e9a6bd2b551020a27180abd"
[[projects]] [[projects]]
digest = "1:343f20460c11a0d0529fe532553bfef9446918d1a1fda6d8661eb27d5b1a68b8" digest = "1:343f20460c11a0d0529fe532553bfef9446918d1a1fda6d8661eb27d5b1a68b8"
name = "github.com/vjeantet/grok" name = "github.com/vjeantet/grok"
@ -1424,6 +1447,7 @@
"github.com/docker/docker/api/types/registry", "github.com/docker/docker/api/types/registry",
"github.com/docker/docker/api/types/swarm", "github.com/docker/docker/api/types/swarm",
"github.com/docker/docker/client", "github.com/docker/docker/client",
"github.com/docker/libnetwork/ipvs",
"github.com/eclipse/paho.mqtt.golang", "github.com/eclipse/paho.mqtt.golang",
"github.com/go-logfmt/logfmt", "github.com/go-logfmt/logfmt",
"github.com/go-redis/redis", "github.com/go-redis/redis",

View File

@ -237,3 +237,11 @@
[[constraint]] [[constraint]]
branch = "master" branch = "master"
name = "golang.org/x/oauth2" name = "golang.org/x/oauth2"
[[constraint]]
branch = "master"
name = "github.com/docker/libnetwork"
[[override]]
name = "github.com/vishvananda/netlink"
revision = "b2de5d10e38ecce8607e6b438b6d174f389a004e"

View File

@ -51,6 +51,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/ipmi_sensor" _ "github.com/influxdata/telegraf/plugins/inputs/ipmi_sensor"
_ "github.com/influxdata/telegraf/plugins/inputs/ipset" _ "github.com/influxdata/telegraf/plugins/inputs/ipset"
_ "github.com/influxdata/telegraf/plugins/inputs/iptables" _ "github.com/influxdata/telegraf/plugins/inputs/iptables"
_ "github.com/influxdata/telegraf/plugins/inputs/ipvs"
_ "github.com/influxdata/telegraf/plugins/inputs/jolokia" _ "github.com/influxdata/telegraf/plugins/inputs/jolokia"
_ "github.com/influxdata/telegraf/plugins/inputs/jolokia2" _ "github.com/influxdata/telegraf/plugins/inputs/jolokia2"
_ "github.com/influxdata/telegraf/plugins/inputs/jti_openconfig_telemetry" _ "github.com/influxdata/telegraf/plugins/inputs/jti_openconfig_telemetry"

View File

@ -0,0 +1,26 @@
# IPVS Input Plugin (Linux)
The IPVS input plugin uses the linux kernel netlink socket interface to gather
metrics about ipvs virtual and real servers.
## Configuration
[[inputs.ipvs]]
# no configuration
## Permissions
Assuming you installed the telegraf package via one of the published packages,
the process will be running as the `telegraf` user. However, in order for this
plugin to communicate over netlink sockets it needs the telegraf process to be
running as `root` (or some user with `CAP_NET_ADMIN` and `CAP_NET_RAW`). Be sure
to ensure these permissions before running telegraf with this plugin included.
## Sample Output
This is what you can expect the emitted metrics to look like
```
ipvs_virtual_server,address=172.18.64.234,address_family=inet,netmask=32,port=9000,protocol=tcp,sched=mh_418 bytes_out=0i,pps_in=0i,pps_out=0i,cps=0i,pkts_in=0i,pkts_out=0i,connections=0i,bytes_in=0i 1540407540000000000
ipvs_virtual_server,address_family=inet,fwmark=47,netmask=32,sched=mh_418 connections=0i,pkts_in=0i,bytes_out=0i,pps_in=0i,pps_out=0i,pkts_out=0i,bytes_in=0i,cps=0i 1540407540000000000
```

112
plugins/inputs/ipvs/ipvs.go Normal file
View File

@ -0,0 +1,112 @@
// +build linux
package ipvs
import (
"errors"
"fmt"
"math/bits"
"strconv"
"syscall"
"github.com/docker/libnetwork/ipvs"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)
// IPVS holds the state for this input plugin
type IPVS struct {
handle *ipvs.Handle
}
// Description returns a description string
func (i *IPVS) Description() string {
return "Collect virtual and real server stats from Linux IPVS"
}
// SampleConfig returns a sample configuration for this input plugin
func (i *IPVS) SampleConfig() string {
return ``
}
// Gather gathers the stats
func (i *IPVS) Gather(acc telegraf.Accumulator) error {
if i.handle == nil {
h, err := ipvs.New("") // TODO: make the namespace configurable
if err != nil {
return errors.New("Unable to open IPVS handle")
}
i.handle = h
}
services, err := i.handle.GetServices()
if err != nil {
i.handle.Close()
i.handle = nil // trigger a reopen on next call to gather
return errors.New("Failed to list IPVS services")
}
for _, s := range services {
fields := map[string]interface{}{
"connections": s.Stats.Connections,
"pkts_in": s.Stats.PacketsIn,
"pkts_out": s.Stats.PacketsOut,
"bytes_in": s.Stats.BytesIn,
"bytes_out": s.Stats.BytesOut,
"pps_in": s.Stats.PPSIn,
"pps_out": s.Stats.PPSOut,
"cps": s.Stats.CPS,
}
acc.AddGauge("ipvs_virtual_server", fields, serviceTags(s))
}
return nil
}
// helper: given a Service, return tags that identify it
func serviceTags(s *ipvs.Service) map[string]string {
ret := map[string]string{
"sched": s.SchedName,
"netmask": fmt.Sprintf("%d", bits.OnesCount32(s.Netmask)),
"address_family": addressFamilyToString(s.AddressFamily),
}
// Per the ipvsadm man page, a virtual service is defined "based on
// protocol/addr/port or firewall mark"
if s.FWMark > 0 {
ret["fwmark"] = strconv.Itoa(int(s.FWMark))
} else {
ret["protocol"] = protocolToString(s.Protocol)
ret["address"] = s.Address.String()
ret["port"] = strconv.Itoa(int(s.Port))
}
return ret
}
// helper: convert protocol uint16 to human readable string (if possible)
func protocolToString(p uint16) string {
switch p {
case syscall.IPPROTO_TCP:
return "tcp"
case syscall.IPPROTO_UDP:
return "udp"
case syscall.IPPROTO_SCTP:
return "sctp"
default:
return fmt.Sprintf("%d", p)
}
}
// helper: convert addressFamily to a human readable string
func addressFamilyToString(af uint16) string {
switch af {
case syscall.AF_INET:
return "inet"
case syscall.AF_INET6:
return "inet6"
default:
return fmt.Sprintf("%d", af)
}
}
func init() {
inputs.Add("ipvs", func() telegraf.Input { return &IPVS{} })
}

View File

@ -0,0 +1,3 @@
// +build !linux
package ipvs