Moving metric naming to it's own package

This commit is contained in:
John Delivuk 2019-02-10 15:58:55 -05:00
parent c2e176bb23
commit 6030912cc0
No known key found for this signature in database
GPG key ID: 8597474A0655625E
12 changed files with 93 additions and 227 deletions

View file

@ -2,26 +2,20 @@ package provider
import "errors" import "errors"
// NewOperatorNotSupportedByPrometheusError creates an error that represents the fact that we were requested to service a query that var (
// Prometheus would be unable to support. // ErrorNewOperatorNotSupportedByPrometheus creates an error that represents the fact that we were requested to service a query that
func NewOperatorNotSupportedByPrometheusError() error { // Prometheus would be unable to support.
return errors.New("operator not supported by prometheus") ErrorNewOperatorNotSupportedByPrometheus = errors.New("operator not supported by prometheus")
}
// NewOperatorRequiresValuesError creates an error that represents the fact that we were requested to service a query // ErrorNewOperatorRequiresValues creates an error that represents the fact that we were requested to service a query
// that was malformed in its operator/value combination. // that was malformed in its operator/value combination.
func NewOperatorRequiresValuesError() error { ErrorNewOperatorRequiresValues = errors.New("operator requires values")
return errors.New("operator requires values")
}
// NewOperatorDoesNotSupportValuesError creates an error that represents the fact that we were requested to service a query // ErrorNewOperatorDoesNotSupportValues creates an error that represents the fact that we were requested to service a query
// that was malformed in its operator/value combination. // that was malformed in its operator/value combination.
func NewOperatorDoesNotSupportValuesError() error { ErrorNewOperatorDoesNotSupportValues = errors.New("operator does not support values")
return errors.New("operator does not support values")
}
// NewLabelNotSpecifiedError creates an error that represents the fact that we were requested to service a query // ErrorNewLabelNotSpecified creates an error that represents the fact that we were requested to service a query
// that was malformed in its label specification. // that was malformed in its label specification.
func NewLabelNotSpecifiedError() error { ErrorNewLabelNotSpecified = errors.New("label not specified")
return errors.New("label not specified") )
}

View file

