Added unit tests
This commit is contained in:
166
plugins/inputs/fleet/fleet.go
Normal file
166
plugins/inputs/fleet/fleet.go
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* @Author: Jim Weber
|
||||
* @Date: 2016-05-18 22:07:31
|
||||
* @Last Modified by: Jim Weber
|
||||
* @Last Modified time: 2016-08-08 14:09:03
|
||||
*/
|
||||
|
||||
package fleet
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
// FleetStates struct to hold all the data for a machine state
|
||||
type FleetStates struct {
|
||||
States []struct {
|
||||
SystemdActiveState string `json:"systemdActiveState"`
|
||||
MachineID string `json:"machineID"`
|
||||
Hash string `json:"hash"`
|
||||
SystemdSubState string `json:"systemdSubState"`
|
||||
Name string `json:"name"`
|
||||
SystemdLoadState string `json:"systemdLoadState"`
|
||||
}
|
||||
}
|
||||
|
||||
// Fleet struct to hold fleet hosts
|
||||
type Fleet struct {
|
||||
Hosts []string `toml:"hosts"`
|
||||
}
|
||||
|
||||
// Description - Method to provide description of plugin
|
||||
func (f *Fleet) Description() string {
|
||||
return "Fleetd Plugin to glather information about container states in fleet cluster"
|
||||
}
|
||||
|
||||
// SampleConfig output sample config for this plugin
|
||||
func (*Fleet) SampleConfig() string {
|
||||
return `
|
||||
# Description
|
||||
[[inputs.fleet]]
|
||||
## Works with Fleet HTTP API
|
||||
## Multiple Hosts from which to read Fleet stats:
|
||||
host = ["http://localhost:49153/fleet/v1/state"]
|
||||
`
|
||||
}
|
||||
|
||||
// Gather method to gather stats for telegraf input
|
||||
func (f *Fleet) Gather(accumulator telegraf.Accumulator) error {
|
||||
errorChannel := make(chan error, len(f.Hosts))
|
||||
var wg sync.WaitGroup
|
||||
for _, u := range f.Hosts {
|
||||
wg.Add(1)
|
||||
go func(host string) {
|
||||
defer wg.Done()
|
||||
if err := f.fetchAndReturnData(accumulator, host); err != nil {
|
||||
errorChannel <- fmt.Errorf("[host=%s]: %s", host, err)
|
||||
}
|
||||
}(u)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errorChannel)
|
||||
|
||||
// If there weren't any errors, we can return nil now.
|
||||
if len(errorChannel) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// There were errors, so join them all together as one big error.
|
||||
errorStrings := make([]string, 0, len(errorChannel))
|
||||
for err := range errorChannel {
|
||||
errorStrings = append(errorStrings, err.Error())
|
||||
}
|
||||
|
||||
return errors.New(strings.Join(errorStrings, "\n"))
|
||||
}
|
||||
|
||||
var tr = &http.Transport{
|
||||
ResponseHeaderTimeout: time.Duration(3 * time.Second),
|
||||
}
|
||||
|
||||
var client = &http.Client{
|
||||
Transport: tr,
|
||||
Timeout: time.Duration(4 * time.Second),
|
||||
}
|
||||
|
||||
func (f *Fleet) fetchAndReturnData(accumulator telegraf.Accumulator, host string) error {
|
||||
_, error := client.Get(host)
|
||||
if error != nil {
|
||||
return error
|
||||
}
|
||||
|
||||
fleetStates := getInstanceStates(host, nil)
|
||||
containerCounts := getContainerCount(fleetStates)
|
||||
fields := make(map[string]interface{})
|
||||
tags := make(map[string]string)
|
||||
|
||||
for k, v := range containerCounts {
|
||||
fields[k] = v
|
||||
}
|
||||
|
||||
// create tags for each host if needed
|
||||
tags["server"] = host
|
||||
|
||||
accumulator.AddFields("fleet", fields, tags)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getInstanceStates(host string, params map[string]string) FleetStates {
|
||||
|
||||
response, err := http.Get(host)
|
||||
fleetStates := FleetStates{}
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("%s", err)
|
||||
} else {
|
||||
defer response.Body.Close()
|
||||
contents, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(contents, &fleetStates); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return fleetStates
|
||||
}
|
||||
|
||||
func getContainerCount(fleetUnits FleetStates) map[string]int {
|
||||
containerCount := make(map[string]int)
|
||||
for _, fleetUnit := range fleetUnits.States {
|
||||
shortNameParts := strings.Split(fleetUnit.Name, "@")
|
||||
if len(shortNameParts) == 0 {
|
||||
// global units do not use the '@' symbol because they do not have instance ids
|
||||
// instead just split off the .server porition
|
||||
shortNameParts = strings.Split(fleetUnit.Name, ".")
|
||||
}
|
||||
shortName := shortNameParts[0]
|
||||
if fleetUnit.SystemdSubState == "running" {
|
||||
containerCount[shortName]++
|
||||
}
|
||||
}
|
||||
|
||||
return containerCount
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("fleet", func() telegraf.Input {
|
||||
return &Fleet{}
|
||||
})
|
||||
}
|
||||
205
plugins/inputs/fleet/fleet_test.go
Normal file
205
plugins/inputs/fleet/fleet_test.go
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* @Author: Jim Weber
|
||||
* @Date: 2016-08-08 09:42:04
|
||||
* @Last Modified by: Jim Weber
|
||||
* @Last Modified time: 2016-08-08 14:09:59
|
||||
*/
|
||||
|
||||
package fleet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, fleetResponseData)
|
||||
}))
|
||||
|
||||
var fleetResponseData = `{
|
||||
"states": [
|
||||
{
|
||||
"hash": "67e33cb6ce9104fa451765128159eaccad11dee8",
|
||||
"machineID": "2d69b20e090a4859b2c9ec7d48b0188c",
|
||||
"name": "auth-api@34.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "67e33cb6ce9104fa451765128159eaccad11dee8",
|
||||
"machineID": "68d18238915842298dc6cd3b90824237",
|
||||
"name": "auth-api@35.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "1ebad1f4aa1b11af59c12e3d0fa58985807b54bb",
|
||||
"machineID": "635a42fc35b241ffa170c1dc1befa01c",
|
||||
"name": "ident@34.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "8a053bc6517baf8473d0ea7872acbd8c31dba0f8",
|
||||
"machineID": "39515ef8debc423c961543d45e382c63",
|
||||
"name": "help-api@55.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "30bf8d8bb392eb65497f2d0e4ea508401054949c",
|
||||
"machineID": "885814e701d94d67bd1264fb1b9c9958",
|
||||
"name": "fixer@50.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "30bf8d8bb392eb65497f2d0e4ea508401054949c",
|
||||
"machineID": "39515ef8debc423c961543d45e382c63",
|
||||
"name": "fixer@51.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "67cc24e573c05fba29de2bbc5cc4b522601ffcf4",
|
||||
"machineID": "2d69b20e090a4859b2c9ec7d48b0188c",
|
||||
"name": "logspout.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "67cc24e573c05fba29de2bbc5cc4b522601ffcf4",
|
||||
"machineID": "39515ef8debc423c961543d45e382c63",
|
||||
"name": "logspout.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "67cc24e573c05fba29de2bbc5cc4b522601ffcf4",
|
||||
"machineID": "635a42fc35b241ffa170c1dc1befa01c",
|
||||
"name": "logspout.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "67cc24e573c05fba29de2bbc5cc4b522601ffcf4",
|
||||
"machineID": "68d18238915842298dc6cd3b90824237",
|
||||
"name": "logspout.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "67cc24e573c05fba29de2bbc5cc4b522601ffcf4",
|
||||
"machineID": "885814e701d94d67bd1264fb1b9c9958",
|
||||
"name": "logspout.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "e6cd43573b54647d4508617f98ed6bae9db1be18",
|
||||
"machineID": "2d69b20e090a4859b2c9ec7d48b0188c",
|
||||
"name": "logstash@56.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "c40cddaed92a845a8ac93eccdc7a5a5517697816",
|
||||
"machineID": "635a42fc35b241ffa170c1dc1befa01c",
|
||||
"name": "logstash-serverlogs@10.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "f9a0c0c9f105bfac4133d5f23856146b27c48931",
|
||||
"machineID": "68d18238915842298dc6cd3b90824237",
|
||||
"name": "nginx@19.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "f9a0c0c9f105bfac4133d5f23856146b27c48931",
|
||||
"machineID": "39515ef8debc423c961543d45e382c63",
|
||||
"name": "nginx@20.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "failed"
|
||||
},
|
||||
{
|
||||
"hash": "7a2914683ef7bae3576bd1e48269839349f58752",
|
||||
"machineID": "885814e701d94d67bd1264fb1b9c9958",
|
||||
"name": "nginx@18.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "7a2914683ef7bae3576bd1e48269839349f58752",
|
||||
"machineID": "68d18238915842298dc6cd3b90824237",
|
||||
"name": "nginx@19.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "8a6b627f67b6ab113f083bef1d7c2e583a12eea5",
|
||||
"machineID": "39515ef8debc423c961543d45e382c63",
|
||||
"name": "weave.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "8a6b627f67b6ab113f083bef1d7c2e583a12eea5",
|
||||
"machineID": "635a42fc35b241ffa170c1dc1befa01c",
|
||||
"name": "weave.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
},
|
||||
{
|
||||
"hash": "8a6b627f67b6ab113f083bef1d7c2e583a12eea5",
|
||||
"machineID": "68d18238915842298dc6cd3b90824237",
|
||||
"name": "weave.service",
|
||||
"systemdActiveState": "active",
|
||||
"systemdLoadState": "loaded",
|
||||
"systemdSubState": "running"
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
func TestGetInstanceStates(t *testing.T) {
|
||||
fleetStates := getInstanceStates(ts.URL, nil)
|
||||
if fleetStates.States[0].MachineID != "2d69b20e090a4859b2c9ec7d48b0188c" {
|
||||
t.Errorf("First machine id json response to be 2d69b20e090a4859b2c9ec7d48b0188c got %v instead", fleetStates.States[0].MachineID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetContainerCount(t *testing.T) {
|
||||
fleetStates := getInstanceStates(ts.URL, nil)
|
||||
containerCounts := getContainerCount(fleetStates)
|
||||
|
||||
if containerCounts["auth-api"] != 2 {
|
||||
t.Errorf("Auth api count is incorrect got %d instead of 2", containerCounts["auth-api"])
|
||||
}
|
||||
|
||||
if containerCounts["nginx"] != 3 {
|
||||
t.Errorf("nginx count is incorrect got %d instead of 4", containerCounts["nginx"])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user