From e806c2a0c544c5802dc46c7b72c08265ecaf6403 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Wed, 10 Nov 2021 15:31:39 +0800 Subject: [PATCH 01/10] amtool to support BearerToken to access alertmanager Signed-off-by: clyang82 --- cli/root.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cli/root.go b/cli/root.go index d987b9b628..163e588672 100644 --- a/cli/root.go +++ b/cli/root.go @@ -41,6 +41,7 @@ var ( output string timeout time.Duration tlsConfig *tls.Config + bearerToken string versionCheck bool configFiles = []string{os.ExpandEnv("$HOME/.config/amtool/config.yml"), "/etc/amtool/config.yml"} @@ -94,6 +95,10 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { cr.DefaultAuthentication = clientruntime.BasicAuth(amURL.User.Username(), password) } + if bearerToken != "" { + cr.DefaultAuthentication = clientruntime.BearerToken(bearerToken) + } + c := client.New(cr, strfmt.Default) if !versionCheck { @@ -131,6 +136,7 @@ func Execute() { app.Flag("tls.cafile", "TLS trusted certificate authorities file").PlaceHolder("").ExistingFileVar(&tls.CAFile) app.Flag("tls.servername", "ServerName to verify hostname of alertmanager").PlaceHolder("").StringVar(&tls.ServerName) app.Flag("tls.insecure.skip.verify", "Skip TLS certificate verification").Default("false").BoolVar(&tls.InsecureSkipVerify) + app.Flag("bearer-token", "A Bearer Token to access Alertmanager.").StringVar(&bearerToken) app.Flag("version-check", "Check alertmanager version. Use --no-version-check to disable.").Default("true").BoolVar(&versionCheck) app.Version(version.Print("amtool")) From d2d3295063560e035f43f39e1ea7964d713e2868 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Wed, 10 Nov 2021 17:14:47 +0800 Subject: [PATCH 02/10] check multiple authentication mechanisms Signed-off-by: clyang82 --- cli/root.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cli/root.go b/cli/root.go index 163e588672..8d3b179df1 100644 --- a/cli/root.go +++ b/cli/root.go @@ -90,6 +90,10 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { TLSClientConfig: tlsConfig, } + if amURL.User != nil && bearerToken != "" { + kingpin.Fatalf("could not specify multiple authentication mechanisms.") + } + if amURL.User != nil { password, _ := amURL.User.Password() cr.DefaultAuthentication = clientruntime.BasicAuth(amURL.User.Username(), password) From 8dee43654d27ee8d281f596c9e33d97b643e03bc Mon Sep 17 00:00:00 2001 From: Chunlin Yang Date: Thu, 11 Nov 2021 09:12:03 +0800 Subject: [PATCH 03/10] Update cli/root.go Co-authored-by: Julien Pivotto Signed-off-by: clyang82 --- cli/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/root.go b/cli/root.go index 8d3b179df1..2fe579fca4 100644 --- a/cli/root.go +++ b/cli/root.go @@ -91,7 +91,7 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { } if amURL.User != nil && bearerToken != "" { - kingpin.Fatalf("could not specify multiple authentication mechanisms.") + kingpin.Fatalf("basic authentication and bearer token are mutually exclusive") } if amURL.User != nil { From 35cbac83c9f8457df184053a797f201dff3cd446 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Wed, 8 Dec 2021 13:55:06 +0800 Subject: [PATCH 04/10] Support http_config for amtool Signed-off-by: clyang82 --- cli/config/http_config.go | 78 +++++++++++++++++ cli/config/http_config_test.go | 86 +++++++++++++++++++ cli/config/testdata/bearer.token | 1 + cli/config/testdata/http_config.bad.yml | 2 + .../testdata/http_config.basic_auth.good.yml | 3 + .../http_config.bearer-token-file.good.yml | 4 + cli/config/testdata/http_config.good.yml | 4 + cli/root.go | 75 ++++++++-------- 8 files changed, 214 insertions(+), 39 deletions(-) create mode 100644 cli/config/http_config.go create mode 100644 cli/config/http_config_test.go create mode 100644 cli/config/testdata/bearer.token create mode 100644 cli/config/testdata/http_config.bad.yml create mode 100644 cli/config/testdata/http_config.basic_auth.good.yml create mode 100644 cli/config/testdata/http_config.bearer-token-file.good.yml create mode 100644 cli/config/testdata/http_config.good.yml diff --git a/cli/config/http_config.go b/cli/config/http_config.go new file mode 100644 index 0000000000..6d3fff6dfb --- /dev/null +++ b/cli/config/http_config.go @@ -0,0 +1,78 @@ +// Copyright 2021 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "io/ioutil" + "os" + + promconfig "github.com/prometheus/common/config" + "gopkg.in/yaml.v2" +) + +// LoadHttpConfig returns HTTPClientConfig for the given http_config file +func LoadHttpConfig(httpConfigFile string) (*promconfig.HTTPClientConfig, error) { + if _, err := os.Stat(httpConfigFile); err != nil { + return nil, err + } + b, err := ioutil.ReadFile(httpConfigFile) + if err != nil { + return nil, err + } + + httpConfig := &promconfig.HTTPClientConfig{} + err = yaml.UnmarshalStrict(b, httpConfig) + if err != nil { + return nil, err + } + return httpConfig, nil +} + +// FetchBearerToken returns bearerToken for the given authorization which type is bearer +func FetchBearerToken(auth *promconfig.Authorization) (string, error) { + + if auth.Credentials != "" { + return string(auth.Credentials), nil + } + + if auth.CredentialsFile != "" { + if _, err := os.Stat(auth.CredentialsFile); err != nil { + return "", err + } + b, err := ioutil.ReadFile(auth.CredentialsFile) + if err != nil { + return "", err + } + return string(b), nil + } + return "", nil +} + +// FetchBasicAuthPassword returns password for the basic auth +func FetchBasicAuthPassword(auth *promconfig.BasicAuth) (string, error) { + + if auth.PasswordFile != "" { + if _, err := os.Stat(auth.PasswordFile); err != nil { + return "", err + } + b, err := ioutil.ReadFile(auth.PasswordFile) + if err != nil { + return "", err + } + return string(b), nil + } else if auth.Password != "" { + return string(auth.Password), nil + } + return "", nil +} diff --git a/cli/config/http_config_test.go b/cli/config/http_config_test.go new file mode 100644 index 0000000000..a722e33a6e --- /dev/null +++ b/cli/config/http_config_test.go @@ -0,0 +1,86 @@ +// Copyright 2021 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "strings" + "testing" +) + +const ( + AuthorizationCredentials = "theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo" +) + +func TestInvalidHttpConfig(t *testing.T) { + _, err := LoadHttpConfig("testdata/http_config.bad.yml") + errMsg := `authorization type cannot be set to "basic", use "basic_auth" instead` + if !strings.Contains(err.Error(), errMsg) { + t.Errorf("Expected error for invalid HTTP client configuration to contain %q but got: %s", errMsg, err) + } +} +func TestValidHttpConfig(t *testing.T) { + + cfg, err := LoadHttpConfig("testdata/http_config.good.yml") + if err != nil { + t.Fatalf("Error loading HTTP client config: %v", err) + } + + proxyURL := "http://remote.host" + if cfg.ProxyURL.String() != proxyURL { + t.Fatalf("Expected proxy_url is %q but got: %s", proxyURL, cfg.ProxyURL.String()) + } + + bearerToken, err := FetchBearerToken(cfg.Authorization) + if err != nil { + t.Fatalf("failed to fetch bearer token: %v", err) + } + + if bearerToken != AuthorizationCredentials { + t.Fatalf("Expected bearer token is %q but got: %s", AuthorizationCredentials, bearerToken) + } +} + +func TestValidBearerTokenFileHttpConfig(t *testing.T) { + + cfg, err := LoadHttpConfig("testdata/http_config.bearer-token-file.good.yml") + if err != nil { + t.Fatalf("Error loading HTTP client config: %v", err) + } + + bearerToken, err := FetchBearerToken(cfg.Authorization) + if err != nil { + t.Fatalf("failed to fetch bearer token: %v", err) + } + + if bearerToken != AuthorizationCredentials { + t.Fatalf("Expected bearer token is %q but got: %s", AuthorizationCredentials, bearerToken) + } +} + +func TestFetchBasicAuthPassword(t *testing.T) { + + cfg, err := LoadHttpConfig("testdata/http_config.basic_auth.good.yml") + if err != nil { + t.Fatalf("Error loading HTTP client config: %v", err) + } + + if cfg.BasicAuth.Username != "user" { + t.Fatalf("Expected username is %q but got: %s", "user", cfg.BasicAuth.Username) + } + + password, _ := FetchBasicAuthPassword(cfg.BasicAuth) + if password != "password" { + t.Fatalf("Expected password is %q but got: %s", "password", password) + } +} diff --git a/cli/config/testdata/bearer.token b/cli/config/testdata/bearer.token new file mode 100644 index 0000000000..24051f03db --- /dev/null +++ b/cli/config/testdata/bearer.token @@ -0,0 +1 @@ +theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo \ No newline at end of file diff --git a/cli/config/testdata/http_config.bad.yml b/cli/config/testdata/http_config.bad.yml new file mode 100644 index 0000000000..1f1f326686 --- /dev/null +++ b/cli/config/testdata/http_config.bad.yml @@ -0,0 +1,2 @@ +authorization: + type: Basic diff --git a/cli/config/testdata/http_config.basic_auth.good.yml b/cli/config/testdata/http_config.basic_auth.good.yml new file mode 100644 index 0000000000..ee0215a9be --- /dev/null +++ b/cli/config/testdata/http_config.basic_auth.good.yml @@ -0,0 +1,3 @@ +basic_auth: + username: user + password: password \ No newline at end of file diff --git a/cli/config/testdata/http_config.bearer-token-file.good.yml b/cli/config/testdata/http_config.bearer-token-file.good.yml new file mode 100644 index 0000000000..863505e36f --- /dev/null +++ b/cli/config/testdata/http_config.bearer-token-file.good.yml @@ -0,0 +1,4 @@ +authorization: + type: Bearer + credentials_file: testdata/bearer.token +proxy_url: "http://remote.host" diff --git a/cli/config/testdata/http_config.good.yml b/cli/config/testdata/http_config.good.yml new file mode 100644 index 0000000000..21583ef1d5 --- /dev/null +++ b/cli/config/testdata/http_config.good.yml @@ -0,0 +1,4 @@ +authorization: + type: Bearer + credentials: theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo +proxy_url: "http://remote.host" diff --git a/cli/root.go b/cli/root.go index 2fe579fca4..342cc8fa4b 100644 --- a/cli/root.go +++ b/cli/root.go @@ -14,7 +14,6 @@ package cli import ( - "crypto/tls" "fmt" "net/http" "net/url" @@ -40,8 +39,7 @@ var ( alertmanagerURL *url.URL output string timeout time.Duration - tlsConfig *tls.Config - bearerToken string + httpConfigFile string versionCheck bool configFiles = []string{os.ExpandEnv("$HOME/.config/amtool/config.yml"), "/etc/amtool/config.yml"} @@ -86,12 +84,8 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { cr := clientruntime.New(address, path.Join(amURL.Path, defaultAmApiv2path), schemes) - cr.Transport = &http.Transport{ - TLSClientConfig: tlsConfig, - } - - if amURL.User != nil && bearerToken != "" { - kingpin.Fatalf("basic authentication and bearer token are mutually exclusive") + if amURL.User != nil && httpConfigFile != "" { + kingpin.Fatalf("basic authentication and http.config.file are mutually exclusive") } if amURL.User != nil { @@ -99,8 +93,35 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { cr.DefaultAuthentication = clientruntime.BasicAuth(amURL.User.Username(), password) } - if bearerToken != "" { - cr.DefaultAuthentication = clientruntime.BearerToken(bearerToken) + var httpConfig *promconfig.HTTPClientConfig + if httpConfigFile != "" { + var err error + httpConfig, err = config.LoadHttpConfig(httpConfigFile) + if err != nil { + kingpin.Fatalf("could not load http config file: %v\n", err) + } + + tlsConfig, err := promconfig.NewTLSConfig(&httpConfig.TLSConfig) + if err != nil { + kingpin.Fatalf("failed to create tls config: %v\n", err) + } + + cr.Transport = &http.Transport{ + TLSClientConfig: tlsConfig, + } + + if httpConfig.BasicAuth != nil { + password, _ := config.FetchBasicAuthPassword(httpConfig.BasicAuth) + cr.DefaultAuthentication = clientruntime.BasicAuth(httpConfig.BasicAuth.Username, password) + } + + if httpConfig.Authorization.Type == "Bearer" { + bearerToken, err := config.FetchBearerToken(httpConfig.Authorization) + if err != nil { + kingpin.Fatalf("failed to fetch bearer token: %v\n", err) + } + cr.DefaultAuthentication = clientruntime.BearerToken(bearerToken) + } } c := client.New(cr, strfmt.Default) @@ -126,7 +147,6 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { func Execute() { var ( app = kingpin.New("amtool", helpRoot).UsageWriter(os.Stdout) - tls = promconfig.TLSConfig{} ) format.InitFormatFlags(app) @@ -135,21 +155,12 @@ func Execute() { app.Flag("alertmanager.url", "Alertmanager to talk to").URLVar(&alertmanagerURL) app.Flag("output", "Output formatter (simple, extended, json)").Short('o').Default("simple").EnumVar(&output, "simple", "extended", "json") app.Flag("timeout", "Timeout for the executed command").Default("30s").DurationVar(&timeout) - app.Flag("tls.certfile", "TLS client certificate file").PlaceHolder("").ExistingFileVar(&tls.CertFile) - app.Flag("tls.keyfile", "TLS client private key file").PlaceHolder("").ExistingFileVar(&tls.KeyFile) - app.Flag("tls.cafile", "TLS trusted certificate authorities file").PlaceHolder("").ExistingFileVar(&tls.CAFile) - app.Flag("tls.servername", "ServerName to verify hostname of alertmanager").PlaceHolder("").StringVar(&tls.ServerName) - app.Flag("tls.insecure.skip.verify", "Skip TLS certificate verification").Default("false").BoolVar(&tls.InsecureSkipVerify) - app.Flag("bearer-token", "A Bearer Token to access Alertmanager.").StringVar(&bearerToken) + app.Flag("http.config.file", "The http config file for amtool is to connect with the alertmanager.").PlaceHolder("").ExistingFileVar(&httpConfigFile) app.Flag("version-check", "Check alertmanager version. Use --no-version-check to disable.").Default("true").BoolVar(&versionCheck) app.Version(version.Print("amtool")) app.GetFlag("help").Short('h') app.UsageTemplate(kingpin.CompactUsageTemplate) - app.PreAction(func(pc *kingpin.ParseContext) (err error) { - tlsConfig, err = promconfig.NewTLSConfig(&tls) - return err - }) resolver, err := config.NewResolver(configFiles, legacyFlags) if err != nil { @@ -201,22 +212,8 @@ static configuration: date.format Sets the output format for dates. Defaults to "2006-01-02 15:04:05 MST" - tls.certfile - TLS client certificate file for mutual-TLS authentication. - Requires tls.keyfile to be useful. - - tls.keyfile - TLS client private key file for mutual-TLS authentication. - Requires tls.certfile to be useful. - - tls.cafile - TLS trusted certificate authorities file. - - tls.servername - ServerName to verify hostname of alertmanager. - - tls.insecure.skip.verify - Skips TLS certificate verification for all HTTPS requests. - Defaults to false. + http.config.file + Set a http_config file for amtool is to connect with the alertmanager. + The format is https://prometheus.io/docs/alerting/latest/configuration/#http_config. ` ) From 7cac620e775a42aabf553a02ae2a825ff9b7d821 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Tue, 21 Dec 2021 14:00:39 +0800 Subject: [PATCH 05/10] Address review comments Signed-off-by: clyang82 --- cli/config/http_config.go | 4 ++-- cli/config/http_config_test.go | 14 +++++++------- cli/root.go | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cli/config/http_config.go b/cli/config/http_config.go index 6d3fff6dfb..81557898ba 100644 --- a/cli/config/http_config.go +++ b/cli/config/http_config.go @@ -21,8 +21,8 @@ import ( "gopkg.in/yaml.v2" ) -// LoadHttpConfig returns HTTPClientConfig for the given http_config file -func LoadHttpConfig(httpConfigFile string) (*promconfig.HTTPClientConfig, error) { +// LoadHTTPConfig returns HTTPClientConfig for the given http_config file +func LoadHTTPConfig(httpConfigFile string) (*promconfig.HTTPClientConfig, error) { if _, err := os.Stat(httpConfigFile); err != nil { return nil, err } diff --git a/cli/config/http_config_test.go b/cli/config/http_config_test.go index a722e33a6e..2957a4736e 100644 --- a/cli/config/http_config_test.go +++ b/cli/config/http_config_test.go @@ -22,16 +22,16 @@ const ( AuthorizationCredentials = "theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo" ) -func TestInvalidHttpConfig(t *testing.T) { - _, err := LoadHttpConfig("testdata/http_config.bad.yml") +func TestInvalidHTTPConfig(t *testing.T) { + _, err := LoadHTTPConfig("testdata/http_config.bad.yml") errMsg := `authorization type cannot be set to "basic", use "basic_auth" instead` if !strings.Contains(err.Error(), errMsg) { t.Errorf("Expected error for invalid HTTP client configuration to contain %q but got: %s", errMsg, err) } } -func TestValidHttpConfig(t *testing.T) { +func TestValidHTTPConfig(t *testing.T) { - cfg, err := LoadHttpConfig("testdata/http_config.good.yml") + cfg, err := LoadHTTPConfig("testdata/http_config.good.yml") if err != nil { t.Fatalf("Error loading HTTP client config: %v", err) } @@ -51,9 +51,9 @@ func TestValidHttpConfig(t *testing.T) { } } -func TestValidBearerTokenFileHttpConfig(t *testing.T) { +func TestValidBearerTokenFileHTTPConfig(t *testing.T) { - cfg, err := LoadHttpConfig("testdata/http_config.bearer-token-file.good.yml") + cfg, err := LoadHTTPConfig("testdata/http_config.bearer-token-file.good.yml") if err != nil { t.Fatalf("Error loading HTTP client config: %v", err) } @@ -70,7 +70,7 @@ func TestValidBearerTokenFileHttpConfig(t *testing.T) { func TestFetchBasicAuthPassword(t *testing.T) { - cfg, err := LoadHttpConfig("testdata/http_config.basic_auth.good.yml") + cfg, err := LoadHTTPConfig("testdata/http_config.basic_auth.good.yml") if err != nil { t.Fatalf("Error loading HTTP client config: %v", err) } diff --git a/cli/root.go b/cli/root.go index 342cc8fa4b..62e4dea01d 100644 --- a/cli/root.go +++ b/cli/root.go @@ -96,14 +96,14 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { var httpConfig *promconfig.HTTPClientConfig if httpConfigFile != "" { var err error - httpConfig, err = config.LoadHttpConfig(httpConfigFile) + httpConfig, err = config.LoadHTTPConfig(httpConfigFile) if err != nil { - kingpin.Fatalf("could not load http config file: %v\n", err) + kingpin.Fatalf("could not load HTTP config file: %v\n", err) } tlsConfig, err := promconfig.NewTLSConfig(&httpConfig.TLSConfig) if err != nil { - kingpin.Fatalf("failed to create tls config: %v\n", err) + kingpin.Fatalf("failed to create TLS config: %v\n", err) } cr.Transport = &http.Transport{ @@ -155,7 +155,7 @@ func Execute() { app.Flag("alertmanager.url", "Alertmanager to talk to").URLVar(&alertmanagerURL) app.Flag("output", "Output formatter (simple, extended, json)").Short('o').Default("simple").EnumVar(&output, "simple", "extended", "json") app.Flag("timeout", "Timeout for the executed command").Default("30s").DurationVar(&timeout) - app.Flag("http.config.file", "The http config file for amtool is to connect with the alertmanager.").PlaceHolder("").ExistingFileVar(&httpConfigFile) + app.Flag("http.config.file", "HTTP client configuration file for amtool to connect to Alertmanager.").PlaceHolder("").ExistingFileVar(&httpConfigFile) app.Flag("version-check", "Check alertmanager version. Use --no-version-check to disable.").Default("true").BoolVar(&versionCheck) app.Version(version.Print("amtool")) @@ -213,7 +213,7 @@ static configuration: Sets the output format for dates. Defaults to "2006-01-02 15:04:05 MST" http.config.file - Set a http_config file for amtool is to connect with the alertmanager. + HTTP client configuration file for amtool to connect to Alertmanager. The format is https://prometheus.io/docs/alerting/latest/configuration/#http_config. ` ) From eabd9c45e347ffeeca86acd60ac690fff4a08a0c Mon Sep 17 00:00:00 2001 From: clyang82 Date: Thu, 23 Dec 2021 22:27:55 +0800 Subject: [PATCH 06/10] Use promconfig.NewClientFromConfig Signed-off-by: clyang82 --- cli/config/http_config.go | 38 ------------------- cli/config/http_config_test.go | 30 +-------------- cli/config/testdata/bearer.token | 1 - .../testdata/http_config.basic_auth.good.yml | 2 +- .../http_config.bearer-token-file.good.yml | 4 -- cli/root.go | 23 ++--------- 6 files changed, 6 insertions(+), 92 deletions(-) delete mode 100644 cli/config/testdata/bearer.token delete mode 100644 cli/config/testdata/http_config.bearer-token-file.good.yml diff --git a/cli/config/http_config.go b/cli/config/http_config.go index 81557898ba..4ac7eb81ee 100644 --- a/cli/config/http_config.go +++ b/cli/config/http_config.go @@ -38,41 +38,3 @@ func LoadHTTPConfig(httpConfigFile string) (*promconfig.HTTPClientConfig, error) } return httpConfig, nil } - -// FetchBearerToken returns bearerToken for the given authorization which type is bearer -func FetchBearerToken(auth *promconfig.Authorization) (string, error) { - - if auth.Credentials != "" { - return string(auth.Credentials), nil - } - - if auth.CredentialsFile != "" { - if _, err := os.Stat(auth.CredentialsFile); err != nil { - return "", err - } - b, err := ioutil.ReadFile(auth.CredentialsFile) - if err != nil { - return "", err - } - return string(b), nil - } - return "", nil -} - -// FetchBasicAuthPassword returns password for the basic auth -func FetchBasicAuthPassword(auth *promconfig.BasicAuth) (string, error) { - - if auth.PasswordFile != "" { - if _, err := os.Stat(auth.PasswordFile); err != nil { - return "", err - } - b, err := ioutil.ReadFile(auth.PasswordFile) - if err != nil { - return "", err - } - return string(b), nil - } else if auth.Password != "" { - return string(auth.Password), nil - } - return "", nil -} diff --git a/cli/config/http_config_test.go b/cli/config/http_config_test.go index 2957a4736e..b3c792fd15 100644 --- a/cli/config/http_config_test.go +++ b/cli/config/http_config_test.go @@ -40,35 +40,9 @@ func TestValidHTTPConfig(t *testing.T) { if cfg.ProxyURL.String() != proxyURL { t.Fatalf("Expected proxy_url is %q but got: %s", proxyURL, cfg.ProxyURL.String()) } - - bearerToken, err := FetchBearerToken(cfg.Authorization) - if err != nil { - t.Fatalf("failed to fetch bearer token: %v", err) - } - - if bearerToken != AuthorizationCredentials { - t.Fatalf("Expected bearer token is %q but got: %s", AuthorizationCredentials, bearerToken) - } -} - -func TestValidBearerTokenFileHTTPConfig(t *testing.T) { - - cfg, err := LoadHTTPConfig("testdata/http_config.bearer-token-file.good.yml") - if err != nil { - t.Fatalf("Error loading HTTP client config: %v", err) - } - - bearerToken, err := FetchBearerToken(cfg.Authorization) - if err != nil { - t.Fatalf("failed to fetch bearer token: %v", err) - } - - if bearerToken != AuthorizationCredentials { - t.Fatalf("Expected bearer token is %q but got: %s", AuthorizationCredentials, bearerToken) - } } -func TestFetchBasicAuthPassword(t *testing.T) { +func TestValidBasicAuthHTTPConfig(t *testing.T) { cfg, err := LoadHTTPConfig("testdata/http_config.basic_auth.good.yml") if err != nil { @@ -79,7 +53,7 @@ func TestFetchBasicAuthPassword(t *testing.T) { t.Fatalf("Expected username is %q but got: %s", "user", cfg.BasicAuth.Username) } - password, _ := FetchBasicAuthPassword(cfg.BasicAuth) + password := string(cfg.BasicAuth.Password) if password != "password" { t.Fatalf("Expected password is %q but got: %s", "password", password) } diff --git a/cli/config/testdata/bearer.token b/cli/config/testdata/bearer.token deleted file mode 100644 index 24051f03db..0000000000 --- a/cli/config/testdata/bearer.token +++ /dev/null @@ -1 +0,0 @@ -theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo \ No newline at end of file diff --git a/cli/config/testdata/http_config.basic_auth.good.yml b/cli/config/testdata/http_config.basic_auth.good.yml index ee0215a9be..cb3ba6a9e5 100644 --- a/cli/config/testdata/http_config.basic_auth.good.yml +++ b/cli/config/testdata/http_config.basic_auth.good.yml @@ -1,3 +1,3 @@ basic_auth: username: user - password: password \ No newline at end of file + password: password diff --git a/cli/config/testdata/http_config.bearer-token-file.good.yml b/cli/config/testdata/http_config.bearer-token-file.good.yml deleted file mode 100644 index 863505e36f..0000000000 --- a/cli/config/testdata/http_config.bearer-token-file.good.yml +++ /dev/null @@ -1,4 +0,0 @@ -authorization: - type: Bearer - credentials_file: testdata/bearer.token -proxy_url: "http://remote.host" diff --git a/cli/root.go b/cli/root.go index 62e4dea01d..0cd9f45e6c 100644 --- a/cli/root.go +++ b/cli/root.go @@ -15,7 +15,6 @@ package cli import ( "fmt" - "net/http" "net/url" "os" "path" @@ -101,27 +100,11 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { kingpin.Fatalf("could not load HTTP config file: %v\n", err) } - tlsConfig, err := promconfig.NewTLSConfig(&httpConfig.TLSConfig) + httpclient, err := promconfig.NewClientFromConfig(*httpConfig, "amtool") if err != nil { - kingpin.Fatalf("failed to create TLS config: %v\n", err) - } - - cr.Transport = &http.Transport{ - TLSClientConfig: tlsConfig, - } - - if httpConfig.BasicAuth != nil { - password, _ := config.FetchBasicAuthPassword(httpConfig.BasicAuth) - cr.DefaultAuthentication = clientruntime.BasicAuth(httpConfig.BasicAuth.Username, password) - } - - if httpConfig.Authorization.Type == "Bearer" { - bearerToken, err := config.FetchBearerToken(httpConfig.Authorization) - if err != nil { - kingpin.Fatalf("failed to fetch bearer token: %v\n", err) - } - cr.DefaultAuthentication = clientruntime.BearerToken(bearerToken) + kingpin.Fatalf("could not create a new HTTP client: %v\n", err) } + cr = clientruntime.NewWithClient(address, path.Join(amURL.Path, defaultAmApiv2path), schemes, httpclient) } c := client.New(cr, strfmt.Default) From 9d105f60dacfee87a556035b575b63dd2cccab95 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Thu, 6 Jan 2022 11:42:28 +0800 Subject: [PATCH 07/10] Address comments Signed-off-by: clyang82 --- cli/config/http_config.go | 10 +++------- cli/config/http_config_test.go | 13 ++++--------- cli/root.go | 7 +++---- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/cli/config/http_config.go b/cli/config/http_config.go index 4ac7eb81ee..6ebc03215a 100644 --- a/cli/config/http_config.go +++ b/cli/config/http_config.go @@ -15,18 +15,14 @@ package config import ( "io/ioutil" - "os" promconfig "github.com/prometheus/common/config" "gopkg.in/yaml.v2" ) -// LoadHTTPConfig returns HTTPClientConfig for the given http_config file -func LoadHTTPConfig(httpConfigFile string) (*promconfig.HTTPClientConfig, error) { - if _, err := os.Stat(httpConfigFile); err != nil { - return nil, err - } - b, err := ioutil.ReadFile(httpConfigFile) +// LoadHTTPConfigFile returns HTTPClientConfig for the given http_config file +func LoadHTTPConfigFile(filename string) (*promconfig.HTTPClientConfig, error) { + b, err := ioutil.ReadFile(filename) if err != nil { return nil, err } diff --git a/cli/config/http_config_test.go b/cli/config/http_config_test.go index b3c792fd15..d226525162 100644 --- a/cli/config/http_config_test.go +++ b/cli/config/http_config_test.go @@ -18,20 +18,16 @@ import ( "testing" ) -const ( - AuthorizationCredentials = "theanswertothegreatquestionoflifetheuniverseandeverythingisfortytwo" -) - func TestInvalidHTTPConfig(t *testing.T) { - _, err := LoadHTTPConfig("testdata/http_config.bad.yml") + _, err := LoadHTTPConfigFile("testdata/http_config.bad.yml") errMsg := `authorization type cannot be set to "basic", use "basic_auth" instead` if !strings.Contains(err.Error(), errMsg) { t.Errorf("Expected error for invalid HTTP client configuration to contain %q but got: %s", errMsg, err) } } -func TestValidHTTPConfig(t *testing.T) { - cfg, err := LoadHTTPConfig("testdata/http_config.good.yml") +func TestValidHTTPConfig(t *testing.T) { + cfg, err := LoadHTTPConfigFile("testdata/http_config.good.yml") if err != nil { t.Fatalf("Error loading HTTP client config: %v", err) } @@ -43,8 +39,7 @@ func TestValidHTTPConfig(t *testing.T) { } func TestValidBasicAuthHTTPConfig(t *testing.T) { - - cfg, err := LoadHTTPConfig("testdata/http_config.basic_auth.good.yml") + cfg, err := LoadHTTPConfigFile("testdata/http_config.basic_auth.good.yml") if err != nil { t.Fatalf("Error loading HTTP client config: %v", err) } diff --git a/cli/root.go b/cli/root.go index 0cd9f45e6c..dc9adf377f 100644 --- a/cli/root.go +++ b/cli/root.go @@ -92,17 +92,16 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { cr.DefaultAuthentication = clientruntime.BasicAuth(amURL.User.Username(), password) } - var httpConfig *promconfig.HTTPClientConfig if httpConfigFile != "" { var err error - httpConfig, err = config.LoadHTTPConfig(httpConfigFile) + httpConfig, err := config.LoadHTTPConfigFile(httpConfigFile) if err != nil { - kingpin.Fatalf("could not load HTTP config file: %v\n", err) + kingpin.Fatalf("failed to load HTTP config file: %v\n", err) } httpclient, err := promconfig.NewClientFromConfig(*httpConfig, "amtool") if err != nil { - kingpin.Fatalf("could not create a new HTTP client: %v\n", err) + kingpin.Fatalf("failed to create a new HTTP client: %v\n", err) } cr = clientruntime.NewWithClient(address, path.Join(amURL.Path, defaultAmApiv2path), schemes, httpclient) } From 0625f90e52dac076e3a2c1d1d68356d4b8b7e5d6 Mon Sep 17 00:00:00 2001 From: Chunlin Yang Date: Fri, 7 Jan 2022 18:46:39 +0800 Subject: [PATCH 08/10] Update cli/root.go Co-authored-by: Simon Pasquier Signed-off-by: clyang82 --- cli/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/root.go b/cli/root.go index dc9adf377f..64f8a00c1f 100644 --- a/cli/root.go +++ b/cli/root.go @@ -101,7 +101,7 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { httpclient, err := promconfig.NewClientFromConfig(*httpConfig, "amtool") if err != nil { - kingpin.Fatalf("failed to create a new HTTP client: %v\n", err) + kingpin.Fatalf("failed to create a new HTTP client: %v", err) } cr = clientruntime.NewWithClient(address, path.Join(amURL.Path, defaultAmApiv2path), schemes, httpclient) } From 0d2945d0f0e50014a54f2c38f6d13632d8ac46e6 Mon Sep 17 00:00:00 2001 From: clyang82 Date: Sat, 8 Jan 2022 10:03:25 +0800 Subject: [PATCH 09/10] address comments Signed-off-by: clyang82 --- cli/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/root.go b/cli/root.go index 64f8a00c1f..95b3510346 100644 --- a/cli/root.go +++ b/cli/root.go @@ -96,7 +96,7 @@ func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager { var err error httpConfig, err := config.LoadHTTPConfigFile(httpConfigFile) if err != nil { - kingpin.Fatalf("failed to load HTTP config file: %v\n", err) + kingpin.Fatalf("failed to load HTTP config file: %v", err) } httpclient, err := promconfig.NewClientFromConfig(*httpConfig, "amtool") From 4b62a7f9575992d3c2f244e3c07fefd624e4ff2d Mon Sep 17 00:00:00 2001 From: clyang82 Date: Tue, 11 Jan 2022 22:35:45 +0800 Subject: [PATCH 10/10] resolve relative paths Signed-off-by: clyang82 --- cli/config/http_config.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cli/config/http_config.go b/cli/config/http_config.go index 6ebc03215a..b94ab10158 100644 --- a/cli/config/http_config.go +++ b/cli/config/http_config.go @@ -15,6 +15,7 @@ package config import ( "io/ioutil" + "path/filepath" promconfig "github.com/prometheus/common/config" "gopkg.in/yaml.v2" @@ -32,5 +33,7 @@ func LoadHTTPConfigFile(filename string) (*promconfig.HTTPClientConfig, error) { if err != nil { return nil, err } + httpConfig.SetDirectory(filepath.Dir(filepath.Dir(filename))) + return httpConfig, nil }