@ -48,12 +48,11 @@ func NewExternalSeriesRegistry(lister MetricListerWithNotification, mapper apime
} }
func (r *externalSeriesRegistry) filterAndStoreMetrics(result MetricUpdateResult) { func (r *externalSeriesRegistry) filterAndStoreMetrics(result MetricUpdateResult) {
newSeriesSlices := result.series newSeriesSlices := result.series
converters := result.converters converters := result.converters
if len(newSeriesSlices) != len(converters) { if len(newSeriesSlices) != len(converters) {
glog.Errorf("need one set of series per converter") glog.Fatal("need one set of series per converter")
} }
apiMetricsCache := make([]provider.ExternalMetricInfo, 0) apiMetricsCache := make([]provider.ExternalMetricInfo, 0)
rawMetricsCache := make(map[string]SeriesConverter) rawMetricsCache := make(map[string]SeriesConverter)
@ -84,6 +83,7 @@ func (r *externalSeriesRegistry) filterAndStoreMetrics(result MetricUpdateResult
r.metrics = apiMetricsCache r.metrics = apiMetricsCache
r.rawMetrics = rawMetricsCache r.rawMetrics = rawMetricsCache
} }
func (r *externalSeriesRegistry) ListAllMetrics() []provider.ExternalMetricInfo { func (r *externalSeriesRegistry) ListAllMetrics() []provider.ExternalMetricInfo {

View file

@ -85,7 +85,6 @@ func (c *metricConverter) convertVector(queryResult prom.QueryResult) (*external
} }
for _, val := range toConvert { for _, val := range toConvert {
singleMetric, err := c.convertSample(val) singleMetric, err := c.convertSample(val)
if err != nil { if err != nil {

View file

@ -1,159 +0,0 @@
package provider
import (
"fmt"
"regexp"
"strings"
"k8s.io/apimachinery/pkg/runtime/schema"
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
"github.com/directxman12/k8s-prometheus-adapter/pkg/config"
"github.com/directxman12/k8s-prometheus-adapter/pkg/naming"
)
var nsGroupResource = schema.GroupResource{Resource: "namespaces"}
var groupNameSanitizer = strings.NewReplacer(".", "_", "-", "_")
// MetricNamer knows how to convert Prometheus series names and label names to
// metrics API resources, and vice-versa. MetricNamers should be safe to access
// concurrently. Returned group-resources are "normalized" as per the
// MetricInfo#Normalized method. Group-resources passed as arguments must
// themselves be normalized.
type MetricNamer interface {
// Selector produces the appropriate Prometheus series selector to match all
// series handlable by this namer.
Selector() prom.Selector
// FilterSeries checks to see which of the given series match any additional
// constrains beyond the series query. It's assumed that the series given
// already matche the series query.
FilterSeries(series []prom.Series) []prom.Series
// MetricNameForSeries returns the name (as presented in the API) for a given series.
MetricNameForSeries(series prom.Series) (string, error)
// QueryForSeries returns the query for a given series (not API metric name), with
// the given namespace name (if relevant), resource, and resource names.
QueryForSeries(series string, resource schema.GroupResource, namespace string, names ...string) (prom.Selector, error)
naming.ResourceConverter
}
func (n *metricNamer) Selector() prom.Selector {
return n.seriesQuery
}
// reMatcher either positively or negatively matches a regex
type reMatcher struct {
regex *regexp.Regexp
positive bool
}
func newReMatcher(cfg config.RegexFilter) (*reMatcher, error) {
if cfg.Is != "" && cfg.IsNot != "" {
return nil, fmt.Errorf("cannot have both an `is` (%q) and `isNot` (%q) expression in a single filter", cfg.Is, cfg.IsNot)
}
if cfg.Is == "" && cfg.IsNot == "" {
return nil, fmt.Errorf("must have either an `is` or `isNot` expression in a filter")
}
var positive bool
var regexRaw string
if cfg.Is != "" {
positive = true
regexRaw = cfg.Is
} else {
positive = false
regexRaw = cfg.IsNot
}
regex, err := regexp.Compile(regexRaw)
if err != nil {
return nil, fmt.Errorf("unable to compile series filter %q: %v", regexRaw, err)
}
return &reMatcher{
regex: regex,
positive: positive,
}, nil
}
func (m *reMatcher) Matches(val string) bool {
return m.regex.MatchString(val) == m.positive
}
type metricNamer struct {
seriesQuery prom.Selector
metricsQuery naming.MetricsQuery
nameMatches *regexp.Regexp
nameAs string
seriesMatchers []*reMatcher
naming.ResourceConverter
}
// queryTemplateArgs are the arguments for the metrics query template.
func (n *metricNamer) FilterSeries(initialSeries []prom.Series) []prom.Series {
if len(n.seriesMatchers) == 0 {
return initialSeries
}
finalSeries := make([]prom.Series, 0, len(initialSeries))
SeriesLoop:
for _, series := range initialSeries {
for _, matcher := range n.seriesMatchers {
if !matcher.Matches(series.Name) {
continue SeriesLoop
}
}
finalSeries = append(finalSeries, series)
}
return finalSeries
}
func (n *metricNamer) QueryForSeries(series string, resource schema.GroupResource, namespace string, names ...string) (prom.Selector, error) {
return n.metricsQuery.Build(series, resource, namespace, nil, names...)
}
func (n *metricNamer) MetricNameForSeries(series prom.Series) (string, error) {
matches := n.nameMatches.FindStringSubmatchIndex(series.Name)
if matches == nil {
return "", fmt.Errorf("series name %q did not match expected pattern %q", series.Name, n.nameMatches.String())
}
outNameBytes := n.nameMatches.ExpandString(nil, n.nameAs, series.Name, matches)
return string(outNameBytes), nil
}
// NewMetricNamer creates a MetricNamer capable of translating Prometheus series names
// into custom metric names.
func NewMetricNamer(mapping config.NameMapping) (MetricNamer, error) {
var nameMatches *regexp.Regexp
var err error
if mapping.Matches != "" {
nameMatches, err = regexp.Compile(mapping.Matches)
if err != nil {
return nil, fmt.Errorf("unable to compile series name match expression %q: %v", mapping.Matches, err)
}
} else {
// this will always succeed
nameMatches = regexp.MustCompile(".*")
}
nameAs := mapping.As
if nameAs == "" {
// check if we have an obvious default
subexpNames := nameMatches.SubexpNames()
if len(subexpNames) == 1 {
// no capture groups, use the whole thing
nameAs = "$0"
} else if len(subexpNames) == 2 {
// one capture group, use that
nameAs = "$1"
} else {
return nil, fmt.Errorf("must specify an 'as' value for name matcher %q", mapping.Matches)
}
}
return &metricNamer{
nameMatches: nameMatches,
nameAs: nameAs,
}, nil
}

View file

@ -18,6 +18,7 @@ import (
"k8s.io/metrics/pkg/apis/external_metrics" "k8s.io/metrics/pkg/apis/external_metrics"
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client" prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
"github.com/directxman12/k8s-prometheus-adapter/pkg/naming"
) )
// TODO: Make sure everything has the proper licensing disclosure at the top. // TODO: Make sure everything has the proper licensing disclosure at the top.
@ -56,7 +57,7 @@ func (p *externalPrometheusProvider) ListAllExternalMetrics() []provider.Externa
func (p *externalPrometheusProvider) selectGroupResource(namespace string) schema.GroupResource { func (p *externalPrometheusProvider) selectGroupResource(namespace string) schema.GroupResource {
if namespace == "default" { if namespace == "default" {
return nsGroupResource return naming.NsGroupResource
} }
return schema.GroupResource{ return schema.GroupResource{

View file

@ -92,11 +92,11 @@ func (n *queryBuilder) processQueryParts(queryParts []queryPart) ([]string, map[
// We obviously can't generate label filters for these cases. // We obviously can't generate label filters for these cases.
fmt.Println("This is queryPart", qPart.labelName, qPart.operator, qPart.values) fmt.Println("This is queryPart", qPart.labelName, qPart.operator, qPart.values)
if qPart.labelName == "" { if qPart.labelName == "" {
return nil, nil, NewLabelNotSpecifiedError() return nil, nil, ErrorNewLabelNotSpecified
} }
if !n.operatorIsSupported(qPart.operator) { if !n.operatorIsSupported(qPart.operator) {
return nil, nil, NewOperatorNotSupportedByPrometheusError() return nil, nil, ErrorNewOperatorNotSupportedByPrometheus
} }
matcher, err := n.selectMatcher(qPart.operator, qPart.values) matcher, err := n.selectMatcher(qPart.operator, qPart.values)
@ -128,7 +128,7 @@ func (n *queryBuilder) selectMatcher(operator selection.Operator, values []strin
case selection.DoesNotExist: case selection.DoesNotExist:
return prom.LabelEq, nil return prom.LabelEq, nil
case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn: case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn:
return nil, NewOperatorRequiresValuesError() return nil, ErrorNewOperatorRequiresValues
} }
} else if numValues == 1 { } else if numValues == 1 {
switch operator { switch operator {
@ -168,7 +168,7 @@ func (n *queryBuilder) selectTargetValue(operator selection.Operator, values []s
// whose value is NOT "". // whose value is NOT "".
return "", nil return "", nil
case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn: case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.In, selection.NotIn:
return "", NewOperatorRequiresValuesError() return "", ErrorNewOperatorRequiresValues
} }
} else if numValues == 1 { } else if numValues == 1 {
switch operator { switch operator {
@ -194,7 +194,7 @@ func (n *queryBuilder) selectTargetValue(operator selection.Operator, values []s
// for their label selector. // for their label selector.
return strings.Join(values, "|"), nil return strings.Join(values, "|"), nil
case selection.Exists, selection.DoesNotExist: case selection.Exists, selection.DoesNotExist:
return "", NewOperatorDoesNotSupportValuesError() return "", ErrorNewOperatorDoesNotSupportValues
} }
} }

View file

@ -49,7 +49,7 @@ type seriesConverter struct {
resourceConverter naming.ResourceConverter resourceConverter naming.ResourceConverter
queryBuilder QueryBuilder queryBuilder QueryBuilder
seriesFilterer SeriesFilterer seriesFilterer SeriesFilterer
metricNamer MetricNamer metricNamer naming.MetricNamer
mapper apimeta.RESTMapper mapper apimeta.RESTMapper
} }
@ -122,7 +122,7 @@ func (c *seriesConverter) buildNamespaceQueryPartForSeries(namespace string) (qu
// If we've been given a namespace, then we need to set up // If we've been given a namespace, then we need to set up
// the label requirements to target that namespace. // the label requirements to target that namespace.
if namespace != "default" { if namespace != "default" {
namespaceLbl, err := c.resourceConverter.LabelForResource(nsGroupResource) namespaceLbl, err := c.resourceConverter.LabelForResource(naming.NsGroupResource)
if err != nil { if err != nil {
return result, err return result, err
} }
@ -226,7 +226,7 @@ func converterFromRule(rule config.DiscoveryRule, mapper apimeta.RESTMapper) (Se
} }
} }
metricNamer, err := NewMetricNamer(rule.Name) metricNamer, err := naming.NewMetricNamer(rule.Name)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to create a MetricNamer associated with series query %q: %v", rule.SeriesQuery, err) return nil, fmt.Errorf("unable to create a MetricNamer associated with series query %q: %v", rule.SeriesQuery, err)
} }
@ -242,7 +242,7 @@ func converterFromRule(rule config.DiscoveryRule, mapper apimeta.RESTMapper) (Se
} }
func (c *seriesConverter) buildNamespaceQueryPartForExternalSeries(namespace string) (queryPart, error) { func (c *seriesConverter) buildNamespaceQueryPartForExternalSeries(namespace string) (queryPart, error) {
namespaceLbl, _ := c.metricNamer.LabelForResource(nsGroupResource) namespaceLbl, _ := c.metricNamer.LabelForResource(naming.NsGroupResource)
return queryPart{ return queryPart{
labelName: string(namespaceLbl), labelName: string(namespaceLbl),

View file

@ -5,6 +5,7 @@ import (
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client" prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
"github.com/directxman12/k8s-prometheus-adapter/pkg/config" "github.com/directxman12/k8s-prometheus-adapter/pkg/config"
"github.com/directxman12/k8s-prometheus-adapter/pkg/naming"
) )
// SeriesFilterer provides functions for filtering collections of Prometheus series // SeriesFilterer provides functions for filtering collections of Prometheus series
@ -15,15 +16,15 @@ type SeriesFilterer interface {
} }
type seriesFilterer struct { type seriesFilterer struct {
seriesMatchers []*reMatcher seriesMatchers []*naming.ReMatcher
} }
// NewSeriesFilterer creates a SeriesFilterer that will remove any series that do not // NewSeriesFilterer creates a SeriesFilterer that will remove any series that do not
// meet the requirements of the provided RegexFilter(s). // meet the requirements of the provided RegexFilter(s).
func NewSeriesFilterer(filters []config.RegexFilter) (SeriesFilterer, error) { func NewSeriesFilterer(filters []config.RegexFilter) (SeriesFilterer, error) {
seriesMatchers := make([]*reMatcher, len(filters)) seriesMatchers := make([]*naming.ReMatcher, len(filters))
for i, filterRaw := range filters { for i, filterRaw := range filters {
matcher, err := newReMatcher(filterRaw) matcher, err := naming.NewReMatcher(filterRaw)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to generate series name filter: %v", err) return nil, fmt.Errorf("unable to generate series name filter: %v", err)
} }
@ -36,7 +37,7 @@ func NewSeriesFilterer(filters []config.RegexFilter) (SeriesFilterer, error) {
} }
func (n *seriesFilterer) AddRequirement(filterRaw config.RegexFilter) error { func (n *seriesFilterer) AddRequirement(filterRaw config.RegexFilter) error {
matcher, err := newReMatcher(filterRaw) matcher, err := naming.NewReMatcher(filterRaw)
if err != nil { if err != nil {
return fmt.Errorf("unable to generate series name filter: %v", err) return fmt.Errorf("unable to generate series name filter: %v", err)
} }

View file

@ -1,21 +1,16 @@
package provider package naming
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"strings"
apimeta "k8s.io/apimachinery/pkg/api/meta" apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client" prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
"github.com/directxman12/k8s-prometheus-adapter/pkg/config" "github.com/directxman12/k8s-prometheus-adapter/pkg/config"
"github.com/directxman12/k8s-prometheus-adapter/pkg/naming"
) )
var nsGroupResource = schema.GroupResource{Resource: "namespaces"}
var groupNameSanitizer = strings.NewReplacer(".", "_", "-", "_")
// MetricNamer knows how to convert Prometheus series names and label names to // MetricNamer knows how to convert Prometheus series names and label names to
// metrics API resources, and vice-versa. MetricNamers should be safe to access // metrics API resources, and vice-versa. MetricNamers should be safe to access
// concurrently. Returned group-resources are "normalized" as per the // concurrently. Returned group-resources are "normalized" as per the
@ -35,20 +30,20 @@ type MetricNamer interface {
// the given namespace name (if relevant), resource, and resource names. // the given namespace name (if relevant), resource, and resource names.
QueryForSeries(series string, resource schema.GroupResource, namespace string, names ...string) (prom.Selector, error) QueryForSeries(series string, resource schema.GroupResource, namespace string, names ...string) (prom.Selector, error)
naming.ResourceConverter ResourceConverter
} }
func (r *metricNamer) Selector() prom.Selector { func (n *metricNamer) Selector() prom.Selector {
return r.seriesQuery return n.seriesQuery
} }
// reMatcher either positively or negatively matches a regex // ReMatcher either positively or negatively matches a regex
type reMatcher struct { type ReMatcher struct {
regex *regexp.Regexp regex *regexp.Regexp
positive bool positive bool
} }
func newReMatcher(cfg config.RegexFilter) (*reMatcher, error) { func NewReMatcher(cfg config.RegexFilter) (*ReMatcher, error) {
if cfg.Is != "" && cfg.IsNot != "" { if cfg.Is != "" && cfg.IsNot != "" {
return nil, fmt.Errorf("cannot have both an `is` (%q) and `isNot` (%q) expression in a single filter", cfg.Is, cfg.IsNot) return nil, fmt.Errorf("cannot have both an `is` (%q) and `isNot` (%q) expression in a single filter", cfg.Is, cfg.IsNot)
} }
@ -71,24 +66,24 @@ func newReMatcher(cfg config.RegexFilter) (*reMatcher, error) {
return nil, fmt.Errorf("unable to compile series filter %q: %v", regexRaw, err) return nil, fmt.Errorf("unable to compile series filter %q: %v", regexRaw, err)
} }
return &reMatcher{ return &ReMatcher{
regex: regex, regex: regex,
positive: positive, positive: positive,
}, nil }, nil
} }
func (m *reMatcher) Matches(val string) bool { func (m *ReMatcher) Matches(val string) bool {
return m.regex.MatchString(val) == m.positive return m.regex.MatchString(val) == m.positive
} }
type metricNamer struct { type metricNamer struct {
seriesQuery prom.Selector seriesQuery prom.Selector
metricsQuery naming.MetricsQuery metricsQuery MetricsQuery
nameMatches *regexp.Regexp nameMatches *regexp.Regexp
nameAs string nameAs string
seriesMatchers []*reMatcher seriesMatchers []*ReMatcher
naming.ResourceConverter ResourceConverter
} }
// queryTemplateArgs are the arguments for the metrics query template. // queryTemplateArgs are the arguments for the metrics query template.
@ -129,26 +124,26 @@ func NamersFromConfig(cfg *config.MetricsDiscoveryConfig, mapper apimeta.RESTMap
namers := make([]MetricNamer, len(cfg.Rules)) namers := make([]MetricNamer, len(cfg.Rules))
for i, rule := range cfg.Rules { for i, rule := range cfg.Rules {
resConv, err := naming.NewResourceConverter(rule.Resources.Template, rule.Resources.Overrides, mapper) resConv, err := NewResourceConverter(rule.Resources.Template, rule.Resources.Overrides, mapper)
if err != nil { if err != nil {
return nil, err return nil, err
} }
metricsQuery, err := naming.NewMetricsQuery(rule.MetricsQuery, resConv) metricsQuery, err := NewMetricsQuery(rule.MetricsQuery, resConv)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to construct metrics query associated with series query %q: %v", rule.SeriesQuery, err) return nil, fmt.Errorf("unable to construct metrics query associated with series query %q: %v", rule.SeriesQuery, err)
} }
seriesMatchers := make([]*reMatcher, len(rule.SeriesFilters)) seriesMatchers := make([]*ReMatcher, len(rule.SeriesFilters))
for i, filterRaw := range rule.SeriesFilters { for i, filterRaw := range rule.SeriesFilters {
matcher, err := newReMatcher(filterRaw) matcher, err := NewReMatcher(filterRaw)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to generate series name filter associated with series query %q: %v", rule.SeriesQuery, err) return nil, fmt.Errorf("unable to generate series name filter associated with series query %q: %v", rule.SeriesQuery, err)
} }
seriesMatchers[i] = matcher seriesMatchers[i] = matcher
} }
if rule.Name.Matches != "" { if rule.Name.Matches != "" {
matcher, err := newReMatcher(config.RegexFilter{Is: rule.Name.Matches}) matcher, err := NewReMatcher(config.RegexFilter{Is: rule.Name.Matches})
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to generate series name filter from name rules associated with series query %q: %v", rule.SeriesQuery, err) return nil, fmt.Errorf("unable to generate series name filter from name rules associated with series query %q: %v", rule.SeriesQuery, err)
} }
@ -194,3 +189,38 @@ func NamersFromConfig(cfg *config.MetricsDiscoveryConfig, mapper apimeta.RESTMap
return namers, nil return namers, nil
} }
// NewMetricNamer creates a MetricNamer capable of translating Prometheus series names
// into custom metric names.
func NewMetricNamer(mapping config.NameMapping) (MetricNamer, error) {
var nameMatches *regexp.Regexp
var err error
if mapping.Matches != "" {
nameMatches, err = regexp.Compile(mapping.Matches)
if err != nil {
return nil, fmt.Errorf("unable to compile series name match expression %q: %v", mapping.Matches, err)
}
} else {
// this will always succeed
nameMatches = regexp.MustCompile(".*")
}
nameAs := mapping.As
if nameAs == "" {
// check if we have an obvious default
subexpNames := nameMatches.SubexpNames()
if len(subexpNames) == 1 {
// no capture groups, use the whole thing
nameAs = "$0"
} else if len(subexpNames) == 2 {
// one capture group, use that
nameAs = "$1"
} else {
return nil, fmt.Errorf("must specify an 'as' value for name matcher %q", mapping.Matches)
}
}
return &metricNamer{
nameMatches: nameMatches,
nameAs: nameAs,
}, nil
}

View file

@ -64,7 +64,7 @@ func (q *metricsQuery) Build(series string, resource schema.GroupResource, names
valuesByName := map[string][]string{} valuesByName := map[string][]string{}
if namespace != "" { if namespace != "" {
namespaceLbl, err := q.resConverter.LabelForResource(nsGroupResource) namespaceLbl, err := q.resConverter.LabelForResource(NsGroupResource)
if err != nil { if err != nil {
return "", err return "", err
} }

View file

@ -1,4 +1,4 @@
package provider package naming
import ( import (
"testing" "testing"
@ -13,7 +13,7 @@ func TestReMatcherIs(t *testing.T) {
Is: "my_.*", Is: "my_.*",
} }
matcher, err := newReMatcher(filter) matcher, err := NewReMatcher(filter)
require.NoError(t, err) require.NoError(t, err)
result := matcher.Matches("my_label") result := matcher.Matches("my_label")
@ -28,7 +28,7 @@ func TestReMatcherIsNot(t *testing.T) {
IsNot: "my_.*", IsNot: "my_.*",
} }
matcher, err := newReMatcher(filter) matcher, err := NewReMatcher(filter)
require.NoError(t, err) require.NoError(t, err)
result := matcher.Matches("my_label") result := matcher.Matches("my_label")
@ -44,6 +44,6 @@ func TestEnforcesIsOrIsNotButNotBoth(t *testing.T) {
IsNot: "your_.*", IsNot: "your_.*",
} }
_, err := newReMatcher(filter) _, err := NewReMatcher(filter)
require.Error(t, err) require.Error(t, err)
} }

View file

@ -18,8 +18,8 @@ import (
) )
var ( var (
groupNameSanitizer = strings.NewReplacer(".", "_", "-", "_") GroupNameSanitizer = strings.NewReplacer(".", "_", "-", "_")
nsGroupResource = schema.GroupResource{Resource: "namespaces"} NsGroupResource = schema.GroupResource{Resource: "namespaces"}
) )
// ResourceConverter knows the relationship between Kubernetes group-resources and Prometheus labels, // ResourceConverter knows the relationship between Kubernetes group-resources and Prometheus labels,
@ -118,7 +118,7 @@ func (r *resourceConverter) makeLabelForResource(resource schema.GroupResource)
return "", fmt.Errorf("unable to singularize resource %s: %v", resource.String(), err) return "", fmt.Errorf("unable to singularize resource %s: %v", resource.String(), err)
} }
convResource := schema.GroupResource{ convResource := schema.GroupResource{
Group: groupNameSanitizer.Replace(resource.Group), Group: GroupNameSanitizer.Replace(resource.Group),
Resource: singularRes, Resource: singularRes,
} }
@ -177,7 +177,7 @@ func (r *resourceConverter) ResourcesForSeries(series prom.Series) ([]schema.Gro
} }
} }
if groupRes == nsGroupResource { if groupRes == NsGroupResource {
namespaced = true namespaced = true
} }
} }