mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-06 01:38:10 +00:00
Merge pull request #509 from ksauzz/feature/query-verb
Add --prometheus-verb to support POST requests to prometheus servers
This commit is contained in:
commit
dd85956fbf
2 changed files with 37 additions and 12 deletions
|
|
@ -74,6 +74,8 @@ type PrometheusAdapter struct {
|
||||||
PrometheusTokenFile string
|
PrometheusTokenFile string
|
||||||
// PrometheusHeaders is a k=v list of headers to set on requests to PrometheusURL
|
// PrometheusHeaders is a k=v list of headers to set on requests to PrometheusURL
|
||||||
PrometheusHeaders []string
|
PrometheusHeaders []string
|
||||||
|
// PrometheusVerb is a verb to set on requests to PrometheusURL
|
||||||
|
PrometheusVerb string
|
||||||
// AdapterConfigFile points to the file containing the metrics discovery configuration.
|
// AdapterConfigFile points to the file containing the metrics discovery configuration.
|
||||||
AdapterConfigFile string
|
AdapterConfigFile string
|
||||||
// MetricsRelistInterval is the interval at which to relist the set of available metrics
|
// MetricsRelistInterval is the interval at which to relist the set of available metrics
|
||||||
|
|
@ -90,6 +92,10 @@ func (cmd *PrometheusAdapter) makePromClient() (prom.Client, error) {
|
||||||
return nil, fmt.Errorf("invalid Prometheus URL %q: %v", baseURL, err)
|
return nil, fmt.Errorf("invalid Prometheus URL %q: %v", baseURL, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cmd.PrometheusVerb != http.MethodGet && cmd.PrometheusVerb != http.MethodPost {
|
||||||
|
return nil, fmt.Errorf("unsupported Prometheus HTTP verb %q. use \"GET\" or \"POST\" instead.", cmd.PrometheusVerb)
|
||||||
|
}
|
||||||
|
|
||||||
var httpClient *http.Client
|
var httpClient *http.Client
|
||||||
|
|
||||||
if cmd.PrometheusCAFile != "" {
|
if cmd.PrometheusCAFile != "" {
|
||||||
|
|
@ -117,7 +123,7 @@ func (cmd *PrometheusAdapter) makePromClient() (prom.Client, error) {
|
||||||
}
|
}
|
||||||
genericPromClient := prom.NewGenericAPIClient(httpClient, baseURL, parseHeaderArgs(cmd.PrometheusHeaders))
|
genericPromClient := prom.NewGenericAPIClient(httpClient, baseURL, parseHeaderArgs(cmd.PrometheusHeaders))
|
||||||
instrumentedGenericPromClient := mprom.InstrumentGenericAPIClient(genericPromClient, baseURL.String())
|
instrumentedGenericPromClient := mprom.InstrumentGenericAPIClient(genericPromClient, baseURL.String())
|
||||||
return prom.NewClientForAPI(instrumentedGenericPromClient), nil
|
return prom.NewClientForAPI(instrumentedGenericPromClient, cmd.PrometheusVerb), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *PrometheusAdapter) addFlags() {
|
func (cmd *PrometheusAdapter) addFlags() {
|
||||||
|
|
@ -137,6 +143,8 @@ func (cmd *PrometheusAdapter) addFlags() {
|
||||||
"Optional file containing the bearer token to use when connecting with Prometheus")
|
"Optional file containing the bearer token to use when connecting with Prometheus")
|
||||||
cmd.Flags().StringArrayVar(&cmd.PrometheusHeaders, "prometheus-header", cmd.PrometheusHeaders,
|
cmd.Flags().StringArrayVar(&cmd.PrometheusHeaders, "prometheus-header", cmd.PrometheusHeaders,
|
||||||
"Optional header to set on requests to prometheus-url. Can be repeated")
|
"Optional header to set on requests to prometheus-url. Can be repeated")
|
||||||
|
cmd.Flags().StringVar(&cmd.PrometheusVerb, "prometheus-verb", cmd.PrometheusVerb,
|
||||||
|
"HTTP verb to set on requests to Prometheus. Possible values: \"GET\", \"POST\"")
|
||||||
cmd.Flags().StringVar(&cmd.AdapterConfigFile, "config", cmd.AdapterConfigFile,
|
cmd.Flags().StringVar(&cmd.AdapterConfigFile, "config", cmd.AdapterConfigFile,
|
||||||
"Configuration file containing details of how to transform between Prometheus metrics "+
|
"Configuration file containing details of how to transform between Prometheus metrics "+
|
||||||
"and custom metrics API resources")
|
"and custom metrics API resources")
|
||||||
|
|
@ -274,6 +282,7 @@ func main() {
|
||||||
// set up flags
|
// set up flags
|
||||||
cmd := &PrometheusAdapter{
|
cmd := &PrometheusAdapter{
|
||||||
PrometheusURL: "https://localhost",
|
PrometheusURL: "https://localhost",
|
||||||
|
PrometheusVerb: http.MethodGet,
|
||||||
MetricsRelistInterval: 10 * time.Minute,
|
MetricsRelistInterval: 10 * time.Minute,
|
||||||
}
|
}
|
||||||
cmd.Name = "prometheus-metrics-adapter"
|
cmd.Name = "prometheus-metrics-adapter"
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
|
|
@ -53,13 +54,26 @@ type httpAPIClient struct {
|
||||||
func (c *httpAPIClient) Do(ctx context.Context, verb, endpoint string, query url.Values) (APIResponse, error) {
|
func (c *httpAPIClient) Do(ctx context.Context, verb, endpoint string, query url.Values) (APIResponse, error) {
|
||||||
u := *c.baseURL
|
u := *c.baseURL
|
||||||
u.Path = path.Join(c.baseURL.Path, endpoint)
|
u.Path = path.Join(c.baseURL.Path, endpoint)
|
||||||
u.RawQuery = query.Encode()
|
var reqBody io.Reader
|
||||||
req, err := http.NewRequest(verb, u.String(), nil)
|
if verb == http.MethodGet {
|
||||||
|
u.RawQuery = query.Encode()
|
||||||
|
} else if verb == http.MethodPost {
|
||||||
|
reqBody = strings.NewReader(query.Encode())
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(verb, u.String(), reqBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, fmt.Errorf("error constructing HTTP request to Prometheus: %v", err)
|
return APIResponse{}, fmt.Errorf("error constructing HTTP request to Prometheus: %v", err)
|
||||||
}
|
}
|
||||||
req.WithContext(ctx)
|
req.WithContext(ctx)
|
||||||
req.Header = c.headers
|
for key, values := range c.headers {
|
||||||
|
for _, value := range values {
|
||||||
|
req.Header.Add(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if verb == http.MethodPost {
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := c.client.Do(req)
|
resp, err := c.client.Do(req)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
@ -131,20 +145,22 @@ const (
|
||||||
|
|
||||||
// queryClient is a Client that connects to the Prometheus HTTP API.
|
// queryClient is a Client that connects to the Prometheus HTTP API.
|
||||||
type queryClient struct {
|
type queryClient struct {
|
||||||
api GenericAPIClient
|
api GenericAPIClient
|
||||||
|
verb string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClientForAPI creates a Client for the given generic Prometheus API client.
|
// NewClientForAPI creates a Client for the given generic Prometheus API client.
|
||||||
func NewClientForAPI(client GenericAPIClient) Client {
|
func NewClientForAPI(client GenericAPIClient, verb string) Client {
|
||||||
return &queryClient{
|
return &queryClient{
|
||||||
api: client,
|
api: client,
|
||||||
|
verb: verb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a Client for the given HTTP client and base URL (the location of the Prometheus server).
|
// NewClient creates a Client for the given HTTP client and base URL (the location of the Prometheus server).
|
||||||
func NewClient(client *http.Client, baseURL *url.URL, headers http.Header) Client {
|
func NewClient(client *http.Client, baseURL *url.URL, headers http.Header, verb string) Client {
|
||||||
genericClient := NewGenericAPIClient(client, baseURL, headers)
|
genericClient := NewGenericAPIClient(client, baseURL, headers)
|
||||||
return NewClientForAPI(genericClient)
|
return NewClientForAPI(genericClient, verb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *queryClient) Series(ctx context.Context, interval model.Interval, selectors ...Selector) ([]Series, error) {
|
func (h *queryClient) Series(ctx context.Context, interval model.Interval, selectors ...Selector) ([]Series, error) {
|
||||||
|
|
@ -160,7 +176,7 @@ func (h *queryClient) Series(ctx context.Context, interval model.Interval, selec
|
||||||
vals.Add("match[]", string(selector))
|
vals.Add("match[]", string(selector))
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := h.api.Do(ctx, "GET", seriesURL, vals)
|
res, err := h.api.Do(ctx, h.verb, seriesURL, vals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +196,7 @@ func (h *queryClient) Query(ctx context.Context, t model.Time, query Selector) (
|
||||||
vals.Set("timeout", model.Duration(timeout).String())
|
vals.Set("timeout", model.Duration(timeout).String())
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := h.api.Do(ctx, "GET", queryURL, vals)
|
res, err := h.api.Do(ctx, h.verb, queryURL, vals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return QueryResult{}, err
|
return QueryResult{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +223,7 @@ func (h *queryClient) QueryRange(ctx context.Context, r Range, query Selector) (
|
||||||
vals.Set("timeout", model.Duration(timeout).String())
|
vals.Set("timeout", model.Duration(timeout).String())
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := h.api.Do(ctx, "GET", queryRangeURL, vals)
|
res, err := h.api.Do(ctx, h.verb, queryRangeURL, vals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return QueryResult{}, err
|
return QueryResult{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue