Enable reading consul token from file (#8926)

* Adopted common http client

Signed-off-by: Levi Harrison <git@leviharrison.dev>
This commit is contained in:
Levi Harrison 2021-06-11 18:06:59 -04:00 committed by GitHub
parent 39dbcd8e3d
commit faed8df31d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 156 additions and 27 deletions

View file

@ -332,11 +332,14 @@ var expectedConf = &Config{
Scheme: "https",
RefreshInterval: consul.DefaultSDConfig.RefreshInterval,
AllowStale: true,
TLSConfig: config.TLSConfig{
CertFile: filepath.FromSlash("testdata/valid_cert_file"),
KeyFile: filepath.FromSlash("testdata/valid_key_file"),
CAFile: filepath.FromSlash("testdata/valid_ca_file"),
InsecureSkipVerify: false,
HTTPClientConfig: config.HTTPClientConfig{
TLSConfig: config.TLSConfig{
CertFile: filepath.FromSlash("testdata/valid_cert_file"),
KeyFile: filepath.FromSlash("testdata/valid_key_file"),
CAFile: filepath.FromSlash("testdata/valid_ca_file"),
InsecureSkipVerify: false,
},
FollowRedirects: true,
},
},
},

View file

@ -92,11 +92,12 @@ var (
// DefaultSDConfig is the default Consul SD configuration.
DefaultSDConfig = SDConfig{
TagSeparator: ",",
Scheme: "http",
Server: "localhost:8500",
AllowStale: true,
RefreshInterval: model.Duration(30 * time.Second),
TagSeparator: ",",
Scheme: "http",
Server: "localhost:8500",
AllowStale: true,
RefreshInterval: model.Duration(30 * time.Second),
HTTPClientConfig: config.DefaultHTTPClientConfig,
}
)
@ -134,7 +135,7 @@ type SDConfig struct {
// Desired node metadata.
NodeMeta map[string]string `yaml:"node_meta,omitempty"`
TLSConfig config.TLSConfig `yaml:"tls_config,omitempty"`
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
}
// Name returns the name of the Config.
@ -147,7 +148,7 @@ func (c *SDConfig) NewDiscoverer(opts discovery.DiscovererOptions) (discovery.Di
// SetDirectory joins any relative file paths with dir.
func (c *SDConfig) SetDirectory(dir string) {
c.TLSConfig.SetDirectory(dir)
c.HTTPClientConfig.SetDirectory(dir)
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
@ -161,7 +162,19 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
if strings.TrimSpace(c.Server) == "" {
return errors.New("consul SD configuration requires a server address")
}
return nil
if c.Username != "" || c.Password != "" {
if c.HTTPClientConfig.BasicAuth != nil {
return errors.New("at most one of consul SD configuration username and password and basic auth can be configured")
}
c.HTTPClientConfig.BasicAuth = &config.BasicAuth{
Username: c.Username,
Password: c.Password,
}
}
if c.Token != "" && (c.HTTPClientConfig.Authorization != nil || c.HTTPClientConfig.OAuth2 != nil) {
return errors.New("at most one of consul SD token, authorization, or oauth2 can be configured")
}
return c.HTTPClientConfig.Validate()
}
// Discovery retrieves target information from a Consul server
@ -186,13 +199,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
logger = log.NewNopLogger()
}
httpConfig := config.HTTPClientConfig{
TLSConfig: conf.TLSConfig,
FollowRedirects: true,
}
wrapper, err := config.NewClientFromConfig(httpConfig, "consul_sd", config.WithHTTP2Disabled(), config.WithIdleConnTimeout(2*time.Duration(watchTimeout)))
wrapper, err := config.NewClientFromConfig(conf.HTTPClientConfig, "consul_sd", config.WithHTTP2Disabled(), config.WithIdleConnTimeout(2*time.Duration(watchTimeout)))
if err != nil {
return nil, err
}
@ -204,10 +211,6 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
Datacenter: conf.Datacenter,
Namespace: conf.Namespace,
Token: string(conf.Token),
HttpAuth: &consul.HttpBasicAuth{
Username: conf.Username,
Password: string(conf.Password),
},
HttpClient: wrapper,
}
client, err := consul.NewClient(clientConf)

View file

@ -22,9 +22,11 @@ import (
"time"
"github.com/go-kit/log"
"github.com/prometheus/common/config"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"gopkg.in/yaml.v2"
"github.com/prometheus/prometheus/discovery/targetgroup"
)
@ -397,3 +399,90 @@ func TestGetDatacenterShouldReturnError(t *testing.T) {
require.Equal(t, "", d.clientDatacenter)
}
}
func TestUnmarshalConfig(t *testing.T) {
unmarshal := func(d []byte) func(interface{}) error {
return func(o interface{}) error {
return yaml.Unmarshal(d, o)
}
}
goodConfig := DefaultSDConfig
goodConfig.Username = "123"
goodConfig.Password = "1234"
goodConfig.HTTPClientConfig = config.HTTPClientConfig{
BasicAuth: &config.BasicAuth{
Username: "123",
Password: "1234",
},
FollowRedirects: true,
}
cases := []struct {
name string
config string
expected SDConfig
errMessage string
}{
{
name: "good",
config: `
server: localhost:8500
username: 123
password: 1234
`,
expected: goodConfig,
},
{
name: "username and password and basic auth configured",
config: `
server: localhost:8500
username: 123
password: 1234
basic_auth:
username: 12345
password: 123456
`,
errMessage: "at most one of consul SD configuration username and password and basic auth can be configured",
},
{
name: "token and authorization configured",
config: `
server: localhost:8500
token: 1234567
authorization:
credentials: 12345678
`,
errMessage: "at most one of consul SD token, authorization, or oauth2 can be configured",
},
{
name: "token and oauth2 configured",
config: `
server: localhost:8500
token: 1234567
oauth2:
client_id: 10
client_secret: 11
token_url: http://example.com
`,
errMessage: "at most one of consul SD token, authorization, or oauth2 can be configured",
},
}
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
var config SDConfig
err := config.UnmarshalYAML(unmarshal([]byte(test.config)))
if err != nil {
require.Equalf(t, err.Error(), test.errMessage, "Expected error '%s', got '%v'", test.errMessage, err)
return
}
if test.errMessage != "" {
t.Errorf("Expected error %s, got none", test.errMessage)
return
}
require.Equal(t, config, test.expected)
})
}
}

View file

@ -447,12 +447,10 @@ The following meta labels are available on targets during [relabeling](#relabel_
# Namespaces are only supported in Consul Enterprise.
[ namespace: <string> ]
[ scheme: <string> | default = "http" ]
# The username and password fields are deprecated in favor of the basic_auth configuration.
[ username: <string> ]
[ password: <secret> ]
tls_config:
[ <tls_config> ]
# A list of services for which targets are retrieved. If omitted, all services
# are scraped.
services:
@ -478,6 +476,42 @@ tags:
# The time after which the provided names are refreshed.
# On large setup it might be a good idea to increase this value because the catalog will change all the time.
[ refresh_interval: <duration> | default = 30s ]
# Authentication information used to authenticate to the consul server.
# Note that `basic_auth`, `authorization` and `oauth2` options are
# mutually exclusive.
# `password` and `password_file` are mutually exclusive.
# Optional HTTP basic authentication information.
basic_auth:
[ username: <string> ]
[ password: <secret> ]
[ password_file: <string> ]
# Optional `Authorization` header configuration.
authorization:
# Sets the authentication type.
[ type: <string> | default: Bearer ]
# Sets the credentials. It is mutually exclusive with
# `credentials_file`.
[ credentials: <secret> ]
# Sets the credentials to the credentials read from the configured file.
# It is mutually exclusive with `credentials`.
[ credentials_file: <filename> ]
# Optional OAuth 2.0 configuration.
oauth2:
[ <oauth2> ]
# Optional proxy URL.
[ proxy_url: <string> ]
# Configure whether HTTP requests follow HTTP 3xx redirects.
[ follow_redirects: <bool> | default = true ]
# TLS configuration.
tls_config:
[ <tls_config> ]
```
Note that the IP number and port used to scrape the targets is assembled as