prometheus-to-sd/config/source_config.go (150 lines of code) (raw):

/* Copyright 2017 Google Inc. 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 ( "fmt" "net" "net/url" "strconv" "strings" "github.com/golang/glog" "github.com/GoogleCloudPlatform/k8s-stackdriver/prometheus-to-sd/flags" ) // SourceConfig contains data specific for scraping one component. type SourceConfig struct { Component string Protocol string Host string Port uint Path string AuthConfig AuthConfig Whitelisted []string WhitelistedLabelsMap map[string]map[string]bool PodConfig PodConfig MetricsPrefix string CustomResourceType string CustomLabels map[string]string } const defaultMetricsPath = "/metrics" var validWhitelistedLabels = map[string]bool{"containerNameLabel": true, "namespaceIdLabel": true, "podIdLabel": true} // newSourceConfig creates a new SourceConfig based on string representation of fields. func newSourceConfig(component, protocol, host, port, path string, auth AuthConfig, whitelisted, metricsPrefix string, podConfig PodConfig, whitelistedLabelsMap map[string]map[string]bool, customResourceType string, customLabels map[string]string) (*SourceConfig, error) { if port == "" { return nil, fmt.Errorf("No port provided.") } if path == "" || path == "/" { path = defaultMetricsPath } portNum, err := strconv.ParseUint(port, 10, 32) if err != nil { return nil, err } if len(protocol) == 0 { if portNum == 443 { protocol = "https" } else { protocol = "http" } } var whitelistedList []string if whitelisted != "" { whitelistedList = strings.Split(whitelisted, ",") } return &SourceConfig{ Component: component, Protocol: protocol, Host: host, Port: uint(portNum), Path: path, AuthConfig: auth, Whitelisted: whitelistedList, WhitelistedLabelsMap: whitelistedLabelsMap, PodConfig: podConfig, MetricsPrefix: metricsPrefix, CustomResourceType: customResourceType, CustomLabels: customLabels, }, nil } // parseSourceConfig creates a new SourceConfig based on the provided flags.Uri instance. func parseSourceConfig(uri flags.Uri, podId, namespaceId string) (*SourceConfig, error) { host, port, err := net.SplitHostPort(uri.Val.Host) if err != nil { return nil, err } component := uri.Key values := uri.Val.Query() protocol := uri.Val.Scheme path := uri.Val.Path whitelisted := values.Get("whitelisted") podIdLabel := values.Get("podIdLabel") namespaceIdLabel := values.Get("namespaceIdLabel") containerNameLabel := values.Get("containerNameLabel") metricsPrefix := values.Get("metricsPrefix") customResource := values.Get("customResourceType") customLabels := getMap(values, "customLabels") auth, err := parseAuthConfig(uri.Val) if err != nil { return nil, err } podConfig := NewPodConfig(podId, namespaceId, podIdLabel, namespaceIdLabel, containerNameLabel) whitelistedLabelsMap, err := parseWhitelistedLabels(values.Get("whitelistedLabels")) if err != nil { return nil, err } return newSourceConfig(component, protocol, host, port, path, *auth, whitelisted, metricsPrefix, podConfig, whitelistedLabelsMap, customResource, customLabels) } func getMap(v url.Values, name string) map[string]string { n := len(name) m := make(map[string]string) for k, vals := range v { if len(k) <= n { continue } if k[:n] == name && k[n] == '[' && k[len(k)-1] == ']' { if len(vals) > 1 { glog.Warningf("Ignoring multiple values of %v", k) } var val string if len(vals) == 1 { val = vals[0] } m[k[n+1:len(k)-1]] = val } } return m } // UpdateWhitelistedMetrics sets passed list as a list of whitelisted metrics. func (config *SourceConfig) UpdateWhitelistedMetrics(list []string) { config.Whitelisted = list } // SourceConfigsFromFlags creates a slice of SourceConfig's base on the provided flags. func SourceConfigsFromFlags(source flags.Uris, podId *string, namespaceId *string, defaultMetricsPrefix string) []*SourceConfig { var sourceConfigs []*SourceConfig for _, c := range source { if sourceConfig, err := parseSourceConfig(c, *podId, *namespaceId); err != nil { glog.Fatalf("Error while parsing source config flag %v: %v", c, err) } else { if sourceConfig.MetricsPrefix == "" { sourceConfig.MetricsPrefix = defaultMetricsPrefix } sourceConfigs = append(sourceConfigs, sourceConfig) } } return sourceConfigs } // parseWhitelistedLabels extracts the labels and their corresponding whitelisted values that will be filtered for. func parseWhitelistedLabels(whitelistedLabels string) (map[string]map[string]bool, error) { // whitelistedLabels is of the format whitelistedLabel1:val11,val12,etc.|whitelistedLabel2:val21 labelsMap := make(map[string]map[string]bool) // URL.Query().Get() will return "" if whitelistedLabels is not specified if whitelistedLabels == "" { return labelsMap, nil } labelVals := strings.Split(whitelistedLabels, "|") for _, labelVal := range labelVals { labelAndValueParts := strings.Split(labelVal, ":") if len(labelAndValueParts) != 2 { return nil, fmt.Errorf("Incorrectly formatted whitelisted label and values: %v", labelVal) } labelKey := labelAndValueParts[0] if validWhitelistedLabels[labelKey] { labelsMap[labelKey] = make(map[string]bool) for _, val := range strings.Split(labelAndValueParts[1], ",") { labelsMap[labelAndValueParts[0]][val] = true } } else { return nil, fmt.Errorf("Filtering against label %v is unsupported. Only containerNameLabel, namespaceIdLabel, and podIdLabel are supported.", labelKey) } } return labelsMap, nil }