Add docs, tests, and move namespaced to metricsQuery

This commit is contained in:
Carson Anderson 2021-04-08 11:07:50 -06:00
parent 3ae38c7417
commit 510c3724ce
7 changed files with 158 additions and 19 deletions

View file

@ -102,15 +102,10 @@ type metricNamer struct {
nameMatches *regexp.Regexp
nameAs string
seriesMatchers []*ReMatcher
namespaced *bool
ResourceConverter
}
func (n *metricNamer) isNamespaced() bool {
return (n.namespaced != nil) && *n.namespaced
}
// queryTemplateArgs are the arguments for the metrics query template.
func (n *metricNamer) FilterSeries(initialSeries []prom.Series) []prom.Series {
if len(n.seriesMatchers) == 0 {
@ -136,10 +131,6 @@ func (n *metricNamer) QueryForSeries(series string, resource schema.GroupResourc
}
func (n *metricNamer) QueryForExternalSeries(series string, namespace string, metricSelector labels.Selector) (prom.Selector, error) {
if !n.isNamespaced() {
namespace = ""
}
return n.metricsQuery.BuildExternal(series, namespace, "", []string{}, metricSelector)
}
@ -162,7 +153,13 @@ func NamersFromConfig(cfg []config.DiscoveryRule, mapper apimeta.RESTMapper) ([]
return nil, err
}
metricsQuery, err := NewMetricsQuery(rule.MetricsQuery, resConv)
// queries are namespaced by default unless the rule specifically disables it
namespaced := true
if rule.Resources.Namespaced != nil {
namespaced = *rule.Resources.Namespaced
}
metricsQuery, err := NewMetricsQuery(rule.MetricsQuery, resConv, namespaced)
if err != nil {
return nil, fmt.Errorf("unable to construct metrics query associated with series query %q: %v", rule.SeriesQuery, err)
}
@ -214,7 +211,6 @@ func NamersFromConfig(cfg []config.DiscoveryRule, mapper apimeta.RESTMapper) ([]
nameMatches: nameMatches,
nameAs: nameAs,
seriesMatchers: seriesMatchers,
namespaced: rule.Resources.Namespaced,
ResourceConverter: resConv,
}

View file

@ -50,7 +50,7 @@ type MetricsQuery interface {
// - LabelMatchersByName: the raw map-form of the above matchers
// - GroupBy: the group-by clause to use for the resources in the query (stringified)
// - GroupBySlice: the raw slice form of the above group-by clause
func NewMetricsQuery(queryTemplate string, resourceConverter ResourceConverter) (MetricsQuery, error) {
func NewMetricsQuery(queryTemplate string, resourceConverter ResourceConverter, namespaced bool) (MetricsQuery, error) {
templ, err := template.New("metrics-query").Delims("<<", ">>").Parse(queryTemplate)
if err != nil {
return nil, fmt.Errorf("unable to parse metrics query template %q: %v", queryTemplate, err)
@ -59,6 +59,7 @@ func NewMetricsQuery(queryTemplate string, resourceConverter ResourceConverter)
return &metricsQuery{
resConverter: resourceConverter,
template: templ,
namespaced: namespaced,
}, nil
}
@ -68,6 +69,7 @@ func NewMetricsQuery(queryTemplate string, resourceConverter ResourceConverter)
type metricsQuery struct {
resConverter ResourceConverter
template *template.Template
namespaced bool
}
// queryTemplateArgs contains the arguments for the template used in metricsQuery.
@ -88,7 +90,7 @@ type queryPart struct {
func (q *metricsQuery) Build(series string, resource schema.GroupResource, namespace string, extraGroupBy []string, metricSelector labels.Selector, names ...string) (prom.Selector, error) {
queryParts := q.createQueryPartsFromSelector(metricSelector)
if namespace != "" {
if q.namespaced && namespace != "" {
namespaceLbl, err := q.resConverter.LabelForResource(NsGroupResource)
if err != nil {
return "", err
@ -150,7 +152,7 @@ func (q *metricsQuery) BuildExternal(seriesName string, namespace string, groupB
// Build up the query parts from the selector.
queryParts = append(queryParts, q.createQueryPartsFromSelector(metricSelector)...)
if namespace != "" {
if q.namespaced && namespace != "" {
namespaceLbl, err := q.resConverter.LabelForResource(NsGroupResource)
if err != nil {
return "", err

View file

@ -76,7 +76,15 @@ func checks(cs ...checkFunc) checkFunc {
func TestBuildSelector(t *testing.T) {
mustNewQuery := func(queryTemplate string, namespaced bool) MetricsQuery {
mq, err := NewMetricsQuery(queryTemplate, &resourceConverterMock{namespaced})
mq, err := NewMetricsQuery(queryTemplate, &resourceConverterMock{namespaced}, true)
if err != nil {
t.Fatal(err)
}
return mq
}
mustNewNonNamespacedQuery := func(queryTemplate string, namespaced bool) MetricsQuery {
mq, err := NewMetricsQuery(queryTemplate, &resourceConverterMock{namespaced}, false)
if err != nil {
t.Fatal(err)
}
@ -204,6 +212,21 @@ func TestBuildSelector(t *testing.T) {
),
},
{
name: "multiple LabelValuesByName values with namespace disabled",
mq: mustNewNonNamespacedQuery(`<<index .LabelValuesByName "namespaces">> <<index .LabelValuesByName "resource">>`, true),
metricSelector: labels.NewSelector(),
resource: schema.GroupResource{Group: "group", Resource: "resource"},
namespace: "default",
names: []string{"bar", "baz"},
check: checks(
hasError(nil),
hasSelector(" bar|baz"),
),
},
{
name: "single GroupBy value",
@ -272,7 +295,15 @@ func TestBuildSelector(t *testing.T) {
func TestBuildExternalSelector(t *testing.T) {
mustNewQuery := func(queryTemplate string) MetricsQuery {
mq, err := NewMetricsQuery(queryTemplate, &resourceConverterMock{true})
mq, err := NewMetricsQuery(queryTemplate, &resourceConverterMock{true}, true)
if err != nil {
t.Fatal(err)
}
return mq
}
mustNewNonNamespacedQuery := func(queryTemplate string) MetricsQuery {
mq, err := NewMetricsQuery(queryTemplate, &resourceConverterMock{true}, false)
if err != nil {
t.Fatal(err)
}
@ -348,6 +379,19 @@ func TestBuildExternalSelector(t *testing.T) {
hasSelector("default [foo bar]"),
),
},
{
name: "multiple GroupBySlice values with namespace disabled",
mq: mustNewNonNamespacedQuery(`<<index .LabelValuesByName "namespaces">> <<.GroupBySlice>>`),
namespace: "default",
groupBySlice: []string{"foo", "bar"},
metricSelector: labels.NewSelector(),
check: checks(
hasError(nil),
hasSelector(" [foo bar]"),
),
},
{
name: "single LabelMatchers value",