Add support for sending a request body to http input (#5074)
This commit is contained in:
parent
cf2b85f383
commit
4d3519756c
|
@ -19,6 +19,13 @@ The HTTP input plugin collects metrics from one or more HTTP(S) endpoints. The
|
||||||
## Optional HTTP headers
|
## Optional HTTP headers
|
||||||
# headers = {"X-Special-Header" = "Special-Value"}
|
# headers = {"X-Special-Header" = "Special-Value"}
|
||||||
|
|
||||||
|
## HTTP entity-body to send with POST/PUT requests.
|
||||||
|
# body = ""
|
||||||
|
|
||||||
|
## HTTP Content-Encoding for write request body, can be set to "gzip" to
|
||||||
|
## compress body or "identity" to apply no encoding.
|
||||||
|
# content_encoding = "identity"
|
||||||
|
|
||||||
## Optional HTTP Basic Auth Credentials
|
## Optional HTTP Basic Auth Credentials
|
||||||
# username = "username"
|
# username = "username"
|
||||||
# password = "pa$$word"
|
# password = "pa$$word"
|
||||||
|
|
|
@ -3,6 +3,7 @@ package http
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -18,16 +19,18 @@ import (
|
||||||
|
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
URLs []string `toml:"urls"`
|
URLs []string `toml:"urls"`
|
||||||
Method string
|
Method string `toml:"method"`
|
||||||
|
Body string `toml:"body"`
|
||||||
|
ContentEncoding string `toml:"content_encoding"`
|
||||||
|
|
||||||
Headers map[string]string
|
Headers map[string]string `toml:"headers"`
|
||||||
|
|
||||||
// HTTP Basic Auth Credentials
|
// HTTP Basic Auth Credentials
|
||||||
Username string
|
Username string `toml:"username"`
|
||||||
Password string
|
Password string `toml:"password"`
|
||||||
tls.ClientConfig
|
tls.ClientConfig
|
||||||
|
|
||||||
Timeout internal.Duration
|
Timeout internal.Duration `toml:"timeout"`
|
||||||
|
|
||||||
client *http.Client
|
client *http.Client
|
||||||
|
|
||||||
|
@ -52,6 +55,13 @@ var sampleConfig = `
|
||||||
# username = "username"
|
# username = "username"
|
||||||
# password = "pa$$word"
|
# password = "pa$$word"
|
||||||
|
|
||||||
|
## HTTP entity-body to send with POST/PUT requests.
|
||||||
|
# body = ""
|
||||||
|
|
||||||
|
## HTTP Content-Encoding for write request body, can be set to "gzip" to
|
||||||
|
## compress body or "identity" to apply no encoding.
|
||||||
|
# content_encoding = "identity"
|
||||||
|
|
||||||
## Optional TLS Config
|
## Optional TLS Config
|
||||||
# tls_ca = "/etc/telegraf/ca.pem"
|
# tls_ca = "/etc/telegraf/ca.pem"
|
||||||
# tls_cert = "/etc/telegraf/cert.pem"
|
# tls_cert = "/etc/telegraf/cert.pem"
|
||||||
|
@ -132,11 +142,20 @@ func (h *HTTP) gatherURL(
|
||||||
acc telegraf.Accumulator,
|
acc telegraf.Accumulator,
|
||||||
url string,
|
url string,
|
||||||
) error {
|
) error {
|
||||||
request, err := http.NewRequest(h.Method, url, nil)
|
body, err := makeRequestBodyReader(h.ContentEncoding, h.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request, err := http.NewRequest(h.Method, url, body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.ContentEncoding == "gzip" {
|
||||||
|
request.Header.Set("Content-Encoding", "gzip")
|
||||||
|
}
|
||||||
|
|
||||||
for k, v := range h.Headers {
|
for k, v := range h.Headers {
|
||||||
if strings.ToLower(k) == "host" {
|
if strings.ToLower(k) == "host" {
|
||||||
request.Host = v
|
request.Host = v
|
||||||
|
@ -183,6 +202,18 @@ func (h *HTTP) gatherURL(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeRequestBodyReader(contentEncoding, body string) (io.Reader, error) {
|
||||||
|
var err error
|
||||||
|
var reader io.Reader = strings.NewReader(body)
|
||||||
|
if contentEncoding == "gzip" {
|
||||||
|
reader, err = internal.CompressWithGzip(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reader, nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
inputs.Add("http", func() telegraf.Input {
|
inputs.Add("http", func() telegraf.Input {
|
||||||
return &HTTP{
|
return &HTTP{
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package http_test
|
package http_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -149,3 +152,93 @@ const simpleJSON = `
|
||||||
"a": 1.2
|
"a": 1.2
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
func TestBodyAndContentEncoding(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.NotFoundHandler())
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
url := fmt.Sprintf("http://%s", ts.Listener.Addr().String())
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
plugin *plugin.HTTP
|
||||||
|
queryHandlerFunc func(t *testing.T, w http.ResponseWriter, r *http.Request)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no body",
|
||||||
|
plugin: &plugin.HTTP{
|
||||||
|
Method: "POST",
|
||||||
|
URLs: []string{url},
|
||||||
|
},
|
||||||
|
queryHandlerFunc: func(t *testing.T, w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []byte(""), body)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "post body",
|
||||||
|
plugin: &plugin.HTTP{
|
||||||
|
URLs: []string{url},
|
||||||
|
Method: "POST",
|
||||||
|
Body: "test",
|
||||||
|
},
|
||||||
|
queryHandlerFunc: func(t *testing.T, w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []byte("test"), body)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get method body is sent",
|
||||||
|
plugin: &plugin.HTTP{
|
||||||
|
URLs: []string{url},
|
||||||
|
Method: "GET",
|
||||||
|
Body: "test",
|
||||||
|
},
|
||||||
|
queryHandlerFunc: func(t *testing.T, w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []byte("test"), body)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gzip encoding",
|
||||||
|
plugin: &plugin.HTTP{
|
||||||
|
URLs: []string{url},
|
||||||
|
Method: "GET",
|
||||||
|
Body: "test",
|
||||||
|
ContentEncoding: "gzip",
|
||||||
|
},
|
||||||
|
queryHandlerFunc: func(t *testing.T, w http.ResponseWriter, r *http.Request) {
|
||||||
|
require.Equal(t, r.Header.Get("Content-Encoding"), "gzip")
|
||||||
|
|
||||||
|
gr, err := gzip.NewReader(r.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
body, err := ioutil.ReadAll(gr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []byte("test"), body)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
ts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tt.queryHandlerFunc(t, w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
parser, err := parsers.NewParser(&parsers.Config{DataFormat: "influx"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tt.plugin.SetParser(parser)
|
||||||
|
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
err = tt.plugin.Gather(&acc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue