mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-09 23:24:05 -08:00
Scaleway SD: Add the ability to read token from file
Prometheus adds the ability to read secrets from files. This add this feature for the scaleway service discovery. Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
This commit is contained in:
parent
9dceeea5e7
commit
5a6d244b00
|
@ -1136,6 +1136,18 @@ var expectedErrors = []struct {
|
|||
filename: "eureka_invalid_server.bad.yml",
|
||||
errMsg: "invalid eureka server URL",
|
||||
},
|
||||
{
|
||||
filename: "scaleway_role.bad.yml",
|
||||
errMsg: `unknown role "invalid"`,
|
||||
},
|
||||
{
|
||||
filename: "scaleway_no_secret.bad.yml",
|
||||
errMsg: "one of secret_key & secret_key_file must be configured",
|
||||
},
|
||||
{
|
||||
filename: "scaleway_two_secrets.bad.yml",
|
||||
errMsg: "at most one of secret_key & secret_key_file must be configured",
|
||||
},
|
||||
}
|
||||
|
||||
func TestBadConfigs(t *testing.T) {
|
||||
|
|
5
config/testdata/scaleway_no_secret.bad.yml
vendored
Normal file
5
config/testdata/scaleway_no_secret.bad.yml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
scrape_configs:
|
||||
- scaleway_sd_configs:
|
||||
- role: instance
|
||||
project_id: 11111111-1111-1111-1111-111111111112
|
||||
access_key: SCWXXXXXXXXXXXXXXXXX
|
5
config/testdata/scaleway_role.bad.yml
vendored
5
config/testdata/scaleway_role.bad.yml
vendored
|
@ -1,4 +1,7 @@
|
|||
scrape_configs:
|
||||
- scaleway_sd_configs:
|
||||
- role: invalid
|
||||
- role: invalid
|
||||
project_id: 11111111-1111-1111-1111-111111111112
|
||||
access_key: SCWXXXXXXXXXXXXXXXXX
|
||||
secret_key_file: bar
|
||||
|
||||
|
|
8
config/testdata/scaleway_two_secrets.bad.yml
vendored
Normal file
8
config/testdata/scaleway_two_secrets.bad.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
scrape_configs:
|
||||
- scaleway_sd_configs:
|
||||
- role: instance
|
||||
project_id: 11111111-1111-1111-1111-111111111112
|
||||
access_key: SCWXXXXXXXXXXXXXXXXX
|
||||
secret_key_file: bar
|
||||
secret_key: 11111111-1111-1111-1111-111111111112
|
||||
|
|
@ -75,10 +75,18 @@ func newBaremetalDiscovery(conf *SDConfig) (*baremetalDiscovery, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if conf.SecretKeyFile != "" {
|
||||
rt, err = newAuthTokenFileRoundTripper(conf.SecretKeyFile, rt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
profile, err := loadProfile(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.client, err = scw.NewClient(
|
||||
scw.WithHTTPClient(&http.Client{
|
||||
Transport: rt,
|
||||
|
|
|
@ -76,7 +76,7 @@ func newInstanceDiscovery(conf *SDConfig) (*instanceDiscovery, error) {
|
|||
zone: conf.Zone,
|
||||
project: conf.Project,
|
||||
accessKey: conf.AccessKey,
|
||||
secretKey: string(conf.SecretKey),
|
||||
secretKey: conf.secretKeyForConfig(),
|
||||
nameFilter: conf.NameFilter,
|
||||
tagsFilter: conf.TagsFilter,
|
||||
}
|
||||
|
@ -86,6 +86,13 @@ func newInstanceDiscovery(conf *SDConfig) (*instanceDiscovery, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if conf.SecretKeyFile != "" {
|
||||
rt, err = newAuthTokenFileRoundTripper(conf.SecretKeyFile, rt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
profile, err := loadProfile(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -27,9 +27,10 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
testProjectID = "8feda53f-15f0-447f-badf-ebe32dad2fc0"
|
||||
testSecretKey = "6d6579e5-a5b9-49fc-a35f-b4feb9b87301"
|
||||
testAccessKey = "SCW0W8NG6024YHRJ7723"
|
||||
testProjectID = "8feda53f-15f0-447f-badf-ebe32dad2fc0"
|
||||
testSecretKeyFile = "testdata/secret_key"
|
||||
testSecretKey = "6d6579e5-a5b9-49fc-a35f-b4feb9b87301"
|
||||
testAccessKey = "SCW0W8NG6024YHRJ7723"
|
||||
)
|
||||
|
||||
func TestScalewayInstanceRefresh(t *testing.T) {
|
||||
|
@ -137,3 +138,28 @@ func mockScalewayInstance(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalewayInstanceAuthToken(t *testing.T) {
|
||||
mock := httptest.NewServer(http.HandlerFunc(mockScalewayInstance))
|
||||
defer mock.Close()
|
||||
|
||||
cfgString := fmt.Sprintf(`
|
||||
---
|
||||
role: instance
|
||||
project_id: %s
|
||||
secret_key_file: %s
|
||||
access_key: %s
|
||||
api_url: %s
|
||||
`, testProjectID, testSecretKeyFile, testAccessKey, mock.URL)
|
||||
var cfg SDConfig
|
||||
require.NoError(t, yaml.UnmarshalStrict([]byte(cfgString), &cfg))
|
||||
|
||||
d, err := newRefresher(&cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
tgs, err := d.refresh(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(tgs))
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ package scaleway
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
|
@ -83,6 +86,8 @@ type SDConfig struct {
|
|||
AccessKey string `yaml:"access_key"`
|
||||
// SecretKey used to authenticate on Scaleway APIs.
|
||||
SecretKey config.Secret `yaml:"secret_key"`
|
||||
// SecretKey used to authenticate on Scaleway APIs.
|
||||
SecretKeyFile string `yaml:"secret_key_file"`
|
||||
// NameFilter to filter on during the ListServers.
|
||||
NameFilter string `yaml:"name_filter,omitempty"`
|
||||
// TagsFilter to filter on during the ListServers.
|
||||
|
@ -100,6 +105,15 @@ func (c SDConfig) Name() string {
|
|||
return "scaleway"
|
||||
}
|
||||
|
||||
// secretKeyForConfig returns a secret key that looks like a UUID, even if we
|
||||
// take the actuel secret from a file.
|
||||
func (c SDConfig) secretKeyForConfig() string {
|
||||
if c.SecretKeyFile != "" {
|
||||
return "00000000-0000-0000-0000-000000000000"
|
||||
}
|
||||
return string(c.SecretKey)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultSDConfig
|
||||
|
@ -117,8 +131,12 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
return errors.New("project_id is mandatory")
|
||||
}
|
||||
|
||||
if c.SecretKey == "" {
|
||||
return errors.New("secret_key is mandatory")
|
||||
if c.SecretKey == "" && c.SecretKeyFile == "" {
|
||||
return errors.New("one of secret_key & secret_key_file must be configured")
|
||||
}
|
||||
|
||||
if c.SecretKey != "" && c.SecretKeyFile != "" {
|
||||
return errors.New("at most one of secret_key & secret_key_file must be configured")
|
||||
}
|
||||
|
||||
if c.AccessKey == "" {
|
||||
|
@ -145,6 +163,7 @@ func (c SDConfig) NewDiscoverer(options discovery.DiscovererOptions) (discovery.
|
|||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *SDConfig) SetDirectory(dir string) {
|
||||
c.SecretKeyFile = config.JoinDir(dir, c.SecretKeyFile)
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
|
@ -190,7 +209,7 @@ func loadProfile(sdConfig *SDConfig) (*scw.Profile, error) {
|
|||
prometheusConfigProfile := &scw.Profile{
|
||||
DefaultZone: scw.StringPtr(sdConfig.Zone),
|
||||
APIURL: scw.StringPtr(sdConfig.APIURL),
|
||||
SecretKey: scw.StringPtr(string(sdConfig.SecretKey)),
|
||||
SecretKey: scw.StringPtr(sdConfig.secretKeyForConfig()),
|
||||
AccessKey: scw.StringPtr(sdConfig.AccessKey),
|
||||
DefaultProjectID: scw.StringPtr(sdConfig.Project),
|
||||
SendTelemetry: scw.BoolPtr(false),
|
||||
|
@ -198,3 +217,29 @@ func loadProfile(sdConfig *SDConfig) (*scw.Profile, error) {
|
|||
|
||||
return prometheusConfigProfile, nil
|
||||
}
|
||||
|
||||
type authTokenFileRoundTripper struct {
|
||||
authTokenFile string
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
// newAuthTokenFileRoundTripper adds the auth token read from the file to a request.
|
||||
func newAuthTokenFileRoundTripper(tokenFile string, rt http.RoundTripper) (http.RoundTripper, error) {
|
||||
// fail-fast if we can't read the file.
|
||||
_, err := ioutil.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to read auth token file %s", tokenFile)
|
||||
}
|
||||
return &authTokenFileRoundTripper{tokenFile, rt}, nil
|
||||
}
|
||||
|
||||
func (rt *authTokenFileRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
b, err := ioutil.ReadFile(rt.authTokenFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to read auth token file %s", rt.authTokenFile)
|
||||
}
|
||||
authToken := strings.TrimSpace(string(b))
|
||||
|
||||
request.Header.Set("X-Auth-Token", authToken)
|
||||
return rt.rt.RoundTrip(request)
|
||||
}
|
||||
|
|
1
discovery/scaleway/testdata/secret_key
vendored
Normal file
1
discovery/scaleway/testdata/secret_key
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
6d6579e5-a5b9-49fc-a35f-b4feb9b87301
|
|
@ -1589,7 +1589,12 @@ See below for the configuration options for Scaleway discovery:
|
|||
access_key: <string>
|
||||
|
||||
# Secret key to use when listing targets. https://console.scaleway.com/project/credentials
|
||||
secret_key: <secret>
|
||||
# It is mutually exclusive with `secret_key_file`.
|
||||
[ secret_key: <secret> ]
|
||||
|
||||
# Sets the secret key with the credentials read from the configured file.
|
||||
# It is mutually exclusive with `secret_key`.
|
||||
[ secret_key_file: <filename> ]
|
||||
|
||||
# Project ID of the targets.
|
||||
project_id: <string>
|
||||
|
|
Loading…
Reference in a new issue