2018-05-14 16:26:38 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
2019-12-08 04:10:22 +00:00
|
|
|
"crypto/tls"
|
|
|
|
"net"
|
2018-05-14 16:26:38 +00:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2019-12-08 04:10:22 +00:00
|
|
|
"time"
|
2019-04-11 02:28:21 +00:00
|
|
|
|
2020-04-20 16:55:23 +00:00
|
|
|
"github.com/influxdata/influxdb/v2/dbrp"
|
2020-04-03 17:39:20 +00:00
|
|
|
"github.com/influxdata/influxdb/v2/kit/tracing"
|
|
|
|
"github.com/influxdata/influxdb/v2/pkg/httpc"
|
2018-05-14 16:26:38 +00:00
|
|
|
)
|
|
|
|
|
2019-12-08 04:10:22 +00:00
|
|
|
// NewHTTPClient creates a new httpc.Client type. This call sets all
|
|
|
|
// the options that are important to the http pkg on the httpc client.
|
|
|
|
// The default status fn and so forth will all be set for the caller.
|
2020-02-26 10:37:57 +00:00
|
|
|
// In addition, some options can be specified. Those will be added to the defaults.
|
|
|
|
func NewHTTPClient(addr, token string, insecureSkipVerify bool, opts ...httpc.ClientOptFn) (*httpc.Client, error) {
|
2019-12-08 04:10:22 +00:00
|
|
|
u, err := url.Parse(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-26 10:37:57 +00:00
|
|
|
defaultOpts := []httpc.ClientOptFn{
|
2019-12-08 04:10:22 +00:00
|
|
|
httpc.WithAddr(addr),
|
|
|
|
httpc.WithContentType("application/json"),
|
|
|
|
httpc.WithHTTPClient(NewClient(u.Scheme, insecureSkipVerify)),
|
|
|
|
httpc.WithInsecureSkipVerify(insecureSkipVerify),
|
|
|
|
httpc.WithStatusFn(CheckError),
|
|
|
|
}
|
|
|
|
if token != "" {
|
2020-02-26 10:37:57 +00:00
|
|
|
defaultOpts = append(defaultOpts, httpc.WithAuthToken(token))
|
2019-12-08 04:10:22 +00:00
|
|
|
}
|
2020-02-26 10:37:57 +00:00
|
|
|
opts = append(defaultOpts, opts...)
|
2019-12-08 04:10:22 +00:00
|
|
|
return httpc.New(opts...)
|
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
// Service connects to an InfluxDB via HTTP.
|
|
|
|
type Service struct {
|
|
|
|
Addr string
|
|
|
|
Token string
|
|
|
|
InsecureSkipVerify bool
|
|
|
|
|
2020-02-24 19:41:21 +00:00
|
|
|
*TaskService
|
2020-03-05 00:32:33 +00:00
|
|
|
*NotificationRuleService
|
2019-02-14 20:32:54 +00:00
|
|
|
*VariableService
|
2019-12-07 18:54:03 +00:00
|
|
|
*WriteService
|
2020-02-26 16:34:10 +00:00
|
|
|
*CheckService
|
2020-02-26 10:37:57 +00:00
|
|
|
*NotificationEndpointService
|
|
|
|
*TelegrafService
|
|
|
|
*LabelService
|
2020-04-20 16:55:23 +00:00
|
|
|
DBRPMappingServiceV2 *dbrp.Client
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
2020-02-26 10:37:57 +00:00
|
|
|
// NewService returns a service that is an HTTP client to a remote.
|
|
|
|
// Address and token are needed for those services that do not use httpc.Client,
|
|
|
|
// but use those for configuring.
|
|
|
|
// Usually one would do:
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// c := NewHTTPClient(addr, token, insecureSkipVerify)
|
|
|
|
// s := NewService(c, addr token)
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// So one should provide the same `addr` and `token` to both calls to ensure consistency
|
|
|
|
// in the behavior of the returned service.
|
|
|
|
func NewService(httpClient *httpc.Client, addr, token string) (*Service, error) {
|
2018-09-17 02:39:46 +00:00
|
|
|
return &Service{
|
2021-06-17 13:18:55 +00:00
|
|
|
Addr: addr,
|
|
|
|
Token: token,
|
2020-03-05 00:32:33 +00:00
|
|
|
TaskService: &TaskService{Client: httpClient},
|
|
|
|
NotificationRuleService: &NotificationRuleService{Client: httpClient},
|
|
|
|
VariableService: &VariableService{Client: httpClient},
|
2019-12-07 18:54:03 +00:00
|
|
|
WriteService: &WriteService{
|
2018-09-17 02:39:46 +00:00
|
|
|
Addr: addr,
|
|
|
|
Token: token,
|
|
|
|
},
|
2020-02-26 10:37:57 +00:00
|
|
|
CheckService: &CheckService{Client: httpClient},
|
|
|
|
NotificationEndpointService: &NotificationEndpointService{Client: httpClient},
|
|
|
|
TelegrafService: NewTelegrafService(httpClient),
|
|
|
|
LabelService: &LabelService{Client: httpClient},
|
2020-04-20 16:55:23 +00:00
|
|
|
DBRPMappingServiceV2: dbrp.NewClient(httpClient),
|
2019-12-07 18:54:03 +00:00
|
|
|
}, nil
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
2019-06-26 05:48:15 +00:00
|
|
|
// NewURL concats addr and path.
|
2019-05-09 17:41:14 +00:00
|
|
|
func NewURL(addr, path string) (*url.URL, error) {
|
2018-05-14 16:26:38 +00:00
|
|
|
u, err := url.Parse(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
u.Path = path
|
|
|
|
return u, nil
|
|
|
|
}
|
|
|
|
|
2019-06-26 05:48:15 +00:00
|
|
|
// NewClient returns an http.Client that pools connections and injects a span.
|
2019-12-08 04:10:22 +00:00
|
|
|
func NewClient(scheme string, insecure bool) *http.Client {
|
|
|
|
return httpClient(scheme, insecure)
|
2018-05-14 16:26:38 +00:00
|
|
|
}
|
2018-08-15 20:14:51 +00:00
|
|
|
|
2019-12-08 04:10:22 +00:00
|
|
|
// SpanTransport injects the http.RoundTripper.RoundTrip() request
|
|
|
|
// with a span.
|
|
|
|
type SpanTransport struct {
|
|
|
|
base http.RoundTripper
|
2018-08-15 20:14:51 +00:00
|
|
|
}
|
|
|
|
|
2019-12-08 04:10:22 +00:00
|
|
|
// RoundTrip implements the http.RoundTripper, intercepting the base
|
|
|
|
// round trippers call and injecting a span.
|
|
|
|
func (s *SpanTransport) RoundTrip(r *http.Request) (*http.Response, error) {
|
2019-04-11 02:28:21 +00:00
|
|
|
span, _ := tracing.StartSpanFromContext(r.Context())
|
2019-06-26 05:48:15 +00:00
|
|
|
defer span.Finish()
|
2019-04-11 02:28:21 +00:00
|
|
|
tracing.InjectToHTTPRequest(span, r)
|
2019-12-08 04:10:22 +00:00
|
|
|
return s.base.RoundTrip(r)
|
|
|
|
}
|
|
|
|
|
2020-06-05 16:52:45 +00:00
|
|
|
// DefaultTransport wraps http.DefaultTransport in SpanTransport to inject
|
|
|
|
// tracing headers into all outgoing requests.
|
|
|
|
var DefaultTransport http.RoundTripper = &SpanTransport{base: http.DefaultTransport}
|
|
|
|
|
|
|
|
// DefaultTransportInsecure is identical to DefaultTransport, with
|
|
|
|
// the exception that tls.Config is configured with InsecureSkipVerify
|
|
|
|
// set to true.
|
|
|
|
var DefaultTransportInsecure http.RoundTripper = &SpanTransport{
|
|
|
|
base: &http.Transport{
|
2019-12-08 04:10:22 +00:00
|
|
|
Proxy: http.ProxyFromEnvironment,
|
|
|
|
DialContext: (&net.Dialer{
|
|
|
|
Timeout: 30 * time.Second,
|
|
|
|
KeepAlive: 30 * time.Second,
|
|
|
|
DualStack: true,
|
|
|
|
}).DialContext,
|
2020-06-05 16:52:45 +00:00
|
|
|
ForceAttemptHTTP2: true,
|
2019-12-08 04:10:22 +00:00
|
|
|
MaxIdleConns: 100,
|
|
|
|
IdleConnTimeout: 90 * time.Second,
|
|
|
|
TLSHandshakeTimeout: 10 * time.Second,
|
|
|
|
ExpectContinueTimeout: 1 * time.Second,
|
2020-06-05 16:52:45 +00:00
|
|
|
TLSClientConfig: &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
2019-12-08 04:10:22 +00:00
|
|
|
},
|
2020-06-05 16:52:45 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func httpClient(scheme string, insecure bool) *http.Client {
|
|
|
|
if scheme == "https" && insecure {
|
|
|
|
return &http.Client{Transport: DefaultTransportInsecure}
|
2019-12-07 18:54:03 +00:00
|
|
|
}
|
2020-06-05 16:52:45 +00:00
|
|
|
return &http.Client{Transport: DefaultTransport}
|
2019-12-07 00:45:49 +00:00
|
|
|
}
|