2020-04-13 18:02:27 +00:00
|
|
|
package kubernetes
|
|
|
|
|
|
|
|
import (
|
2021-02-26 14:54:03 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"strings"
|
2020-04-13 18:02:27 +00:00
|
|
|
|
2021-02-26 14:54:03 +00:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
|
2020-04-13 18:02:27 +00:00
|
|
|
)
|
|
|
|
|
2021-03-02 14:42:48 +00:00
|
|
|
func newAPIConfig(sdc *SDConfig, baseDir string, swcFunc ScrapeWorkConstructorFunc) (*apiConfig, error) {
|
2021-08-29 09:34:55 +00:00
|
|
|
role := sdc.role()
|
|
|
|
switch role {
|
2021-08-29 08:23:06 +00:00
|
|
|
case "node", "pod", "service", "endpoints", "endpointslice", "ingress":
|
2021-03-11 14:41:09 +00:00
|
|
|
default:
|
2021-08-29 09:34:55 +00:00
|
|
|
return nil, fmt.Errorf("unexpected `role`: %q; must be one of `node`, `pod`, `service`, `endpoints`, `endpointslice` or `ingress`", role)
|
2021-03-11 14:41:09 +00:00
|
|
|
}
|
2022-06-22 17:38:43 +00:00
|
|
|
cc := &sdc.HTTPClientConfig
|
|
|
|
ac, err := cc.NewConfig(baseDir)
|
2020-05-04 12:53:50 +00:00
|
|
|
if err != nil {
|
2021-02-26 14:54:03 +00:00
|
|
|
return nil, fmt.Errorf("cannot parse auth config: %w", err)
|
|
|
|
}
|
|
|
|
apiServer := sdc.APIServer
|
2022-06-01 18:34:00 +00:00
|
|
|
|
2022-06-06 11:24:52 +00:00
|
|
|
if len(sdc.KubeConfigFile) > 0 {
|
|
|
|
if len(apiServer) > 0 {
|
|
|
|
return nil, fmt.Errorf("`api_server: %q` and `kubeconfig_file: %q` options cannot be set simultaneously", apiServer, sdc.KubeConfigFile)
|
|
|
|
}
|
|
|
|
kc, err := newKubeConfig(sdc.KubeConfigFile)
|
2022-06-01 18:34:00 +00:00
|
|
|
if err != nil {
|
2022-06-06 11:24:52 +00:00
|
|
|
return nil, fmt.Errorf("cannot build kube config from the specified `kubeconfig_file` config option: %w", err)
|
2022-06-01 18:34:00 +00:00
|
|
|
}
|
2022-07-04 11:27:48 +00:00
|
|
|
opts := &promauth.Options{
|
|
|
|
BaseDir: baseDir,
|
|
|
|
BasicAuth: kc.basicAuth,
|
|
|
|
BearerToken: kc.token,
|
|
|
|
BearerTokenFile: kc.tokenFile,
|
|
|
|
OAuth2: cc.OAuth2,
|
|
|
|
TLSConfig: kc.tlsConfig,
|
|
|
|
Headers: cc.Headers,
|
|
|
|
}
|
|
|
|
acNew, err := opts.NewConfig()
|
2022-06-01 18:34:00 +00:00
|
|
|
if err != nil {
|
2022-06-06 11:24:52 +00:00
|
|
|
return nil, fmt.Errorf("cannot initialize auth config from `kubeconfig_file: %q`: %w", sdc.KubeConfigFile, err)
|
2022-06-01 18:34:00 +00:00
|
|
|
}
|
2022-06-06 11:24:52 +00:00
|
|
|
ac = acNew
|
2022-06-01 18:44:45 +00:00
|
|
|
apiServer = kc.server
|
|
|
|
sdc.ProxyURL = kc.proxyURL
|
2022-06-01 18:34:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 14:54:03 +00: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
|
|
|
|
host := os.Getenv("KUBERNETES_SERVICE_HOST")
|
|
|
|
port := os.Getenv("KUBERNETES_SERVICE_PORT")
|
|
|
|
if len(host) == 0 {
|
|
|
|
return nil, fmt.Errorf("cannot find KUBERNETES_SERVICE_HOST env var; it must be defined when running in k8s; " +
|
|
|
|
"probably, `kubernetes_sd_config->api_server` is missing in Prometheus configs?")
|
|
|
|
}
|
|
|
|
if len(port) == 0 {
|
|
|
|
return nil, fmt.Errorf("cannot find KUBERNETES_SERVICE_PORT env var; it must be defined when running in k8s; "+
|
|
|
|
"KUBERNETES_SERVICE_HOST=%q", host)
|
|
|
|
}
|
|
|
|
apiServer = "https://" + net.JoinHostPort(host, port)
|
|
|
|
tlsConfig := promauth.TLSConfig{
|
|
|
|
CAFile: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
|
|
|
|
}
|
2022-07-04 11:27:48 +00:00
|
|
|
opts := &promauth.Options{
|
|
|
|
BaseDir: baseDir,
|
|
|
|
BearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token",
|
|
|
|
OAuth2: cc.OAuth2,
|
|
|
|
TLSConfig: &tlsConfig,
|
|
|
|
Headers: cc.Headers,
|
|
|
|
}
|
|
|
|
acNew, err := opts.NewConfig()
|
2021-02-26 14:54:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot initialize service account auth: %w; probably, `kubernetes_sd_config->api_server` is missing in Prometheus configs?", err)
|
|
|
|
}
|
|
|
|
ac = acNew
|
|
|
|
}
|
|
|
|
if !strings.Contains(apiServer, "://") {
|
|
|
|
proto := "http"
|
2021-04-02 18:17:43 +00:00
|
|
|
if sdc.HTTPClientConfig.TLSConfig != nil {
|
2021-02-26 14:54:03 +00:00
|
|
|
proto = "https"
|
|
|
|
}
|
|
|
|
apiServer = proto + "://" + apiServer
|
|
|
|
}
|
|
|
|
for strings.HasSuffix(apiServer, "/") {
|
|
|
|
apiServer = apiServer[:len(apiServer)-1]
|
2020-04-13 18:02:27 +00:00
|
|
|
}
|
2023-10-27 18:20:22 +00:00
|
|
|
// pre-check tls config
|
|
|
|
if _, err := ac.NewTLSConfig(); err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot initialize tls config: %w", err)
|
|
|
|
}
|
2021-03-11 14:41:09 +00:00
|
|
|
aw := newAPIWatcher(apiServer, ac, sdc, swcFunc)
|
2020-05-04 17:48:02 +00:00
|
|
|
cfg := &apiConfig{
|
2021-02-26 14:54:03 +00:00
|
|
|
aw: aw,
|
2020-04-13 18:02:27 +00:00
|
|
|
}
|
2020-05-04 17:48:02 +00:00
|
|
|
return cfg, nil
|
|
|
|
}
|