prometheus-adapter/pkg/custom-provider/external_metric_query_builder.go
Tony Compton 3727f99343 Moving the query building logic, adding first unit test.
Moving it into its own type to better organize and separate concerns. Also makes unit testing easier.
2018-06-27 21:37:21 -04:00

94 lines
2.5 KiB
Go

package provider
import (
"fmt"
s "strings"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
)
type ExternalMetricQueryBuilder interface {
BuildPrometheusQuery(namespace string, metricName string, metricSelector labels.Selector) string
}
type externalMetricQueryBuilder struct {
}
func NewExternalMetricQueryBuilder() ExternalMetricQueryBuilder {
return &externalMetricQueryBuilder{}
}
func (p *externalMetricQueryBuilder) BuildPrometheusQuery(namespace string, metricName string, metricSelector labels.Selector) string {
namespaceSelector := p.makeLabelFilter("namespace", "=", namespace)
otherSelectors := p.convertSelectors(metricSelector)
finalTargets := append([]string{namespaceSelector}, otherSelectors...)
joinedLabels := s.Join(finalTargets, ", ")
return fmt.Sprintf("%s{%s}", metricName, joinedLabels)
}
func (p *externalMetricQueryBuilder) makeLabelFilter(labelName string, operator string, targetValue string) string {
return fmt.Sprintf("%s%s\"%s\"", labelName, operator, targetValue)
}
func (p *externalMetricQueryBuilder) convertSelectors(metricSelector labels.Selector) []string {
requirements, _ := metricSelector.Requirements()
selectors := []string{}
for i := 0; i < len(requirements); i++ {
selector := p.convertRequirement(requirements[i])
selectors = append(selectors, selector)
}
return selectors
}
func (p *externalMetricQueryBuilder) convertRequirement(requirement labels.Requirement) string {
labelName := requirement.Key()
values := requirement.Values().List()
stringValues := values[0]
valueCount := len(values)
if valueCount > 1 {
stringValues = s.Join(values, "|")
}
operator := p.selectOperator(requirement.Operator(), valueCount)
return p.makeLabelFilter(labelName, operator, stringValues)
}
func (p *externalMetricQueryBuilder) selectOperator(operator selection.Operator, valueCount int) string {
if valueCount > 1 {
return p.selectRegexOperator(operator)
}
return p.selectSingleValueOperator(operator)
}
func (p *externalMetricQueryBuilder) selectRegexOperator(operator selection.Operator) string {
switch operator {
case selection.Equals:
return "=~"
case selection.NotEquals:
return "!~"
}
//TODO: Cover more cases, supply appropriate errors for any unhandled cases.
return "="
}
func (p *externalMetricQueryBuilder) selectSingleValueOperator(operator selection.Operator) string {
switch operator {
case selection.Equals:
return "="
case selection.NotEquals:
return "!="
}
//TODO: Cover more cases, supply appropriate errors for any unhandled cases.
return "="
}