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
344
plugins/inputs/haproxy/haproxy_test.go
Normal file
344
plugins/inputs/haproxy/haproxy_test.go
Normal file
|
@ -0,0 +1,344 @@
|
|||
package haproxy
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
func serverSocket(l net.Listener) {
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go func(c net.Conn) {
|
||||
defer c.Close()
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
n, err := c.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := buf[:n]
|
||||
if string(data) == "show stat\n" {
|
||||
c.Write(csvOutputSample) //nolint:errcheck // we return anyway
|
||||
}
|
||||
}(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHaproxyGeneratesMetricsWithAuthentication(t *testing.T) {
|
||||
// We create a fake server to return test data
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
if _, err := fmt.Fprint(w, "Unauthorized"); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if username == "user" && password == "password" {
|
||||
if _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
if _, err := fmt.Fprint(w, "Unauthorized"); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
// Now we tested again above server, with our authentication data
|
||||
r := &HAProxy{
|
||||
Servers: []string{strings.Replace(ts.URL, "http://", "http://user:password@", 1)},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := r.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
tags := map[string]string{
|
||||
"server": ts.Listener.Addr().String(),
|
||||
"proxy": "git",
|
||||
"sv": "www",
|
||||
"type": "server",
|
||||
}
|
||||
|
||||
fields := haproxyGetFieldValues()
|
||||
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
|
||||
|
||||
// Here, we should get error because we don't pass authentication data
|
||||
r = &HAProxy{
|
||||
Servers: []string{ts.URL},
|
||||
}
|
||||
|
||||
require.NoError(t, r.Gather(&acc))
|
||||
require.NotEmpty(t, acc.Errors)
|
||||
}
|
||||
|
||||
func TestHaproxyGeneratesMetricsWithoutAuthentication(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
if _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
r := &HAProxy{
|
||||
Servers: []string{ts.URL},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
require.NoError(t, r.Gather(&acc))
|
||||
|
||||
tags := map[string]string{
|
||||
"server": ts.Listener.Addr().String(),
|
||||
"proxy": "git",
|
||||
"sv": "www",
|
||||
"type": "server",
|
||||
}
|
||||
|
||||
fields := haproxyGetFieldValues()
|
||||
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
|
||||
}
|
||||
|
||||
func TestHaproxyGeneratesMetricsUsingSocket(t *testing.T) {
|
||||
var randomNumber int64
|
||||
var sockets [5]net.Listener
|
||||
|
||||
// The Maximum length of the socket path is 104/108 characters, path created with t.TempDir() is too long for some cases
|
||||
// (it combines test name with subtest name and some random numbers in the path). Therefore, in this case, it is safer to stick with `os.MkdirTemp()`.
|
||||
//nolint:usetesting // Ignore "os.TempDir() could be replaced by t.TempDir() in TestHaproxyGeneratesMetricsUsingSocket" finding.
|
||||
tempDir := os.TempDir()
|
||||
_globmask := filepath.Join(tempDir, "test-haproxy*.sock")
|
||||
_badmask := filepath.Join(tempDir, "test-fail-haproxy*.sock")
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
require.NoError(t, binary.Read(rand.Reader, binary.LittleEndian, &randomNumber))
|
||||
sockname := filepath.Join(tempDir, fmt.Sprintf("test-haproxy%d.sock", randomNumber))
|
||||
|
||||
sock, err := net.Listen("unix", sockname)
|
||||
require.NoError(t, err, "Cannot initialize socket")
|
||||
|
||||
sockets[i] = sock
|
||||
defer sock.Close() //nolint:revive,gocritic // done on purpose, closing will be executed properly
|
||||
|
||||
go serverSocket(sock)
|
||||
}
|
||||
|
||||
r := &HAProxy{
|
||||
Servers: []string{_globmask},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := r.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
fields := haproxyGetFieldValues()
|
||||
|
||||
for _, sock := range sockets {
|
||||
tags := map[string]string{
|
||||
"server": getSocketAddr(sock.Addr().String()),
|
||||
"proxy": "git",
|
||||
"sv": "www",
|
||||
"type": "server",
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
|
||||
}
|
||||
|
||||
// This mask should not match any socket
|
||||
r.Servers = []string{_badmask}
|
||||
|
||||
require.NoError(t, r.Gather(&acc))
|
||||
require.NotEmpty(t, acc.Errors)
|
||||
}
|
||||
|
||||
func TestHaproxyGeneratesMetricsUsingTcp(t *testing.T) {
|
||||
l, err := net.Listen("tcp", "localhost:8192")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
go serverSocket(l)
|
||||
|
||||
r := &HAProxy{
|
||||
Servers: []string{"tcp://" + l.Addr().String()},
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
require.NoError(t, r.Gather(&acc))
|
||||
|
||||
fields := haproxyGetFieldValues()
|
||||
|
||||
tags := map[string]string{
|
||||
"server": l.Addr().String(),
|
||||
"proxy": "git",
|
||||
"sv": "www",
|
||||
"type": "server",
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
|
||||
|
||||
require.NoError(t, r.Gather(&acc))
|
||||
}
|
||||
|
||||
// When not passing server config, we default to localhost
|
||||
// We just want to make sure we did request stat from localhost
|
||||
func TestHaproxyDefaultGetFromLocalhost(t *testing.T) {
|
||||
r := &HAProxy{}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := r.Gather(&acc)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "127.0.0.1:1936/haproxy?stats/;csv")
|
||||
}
|
||||
|
||||
func TestHaproxyKeepFieldNames(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
if _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
r := &HAProxy{
|
||||
Servers: []string{ts.URL},
|
||||
KeepFieldNames: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
|
||||
require.NoError(t, r.Gather(&acc))
|
||||
|
||||
tags := map[string]string{
|
||||
"server": ts.Listener.Addr().String(),
|
||||
"pxname": "git",
|
||||
"svname": "www",
|
||||
"type": "server",
|
||||
}
|
||||
|
||||
fields := haproxyGetFieldValues()
|
||||
fields["act"] = fields["active_servers"]
|
||||
delete(fields, "active_servers")
|
||||
fields["bck"] = fields["backup_servers"]
|
||||
delete(fields, "backup_servers")
|
||||
fields["cli_abrt"] = fields["cli_abort"]
|
||||
delete(fields, "cli_abort")
|
||||
fields["srv_abrt"] = fields["srv_abort"]
|
||||
delete(fields, "srv_abort")
|
||||
fields["hrsp_1xx"] = fields["http_response.1xx"]
|
||||
delete(fields, "http_response.1xx")
|
||||
fields["hrsp_2xx"] = fields["http_response.2xx"]
|
||||
delete(fields, "http_response.2xx")
|
||||
fields["hrsp_3xx"] = fields["http_response.3xx"]
|
||||
delete(fields, "http_response.3xx")
|
||||
fields["hrsp_4xx"] = fields["http_response.4xx"]
|
||||
delete(fields, "http_response.4xx")
|
||||
fields["hrsp_5xx"] = fields["http_response.5xx"]
|
||||
delete(fields, "http_response.5xx")
|
||||
fields["hrsp_other"] = fields["http_response.other"]
|
||||
delete(fields, "http_response.other")
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
|
||||
}
|
||||
|
||||
func mustReadSampleOutput() []byte {
|
||||
filePath := "testdata/sample_output.csv"
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("could not read from file %s: %w", filePath, err))
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func haproxyGetFieldValues() map[string]interface{} {
|
||||
fields := map[string]interface{}{
|
||||
"active_servers": uint64(1),
|
||||
"backup_servers": uint64(0),
|
||||
"bin": uint64(5228218),
|
||||
"bout": uint64(303747244),
|
||||
"check_code": uint64(200),
|
||||
"check_duration": uint64(3),
|
||||
"check_fall": uint64(3),
|
||||
"check_health": uint64(4),
|
||||
"check_rise": uint64(2),
|
||||
"check_status": "L7OK",
|
||||
"chkdown": uint64(84),
|
||||
"chkfail": uint64(559),
|
||||
"cli_abort": uint64(690),
|
||||
"ctime": uint64(1),
|
||||
"downtime": uint64(3352),
|
||||
"dresp": uint64(0),
|
||||
"econ": uint64(0),
|
||||
"eresp": uint64(21),
|
||||
"http_response.1xx": uint64(0),
|
||||
"http_response.2xx": uint64(5668),
|
||||
"http_response.3xx": uint64(8710),
|
||||
"http_response.4xx": uint64(140),
|
||||
"http_response.5xx": uint64(0),
|
||||
"http_response.other": uint64(0),
|
||||
"iid": uint64(4),
|
||||
"last_chk": "OK",
|
||||
"lastchg": uint64(1036557),
|
||||
"lastsess": int64(1342),
|
||||
"lbtot": uint64(9481),
|
||||
"mode": "http",
|
||||
"pid": uint64(1),
|
||||
"qcur": uint64(0),
|
||||
"qmax": uint64(0),
|
||||
"qtime": uint64(1268),
|
||||
"rate": uint64(0),
|
||||
"rate_max": uint64(2),
|
||||
"rtime": uint64(2908),
|
||||
"sid": uint64(1),
|
||||
"scur": uint64(0),
|
||||
"slim": uint64(2),
|
||||
"smax": uint64(2),
|
||||
"srv_abort": uint64(0),
|
||||
"status": "UP",
|
||||
"stot": uint64(14539),
|
||||
"ttime": uint64(4500),
|
||||
"weight": uint64(1),
|
||||
"wredis": uint64(0),
|
||||
"wretr": uint64(0),
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
// Can obtain from official haproxy demo: 'http://demo.haproxy.org/;csv'
|
||||
var csvOutputSample = mustReadSampleOutput()
|
Loading…
Add table
Add a link
Reference in a new issue