Skip to content

Commit

Permalink
feat: support prometheus web_basic_auth
Browse files Browse the repository at this point in the history
  • Loading branch information
hzp committed Jan 13, 2025
1 parent f57aa1d commit 2184ffa
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 25 deletions.
2 changes: 2 additions & 0 deletions embed/examples/cluster/topology.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ monitoring_servers:
# port: 9090
# # ng-monitoring servive communication port
# ng_port: 12020
# #prometheus web basic_auth_password
# basic_auth_password: admin
# # Prometheus deployment file, startup script, configuration file storage directory.
# deploy_dir: "/tidb-deploy/prometheus-8249"
# # Prometheus data storage directory.
Expand Down
7 changes: 6 additions & 1 deletion embed/templates/config/datasource.yml.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ datasources:
tlsAuth: false
tlsAuthWithCACert: false
version: 1
editable: true
editable: true
{{- if .AuthPassword}}
basicAuth: true
basicAuthUser: admin
basicAuthPassword: {{.AuthPassword}}
{{- end}}
2 changes: 2 additions & 0 deletions embed/templates/config/web.config.yml.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
basic_auth_users:
admin: {{.BasicAuthPassword}}
3 changes: 3 additions & 0 deletions embed/templates/scripts/run_prometheus.sh.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ exec numactl --cpunodebind={{.NumaNode}} --membind={{.NumaNode}} bin/prometheus/
exec bin/prometheus/prometheus \
{{- end}}
--config.file="{{.DeployDir}}/conf/prometheus.yml" \
{{- if .BasicAuthPassword}}
--web.config.file="{{.DeployDir}}/conf/web.config.yml" \
{{- end}}
--web.listen-address=":{{.Port}}" \
--web.external-url="{{.WebExternalURL}}/" \
--web.enable-admin-api \
Expand Down
5 changes: 3 additions & 2 deletions pkg/cluster/spec/grafana.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,9 @@ func (i *GrafanaInstance) InitConfig(
}
fp = filepath.Join(paths.Cache, fmt.Sprintf("datasource_%s.yml", i.GetHost()))
datasourceCfg := &config.DatasourceConfig{
ClusterName: clusterName,
URL: fmt.Sprintf("http://%s", utils.JoinHostPort(monitors[0].Host, monitors[0].Port)),
ClusterName: clusterName,
URL: fmt.Sprintf("http://%s", utils.JoinHostPort(monitors[0].Host, monitors[0].Port)),
AuthPassword: monitors[0].BasicAuthPassword,
}
if err := datasourceCfg.ConfigToFile(fp); err != nil {
return err
Expand Down
17 changes: 17 additions & 0 deletions pkg/cluster/spec/monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type PrometheusSpec struct {
Patched bool `yaml:"patched,omitempty"`
IgnoreExporter bool `yaml:"ignore_exporter,omitempty"`
Port int `yaml:"port" default:"9090"`
BasicAuthPassword string `yaml:"basic_auth_password,omitempty"`
NgPort int `yaml:"ng_port,omitempty" validate:"ng_port:editable"` // ng_port is usable since v5.3.0 and default as 12020 since v5.4.0, so the default value is set in spec.go/AdjustByVersion
DeployDir string `yaml:"deploy_dir,omitempty"`
DataDir string `yaml:"data_dir,omitempty"`
Expand Down Expand Up @@ -172,9 +173,15 @@ func (c *MonitorComponent) Instances() []Instance {
s.DataDir,
},
StatusFn: func(_ context.Context, timeout time.Duration, _ *tls.Config, _ ...string) string {
if s.BasicAuthPassword != "" {
return statusByHostWithAuth(s.BasicAuthPassword, s.GetManageHost(), s.Port, "/-/ready", timeout, nil)
}
return statusByHost(s.GetManageHost(), s.Port, "/-/ready", timeout, nil)
},
UptimeFn: func(_ context.Context, timeout time.Duration, tlsCfg *tls.Config) time.Duration {
if s.BasicAuthPassword != "" {
return UptimeByHostWithAuth(s.BasicAuthPassword, s.GetManageHost(), s.Port, timeout, tlsCfg)
}
return UptimeByHost(s.GetManageHost(), s.Port, timeout, tlsCfg)
},
Component: c,
Expand Down Expand Up @@ -226,6 +233,16 @@ func (i *MonitorInstance) InitConfig(
AdditionalArgs: spec.AdditionalArgs,
}

// transfer web config
srcfp := filepath.Join(paths.Cache, fmt.Sprintf("web.config_%s_%d.yml", i.GetHost(), i.GetPort()))
if err := cfg.WebConfigToFile(srcfp); err != nil {
return err
}
dstfp := filepath.Join(paths.Deploy, "conf", "web.config.yml")
if err := e.Transfer(ctx, srcfp, dstfp, false, 0, false); err != nil {
return err
}

fp := filepath.Join(paths.Cache, fmt.Sprintf("run_prometheus_%s_%d.sh", i.GetHost(), i.GetPort()))
if err := cfg.ConfigToFile(fp); err != nil {
return err
Expand Down
54 changes: 38 additions & 16 deletions pkg/cluster/spec/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"crypto/tls"
"fmt"
"net/url"
"path/filepath"
"reflect"
"strings"
Expand Down Expand Up @@ -123,46 +124,56 @@ func LoadClientCert(dir string) (*tls.Config, error) {
}.ClientConfig()
}

// statusByHost queries current status of the instance by http status api.
func statusByHost(host string, port int, path string, timeout time.Duration, tlsCfg *tls.Config) string {
func getStatusByHost(uri string, timeout time.Duration, tlsCfg *tls.Config) string {
if timeout < time.Second {
timeout = statusQueryTimeout
}

client := utils.NewHTTPClient(timeout, tlsCfg)

scheme := "http"
if tlsCfg != nil {
scheme = "https"
}
if path == "" {
path = "/"
}
url := fmt.Sprintf("%s://%s%s", scheme, utils.JoinHostPort(host, port), path)

urlStr := fmt.Sprintf("%s://%s", scheme, uri)
client := utils.NewHTTPClient(timeout, tlsCfg)

// body doesn't have any status section needed
body, err := client.Get(context.TODO(), url)
body, err := client.Get(context.TODO(), urlStr)
if err != nil || body == nil {
return "Down"
}
return "Up"
}

// UptimeByHost queries current uptime of the instance by http Prometheus metric api.
func UptimeByHost(host string, port int, timeout time.Duration, tlsCfg *tls.Config) time.Duration {
// statusByHost queries current status of the instance by http status api.
func statusByHost(host string, port int, path string, timeout time.Duration, tlsCfg *tls.Config) string {
if path == "" {
path = "/"
}
uri := fmt.Sprintf("%s%s", utils.JoinHostPort(host, port), path)

return getStatusByHost(uri, timeout, tlsCfg)
}

func statusByHostWithAuth(authPassword string, host string, port int, path string, timeout time.Duration, tlsCfg *tls.Config) string {
if path == "" {
path = "/"
}
uri := fmt.Sprintf("admin:%s@%s%s", url.QueryEscape(authPassword), utils.JoinHostPort(host, port), path)
return getStatusByHost(uri, timeout, tlsCfg)
}

func getUptimeByHost(uri string, timeout time.Duration, tlsCfg *tls.Config) time.Duration {
if timeout < time.Second {
timeout = statusQueryTimeout
}

scheme := "http"
if tlsCfg != nil {
scheme = "https"
}
url := fmt.Sprintf("%s://%s/metrics", scheme, utils.JoinHostPort(host, port))

urlStr := fmt.Sprintf("%s://%s", scheme, uri)
client := utils.NewHTTPClient(timeout, tlsCfg)

body, err := client.Get(context.TODO(), url)
body, err := client.Get(context.TODO(), urlStr)
if err != nil || body == nil {
return 0
}
Expand All @@ -189,6 +200,17 @@ func UptimeByHost(host string, port int, timeout time.Duration, tlsCfg *tls.Conf
return 0
}

// UptimeByHost queries current uptime of the instance by http Prometheus metric api.
func UptimeByHost(host string, port int, timeout time.Duration, tlsCfg *tls.Config) time.Duration {
uri := fmt.Sprintf("%s/metrics", utils.JoinHostPort(host, port))
return getUptimeByHost(uri, timeout, tlsCfg)
}

func UptimeByHostWithAuth(authPassword string, host string, port int, timeout time.Duration, tlsCfg *tls.Config) time.Duration {
uri := fmt.Sprintf("admin:%s@%s/metrics", url.QueryEscape(authPassword), utils.JoinHostPort(host, port))
return getUptimeByHost(uri, timeout, tlsCfg)
}

// Abs returns the absolute path
func Abs(user, path string) string {
// trim whitespaces before joining
Expand Down
5 changes: 3 additions & 2 deletions pkg/cluster/template/config/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ import (

// DatasourceConfig represent the data to generate Datasource config
type DatasourceConfig struct {
ClusterName string
URL string
ClusterName string
URL string
AuthPassword string
}

// ConfigToFile write config content to specific path
Expand Down
38 changes: 34 additions & 4 deletions pkg/cluster/template/scripts/monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,22 @@ package scripts

import (
"bytes"
"os"
"path"
"text/template"

"github.com/pingcap/tiup/embed"
"github.com/pingcap/tiup/pkg/utils"
"golang.org/x/crypto/bcrypt"
)

// PrometheusScript represent the data to generate Prometheus config
type PrometheusScript struct {
Port int
WebExternalURL string
Retention string
EnableNG bool
Port int
WebExternalURL string
BasicAuthPassword string
Retention string
EnableNG bool

DeployDir string
DataDir string
Expand Down Expand Up @@ -58,3 +61,30 @@ func (c *PrometheusScript) ConfigToFile(file string) error {

return utils.WriteFile(file, content.Bytes(), 0755)
}

func (c *PrometheusScript) WebConfigToFile(file string) error {
fp := path.Join("templates", "config", "web.config.yml.tpl")
tpl, err := embed.ReadTemplate(fp)
if err != nil {
return err
}
tmpl, err := template.New("web.config").Parse(string(tpl))
if err != nil {
return err
}

pswHash, err := bcrypt.GenerateFromPassword([]byte(c.BasicAuthPassword), bcrypt.DefaultCost)
if err != nil {
return err
}
tmp := struct {
BasicAuthPassword string
}{BasicAuthPassword: string(pswHash)}

content := bytes.NewBufferString("")
if err := tmpl.Execute(content, tmp); err != nil {
return err
}

return os.WriteFile(file, content.Bytes(), 0755)
}

0 comments on commit 2184ffa

Please sign in to comment.