2020-04-13 20:02:27 +02:00
|
|
|
package kubernetes
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
|
2020-05-04 15:21:24 +02:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
|
2020-04-13 20:02:27 +02:00
|
|
|
)
|
|
|
|
|
2020-04-23 10:34:04 +02:00
|
|
|
// apiConfig contains config for API server
|
|
|
|
type apiConfig struct {
|
2020-05-04 19:48:02 +02:00
|
|
|
client *discoveryutils.Client
|
2020-05-04 14:53:50 +02:00
|
|
|
namespaces []string
|
|
|
|
selectors []Selector
|
2020-04-23 10:34:04 +02:00
|
|
|
}
|
|
|
|
|
2020-05-04 15:21:24 +02:00
|
|
|
var configMap = discoveryutils.NewConfigMap()
|
2020-05-04 14:53:50 +02:00
|
|
|
|
2020-05-04 15:21:24 +02:00
|
|
|
func getAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
|
|
|
|
v, err := configMap.Get(sdc, func() (interface{}, error) { return newAPIConfig(sdc, baseDir) })
|
2020-04-13 20:02:27 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-05-04 15:21:24 +02:00
|
|
|
return v.(*apiConfig), nil
|
2020-05-04 14:53:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func newAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
|
|
|
|
ac, err := promauth.NewConfig(baseDir, sdc.BasicAuth, sdc.BearerToken, sdc.BearerTokenFile, sdc.TLSConfig)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot parse auth config: %s", err)
|
|
|
|
}
|
2020-05-04 19:48:02 +02:00
|
|
|
apiServer := sdc.APIServer
|
2020-04-13 20:02:27 +02:00
|
|
|
if len(apiServer) == 0 {
|
|
|
|
// Assume we run at k8s pod.
|
|
|
|
// Discover apiServer and auth config according to k8s docs.
|
|
|
|
// See https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#service-account-admission-controller
|
2020-04-23 10:34:04 +02:00
|
|
|
host := os.Getenv("KUBERNETES_SERVICE_HOST")
|
|
|
|
port := os.Getenv("KUBERNETES_SERVICE_PORT")
|
2020-04-13 20:02:27 +02:00
|
|
|
if len(host) == 0 {
|
2020-04-14 13:19:15 +02:00
|
|
|
return nil, fmt.Errorf("cannot find KUBERNETES_SERVICE_HOST env var; it must be defined when running in k8s; " +
|
2020-04-13 20:02:27 +02:00
|
|
|
"probably, `kubernetes_sd_config->api_server` is missing in Prometheus configs?")
|
|
|
|
}
|
|
|
|
if len(port) == 0 {
|
2020-04-14 13:19:15 +02:00
|
|
|
return nil, fmt.Errorf("cannot find KUBERNETES_SERVICE_PORT env var; it must be defined when running in k8s; "+
|
2020-04-13 20:02:27 +02:00
|
|
|
"KUBERNETES_SERVICE_HOST=%q", host)
|
|
|
|
}
|
|
|
|
apiServer = "https://" + net.JoinHostPort(host, port)
|
|
|
|
tlsConfig := promauth.TLSConfig{
|
|
|
|
CAFile: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
|
|
|
|
}
|
|
|
|
acNew, err := promauth.NewConfig("/", nil, "", "/var/run/secrets/kubernetes.io/serviceaccount/token", &tlsConfig)
|
|
|
|
if err != nil {
|
2020-04-14 13:19:15 +02:00
|
|
|
return nil, fmt.Errorf("cannot initialize service account auth: %s; probably, `kubernetes_sd_config->api_server` is missing in Prometheus configs?", err)
|
2020-04-13 20:02:27 +02:00
|
|
|
}
|
|
|
|
ac = acNew
|
|
|
|
}
|
2020-05-04 19:48:02 +02:00
|
|
|
client, err := discoveryutils.NewClient(apiServer, ac)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot create HTTP client for %q: %s", apiServer, err)
|
2020-04-13 20:02:27 +02:00
|
|
|
}
|
2020-05-04 19:48:02 +02:00
|
|
|
cfg := &apiConfig{
|
|
|
|
client: client,
|
|
|
|
namespaces: sdc.Namespaces.Names,
|
|
|
|
selectors: sdc.Selectors,
|
2020-04-13 20:02:27 +02:00
|
|
|
}
|
2020-05-04 19:48:02 +02:00
|
|
|
return cfg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getAPIResponse(cfg *apiConfig, role, path string) ([]byte, error) {
|
|
|
|
query := joinSelectors(role, cfg.namespaces, cfg.selectors)
|
|
|
|
if len(query) > 0 {
|
|
|
|
path += "?" + query
|
2020-04-13 20:02:27 +02:00
|
|
|
}
|
2020-05-04 19:48:02 +02:00
|
|
|
return cfg.client.GetAPIResponse(path)
|
2020-04-13 20:02:27 +02:00
|
|
|
}
|