2020-04-13 20:02:27 +02:00
package kubernetes
import (
2021-02-26 15:54:03 +01:00
"flag"
"fmt"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
2020-04-13 20:02:27 +02:00
2021-02-26 15:54:03 +01:00
"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
)
2021-03-02 17:32:44 +01:00
var apiServerTimeout = flag . Duration ( "promscrape.kubernetes.apiServerTimeout" , 30 * time . Minute , "How frequently to reload the full state from Kuberntes API server" )
2021-02-26 15:54:03 +01:00
2020-04-23 10:34:04 +02:00
// apiConfig contains config for API server
type apiConfig struct {
2021-02-26 15:54:03 +01:00
aw * apiWatcher
2020-04-23 10:34:04 +02:00
}
2021-03-01 13:13:56 +01:00
func ( ac * apiConfig ) mustStop ( ) {
ac . aw . mustStop ( )
}
2020-05-04 15:21:24 +02:00
var configMap = discoveryutils . NewConfigMap ( )
2020-05-04 14:53:50 +02:00
2021-03-02 15:42:48 +01:00
func getAPIConfig ( sdc * SDConfig , baseDir string , swcFunc ScrapeWorkConstructorFunc ) ( * apiConfig , error ) {
v , err := configMap . Get ( sdc , func ( ) ( interface { } , error ) { return newAPIConfig ( sdc , baseDir , swcFunc ) } )
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
}
2021-03-02 15:42:48 +01:00
func newAPIConfig ( sdc * SDConfig , baseDir string , swcFunc ScrapeWorkConstructorFunc ) ( * apiConfig , error ) {
2021-02-26 15:54:03 +01:00
ac , err := promauth . NewConfig ( baseDir , sdc . BasicAuth , sdc . BearerToken , sdc . BearerTokenFile , sdc . TLSConfig )
2020-05-04 14:53:50 +02:00
if err != nil {
2021-02-26 15:54:03 +01:00
return nil , fmt . Errorf ( "cannot parse auth config: %w" , err )
}
apiServer := sdc . APIServer
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" ,
}
acNew , err := promauth . NewConfig ( "." , nil , "" , "/var/run/secrets/kubernetes.io/serviceaccount/token" , & tlsConfig )
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"
if sdc . TLSConfig != nil {
proto = "https"
}
apiServer = proto + "://" + apiServer
}
for strings . HasSuffix ( apiServer , "/" ) {
apiServer = apiServer [ : len ( apiServer ) - 1 ]
2020-04-13 20:02:27 +02:00
}
2021-02-26 15:54:03 +01:00
var proxy func ( * http . Request ) ( * url . URL , error )
if proxyURL := sdc . ProxyURL . URL ( ) ; proxyURL != nil {
proxy = http . ProxyURL ( proxyURL )
}
client := & http . Client {
Transport : & http . Transport {
TLSClientConfig : ac . NewTLSConfig ( ) ,
Proxy : proxy ,
TLSHandshakeTimeout : 10 * time . Second ,
IdleConnTimeout : * apiServerTimeout ,
} ,
Timeout : * apiServerTimeout ,
}
2021-03-02 15:42:48 +01:00
aw := newAPIWatcher ( client , apiServer , ac . Authorization , sdc . Namespaces . Names , sdc . Selectors , swcFunc )
2020-05-04 19:48:02 +02:00
cfg := & apiConfig {
2021-02-26 15:54:03 +01:00
aw : aw ,
2020-04-13 20:02:27 +02:00
}
2020-05-04 19:48:02 +02:00
return cfg , nil
}