Cleaning up.

* Wiped out a ton of warnings about comments.
* Created consts for `MetricType` values.
* `externalInfoMap` can now track multiple series with the same name/namespace and different labels.
* `namespace` parameter of external metrics queries is now respected (albeit very rudimentarily)
* Metric converter values for external metrics are now converted the same way as for custom metrics (probably still some opportunity for consolidation).
* Lots of TODOs actually done.
* Deleted a lot of commented out code.
This commit is contained in:
Tony Compton 2018-07-20 15:35:24 -04:00
parent 9641e70005
commit a94494337e
18 changed files with 155 additions and 188 deletions

View file

@ -34,7 +34,10 @@ type DiscoveryRule struct {
MetricsQuery string `yaml:"metricsQuery,omitempty"`
// MetricType identifies whether the metrics derived from this rule should be classified
// as external or custom metrics.
MetricType MetricType `yaml:"metricType"`
MetricType MetricType `yaml:"metricType,omitempty"`
// ExternalMetricNamespaceLabelName identifies what Prometheus label should be examined
// to apply a namespace to metrics creates from this rule.
ExternalMetricNamespaceLabelName string `yaml:"externalMetricNamespaceLabelName,omitempty"`
}
// RegexFilter is a filter that matches positively or negatively against a regex.
@ -79,3 +82,12 @@ type NameMapping struct {
//MetricType identifies whether a given metric should be handled and interpreted as a Custom or External metric.
type MetricType string
// Operator represents a key/field's relationship to value(s).
// See labels.Requirement and fields.Requirement for more details.
type Operator string
const (
External MetricType = "External"
Custom MetricType = "Custom"
)

View file

@ -48,13 +48,15 @@ type MetricLister interface {
ListAllMetrics() (metricUpdateResult, error)
}
//A MetricListerWithNotification is a MetricLister that has the ability to notify listeners
//when new metric data is available.
type MetricListerWithNotification interface {
//It can list metrics, just like a normal MetricLister.
MetricLister
//Because it periodically pulls metrics, it needs to be Runnable.
Runnable
//It provides notifications when it has new data to supply.
//AddNotificationReceiver registers a callback to be invoked when new metric data is available.
AddNotificationReceiver(func(metricUpdateResult))
//UpdateNow forces an immediate refresh from the source data. Primarily for test purposes.
UpdateNow()
}
@ -64,6 +66,7 @@ type basicMetricLister struct {
lookback time.Duration
}
//NewBasicMetricLister creates a MetricLister that is capable of interactly directly with Prometheus to list metrics.
func NewBasicMetricLister(promClient prom.Client, namers []MetricNamer, lookback time.Duration) MetricLister {
lister := basicMetricLister{
promClient: promClient,

View file

@ -5,24 +5,37 @@ import (
"k8s.io/apimachinery/pkg/labels"
)
//ExportedMetric is a description of an available metric.
type ExportedMetric struct {
MetricName string
Labels labels.Set
Namespace string
}
//ExternalInfoMap is a data object that accepts and organizes information
//about available metrics.
type ExternalInfoMap interface {
//Begins tracking a metric, returning it to the caller.
TrackMetric(metricName string, generatedBy MetricNamer) ExternalMetricData
//Exports a collection of all of the metrics currently being tracked.
ExportMetrics() []ExportedMetric
//Finds a tracked metric with the given metric name, if it exists.
FindMetric(metricName string) (data ExternalMetricData, found bool)
}
//ExternalMetricData is a data object that accepts and organizes information
//about the various series/namespaces that a metric is associated with.
type ExternalMetricData interface {
//MetricName returns the name of the metric represented by this object.
MetricName() string
//WithSeries associates the provided labels with this metric.
WithSeries(labels labels.Set)
//WithNamespacedSeries associates the provided labels with this metric, but within a particular namespace.
WithNamespacedSeries(namespace string, labels labels.Set)
//Exports a collection of all the metrics currently being tracked.
ExportMetrics() []ExportedMetric
GenerateQuery(selector labels.Selector) (prom.Selector, error)
//Generates a query to select the series/values for the metric this object represents.
GenerateQuery(namespace string, selector labels.Selector) (prom.Selector, error)
}
type externalInfoMap struct {
@ -31,18 +44,20 @@ type externalInfoMap struct {
type externalMetricData struct {
metricName string
namespacedData map[string]labels.Set
namespacedData map[string][]labels.Set
generatedBy MetricNamer
}
//NewExternalMetricData creates an ExternalMetricData for the provided metric name and namer.
func NewExternalMetricData(metricName string, generatedBy MetricNamer) ExternalMetricData {
return &externalMetricData{
metricName: metricName,
generatedBy: generatedBy,
namespacedData: map[string]labels.Set{},
namespacedData: map[string][]labels.Set{},
}
}
//NewExternalInfoMap creates an empty ExternalInfoMap for storing external metric information.
func NewExternalInfoMap() ExternalInfoMap {
return &externalInfoMap{
metrics: map[string]ExternalMetricData{},
@ -78,18 +93,20 @@ func (d *externalMetricData) MetricName() string {
return d.metricName
}
func (d *externalMetricData) GenerateQuery(selector labels.Selector) (prom.Selector, error) {
return d.generatedBy.QueryForExternalSeries(d.metricName, selector)
func (d *externalMetricData) GenerateQuery(namespace string, selector labels.Selector) (prom.Selector, error) {
return d.generatedBy.QueryForExternalSeries(namespace, d.metricName, selector)
}
func (d *externalMetricData) ExportMetrics() []ExportedMetric {
results := make([]ExportedMetric, 0)
for namespace, labels := range d.namespacedData {
results = append(results, ExportedMetric{
Labels: labels,
MetricName: d.metricName,
Namespace: namespace,
})
for namespace, labelSets := range d.namespacedData {
for _, labelSet := range labelSets {
results = append(results, ExportedMetric{
Labels: labelSet,
MetricName: d.metricName,
Namespace: namespace,
})
}
}
return results
@ -99,10 +116,13 @@ func (d *externalMetricData) WithSeries(labels labels.Set) {
d.WithNamespacedSeries("", labels)
}
func (d *externalMetricData) WithNamespacedSeries(namespace string, labels labels.Set) {
func (d *externalMetricData) WithNamespacedSeries(namespace string, seriesLabels labels.Set) {
data, found := d.namespacedData[namespace]
if !found {
data = labels
d.namespacedData[namespace] = data
data = []labels.Set{}
}
data = append(data, seriesLabels)
d.namespacedData[namespace] = data
}

View file

@ -15,16 +15,7 @@ import (
conv "github.com/directxman12/k8s-prometheus-adapter/pkg/custom-provider/metric-converter"
)
//TODO: Make sure everything has the proper licensing disclosure at the top.
//TODO: I'd like to move these files into another directory, but the compiler was giving me
//some static around unexported types. I'm going to leave things as-is for now, but it
//might be worthwhile to, once the shared components are discovered, move some things around.
//TODO: Some of these members may not be necessary.
//Some of them are definitely duplicated between the
//external and custom providers. They should probably share
//the same instances of these objects (especially the SeriesRegistry)
//to cut down on unnecessary chatter/bookkeeping.
//TODO: AC - Make sure everything has the proper licensing disclosure at the top.
type externalPrometheusProvider struct {
promClient prom.Client
metricConverter conv.MetricConverter
@ -32,13 +23,7 @@ type externalPrometheusProvider struct {
seriesRegistry ExternalSeriesRegistry
}
//TODO: It probably makes more sense to, once this is functional and complete, roll the
//prometheusProvider and externalPrometheusProvider up into a single type
//that implements both interfaces or provide a thin wrapper that composes them.
//Just glancing at start.go looks like it would be much more straightforward
//to do one of those two things instead of trying to run the two providers
//independently.
//NewExternalPrometheusProvider creates an ExternalMetricsProvider capable of responding to Kubernetes requests for external metric data.
func NewExternalPrometheusProvider(seriesRegistry ExternalSeriesRegistry, promClient prom.Client, converter conv.MetricConverter) provider.ExternalMetricsProvider {
return &externalPrometheusProvider{
promClient: promClient,
@ -48,21 +33,17 @@ func NewExternalPrometheusProvider(seriesRegistry ExternalSeriesRegistry, promCl
}
func (p *externalPrometheusProvider) GetExternalMetric(namespace string, metricName string, metricSelector labels.Selector) (*external_metrics.ExternalMetricValueList, error) {
selector, found := p.seriesRegistry.QueryForMetric(metricName, metricSelector)
selector, found := p.seriesRegistry.QueryForMetric(namespace, metricName, metricSelector)
if !found {
return &external_metrics.ExternalMetricValueList{
Items: []external_metrics.ExternalMetricValue{},
}, nil
}
// query := p.queryBuilder.BuildPrometheusQuery(namespace, metricName, metricSelector, queryMetadata)
//TODO: I don't yet know what a context is, but apparently I should use a real one.
queryResults, err := p.promClient.Query(context.TODO(), pmodel.Now(), selector)
if err != nil {
//TODO: Is this how folks normally deal w/ errors? Just propagate them upwards?
//I should go look at what the customProvider does.
return nil, err
}

View file

@ -14,31 +14,33 @@ import (
"github.com/directxman12/k8s-prometheus-adapter/pkg/config"
)
//ExternalSeriesRegistry acts as the top-level converter for transforming Kubernetes requests
//for external metrics into Prometheus queries.
type ExternalSeriesRegistry interface {
// ListAllMetrics lists all metrics known to this registry
ListAllMetrics() []provider.ExternalMetricInfo
QueryForMetric(metricName string, metricSelector labels.Selector) (query prom.Selector, found bool)
QueryForMetric(namespace string, metricName string, metricSelector labels.Selector) (query prom.Selector, found bool)
}
// overridableSeriesRegistry is a basic SeriesRegistry
type externalSeriesRegistry struct {
mu sync.RWMutex
externalInfo map[string]seriesInfo
// metrics is the list of all known metrics
metrics []provider.ExternalMetricInfo
mapper apimeta.RESTMapper
metricLister MetricListerWithNotification
tonyExternalInfo ExternalInfoMap
metricLister MetricListerWithNotification
externalMetricInfo ExternalInfoMap
}
//NewExternalSeriesRegistry creates an ExternalSeriesRegistry driven by the data from the provided MetricLister.
func NewExternalSeriesRegistry(lister MetricListerWithNotification, mapper apimeta.RESTMapper) ExternalSeriesRegistry {
var registry = externalSeriesRegistry{
mapper: mapper,
metricLister: lister,
tonyExternalInfo: NewExternalInfoMap(),
mapper: mapper,
metricLister: lister,
externalMetricInfo: NewExternalInfoMap(),
}
lister.AddNotificationReceiver(registry.onNewDataAvailable)
@ -50,7 +52,7 @@ func (r *externalSeriesRegistry) filterMetrics(result metricUpdateResult) metric
namers := make([]MetricNamer, 0)
series := make([][]prom.Series, 0)
targetType := config.MetricType("External")
targetType := config.External
for i, namer := range result.namers {
if namer.MetricType() == targetType {
@ -98,10 +100,16 @@ func (r *externalSeriesRegistry) onNewDataAvailable(result metricUpdateResult) {
// namespaced := identity.namespaced
name := identity.name
labels := r.convertLabels(series.Labels)
//TODO: Figure out the namespace, if applicable
metricNs := ""
//Check for a label indicating namespace.
metricNs, found := series.Labels[model.LabelName(namer.ExternalMetricNamespaceLabelName())]
if !found {
metricNs = ""
}
trackedMetric := updatedCache.TrackMetric(name, namer)
trackedMetric.WithNamespacedSeries(metricNs, labels)
trackedMetric.WithNamespacedSeries(string(metricNs), labels)
}
}
@ -112,7 +120,7 @@ func (r *externalSeriesRegistry) onNewDataAvailable(result metricUpdateResult) {
r.mu.Lock()
defer r.mu.Unlock()
r.tonyExternalInfo = updatedCache
r.externalMetricInfo = updatedCache
r.metrics = convertedMetrics
}
@ -135,29 +143,20 @@ func (r *externalSeriesRegistry) ListAllMetrics() []provider.ExternalMetricInfo
return r.metrics
}
func (r *externalSeriesRegistry) QueryForMetric(metricName string, metricSelector labels.Selector) (query prom.Selector, found bool) {
func (r *externalSeriesRegistry) QueryForMetric(namespace string, metricName string, metricSelector labels.Selector) (query prom.Selector, found bool) {
r.mu.RLock()
defer r.mu.RUnlock()
metric, found := r.tonyExternalInfo.FindMetric(metricName)
metric, found := r.externalMetricInfo.FindMetric(metricName)
if !found {
glog.V(10).Infof("external metric %q not registered", metricName)
return "", false
}
query, err := metric.GenerateQuery(metricSelector)
// info, infoFound := r.info[metricInfo]
// if !infoFound {
// //TODO: Weird that it switches between types here.
// glog.V(10).Infof("metric %v not registered", metricInfo)
// return "", false
// }
query, err := metric.GenerateQuery(namespace, metricSelector)
// query, err := info.namer.QueryForExternalSeries(info.seriesName, metricSelector)
if err != nil {
//TODO: See what was being .String() and implement that for ExternalMetricInfo.
// errorVal := metricInfo.String()
errorVal := "something"
glog.Errorf("unable to construct query for metric %s: %v", errorVal, err)
glog.Errorf("unable to construct query for external metric %s: %v", metricName, err)
return "", false
}

View file

@ -32,6 +32,6 @@ func (c *matrixConverter) Convert(queryResult prom.QueryResult) (*external_metri
}
func (c *matrixConverter) convert(result *model.Matrix) (*external_metrics.ExternalMetricValueList, error) {
//TODO: Implementation.
//TODO: AC - Implementation.
return nil, errors.New("converting Matrix results is not yet supported")
}

View file

@ -30,14 +30,10 @@ func (c *sampleConverter) Convert(sample *model.Sample) (*external_metrics.Exter
Timestamp: metav1.Time{
sample.Timestamp.Time(),
},
//TODO: I'm not so sure about this type/conversions.
//This can't possibly be the right way to convert this.
//Also, does K8S only deal win integer metrics?
Value: *resource.NewQuantity(int64(float64(sample.Value)), resource.DecimalSI),
Value: *resource.NewMilliQuantity(int64(sample.Value*1000.0), resource.DecimalSI),
MetricLabels: labels,
}
//TODO: Actual errors?
return &singleMetric, nil
}

View file

@ -35,18 +35,11 @@ func (c *scalarConverter) Convert(queryResult prom.QueryResult) (*external_metri
func (c *scalarConverter) convert(input *model.Scalar) (*external_metrics.ExternalMetricValueList, error) {
result := external_metrics.ExternalMetricValueList{
//Using prometheusProvider.metricsFor(...) as an example,
//it seems that I don't need to provide values for
//TypeMeta and ListMeta.
//TODO: Get some confirmation on this.
Items: []external_metrics.ExternalMetricValue{
{
Timestamp: metav1.Time{
input.Timestamp.Time(),
},
//TODO: I'm not so sure about this type/conversions.
//Is there a meaningful loss of precision here?
//Does K8S only deal win integer metrics?
Value: *resource.NewMilliQuantity(int64(input.Value*1000.0), resource.DecimalSI),
},
},

View file

@ -2,6 +2,7 @@ package provider
import (
"errors"
"fmt"
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
"github.com/prometheus/common/model"
@ -46,8 +47,13 @@ func (c *vectorConverter) convert(result model.Vector) (*external_metrics.Extern
}
for _, val := range result {
//TODO: Care about potential errors here.
singleMetric, _ := c.SampleConverter.Convert(val)
singleMetric, err := c.SampleConverter.Convert(val)
if err != nil {
return nil, fmt.Errorf("unable to convert vector: %v", err)
}
items = append(items, *singleMetric)
}

View file

@ -8,6 +8,7 @@ import (
"github.com/directxman12/k8s-prometheus-adapter/pkg/config"
)
//MetricNameConverter provides functions for naming custom metrics from Promethes series.
type MetricNameConverter interface {
GetMetricNameForSeries(series prom.Series) (string, error)
}
@ -17,6 +18,8 @@ type metricNameConverter struct {
nameAs string
}
//NewMetricNameConverter creates a MetricNameConverter capable of translating Prometheus series names
//into custom metric names.
func NewMetricNameConverter(mapping config.NameMapping) (MetricNameConverter, error) {
var nameMatches *regexp.Regexp
var err error

View file

@ -34,9 +34,10 @@ type MetricNamer interface {
// 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)
QueryForExternalSeries(series string, metricSelector labels.Selector) (prom.Selector, error)
QueryForExternalSeries(namespace string, series string, metricSelector labels.Selector) (prom.Selector, error)
IdentifySeries(series prom.Series) (seriesIdentity, error)
MetricType() config.MetricType
ExternalMetricNamespaceLabelName() string
}
type seriesIdentity struct {
@ -58,7 +59,8 @@ type metricNamer struct {
metricNameConverter MetricNameConverter
mapper apimeta.RESTMapper
metricType config.MetricType
metricType config.MetricType
externalMetricNamespaceLabel string
}
// queryTemplateArgs are the arguments for the metrics query template.
@ -74,6 +76,10 @@ func (n *metricNamer) MetricType() config.MetricType {
return n.metricType
}
func (n *metricNamer) ExternalMetricNamespaceLabelName() string {
return n.externalMetricNamespaceLabel
}
func (n *metricNamer) IdentifySeries(series prom.Series) (seriesIdentity, error) {
// TODO: warn if it doesn't match any resources
resources, namespaced := n.resourceConverter.ResourcesForSeries(series)
@ -219,15 +225,26 @@ func NamersFromConfig(cfg *config.MetricsDiscoveryConfig, mapper apimeta.RESTMap
return nil, fmt.Errorf("unable to create a MetricNameConverter associated with series query %q: %v", rule.SeriesQuery, err)
}
namespaceLabel := ""
if rule.MetricType == config.External {
namespaceLabel = rule.ExternalMetricNamespaceLabelName
}
metricType := rule.MetricType
if metricType == config.MetricType("") {
metricType = config.Custom
}
namer := &metricNamer{
seriesQuery: prom.Selector(rule.SeriesQuery),
mapper: mapper,
resourceConverter: resourceConverter,
queryBuilder: queryBuilder,
seriesFilterer: seriesFilterer,
metricNameConverter: metricNameConverter,
metricType: rule.MetricType,
resourceConverter: resourceConverter,
queryBuilder: queryBuilder,
seriesFilterer: seriesFilterer,
metricNameConverter: metricNameConverter,
metricType: metricType,
externalMetricNamespaceLabel: namespaceLabel,
}
namers[i] = namer
@ -236,8 +253,28 @@ func NamersFromConfig(cfg *config.MetricsDiscoveryConfig, mapper apimeta.RESTMap
return namers, nil
}
func (n *metricNamer) QueryForExternalSeries(series string, metricSelector labels.Selector) (prom.Selector, error) {
queryParts := n.createQueryPartsFromSelector(metricSelector)
func (n *metricNamer) buildNamespaceQueryPartForExternalSeries(namespace string) (queryPart, error) {
return queryPart{
labelName: n.externalMetricNamespaceLabel,
values: []string{namespace},
}, nil
}
func (n *metricNamer) QueryForExternalSeries(namespace string, series string, metricSelector labels.Selector) (prom.Selector, error) {
queryParts := []queryPart{}
if namespace != "" {
//Build up the namespace part of the query.
namespaceQueryPart, err := n.buildNamespaceQueryPartForExternalSeries(namespace)
if err != nil {
return "", err
}
queryParts = append(queryParts, namespaceQueryPart)
}
//Build up the query parts from the selector.
queryParts = append(queryParts, n.createQueryPartsFromSelector(metricSelector)...)
selector, err := n.queryBuilder.BuildSelector(series, "", []string{}, queryParts)
if err != nil {

View file

@ -87,69 +87,3 @@ func (l *periodicMetricLister) notifyListeners() {
func (l *periodicMetricLister) UpdateNow() {
l.updateMetrics()
}
// func (l *periodicMetricLister) updateMetrics() (metricUpdateResult, error) {
// result := metricUpdateResult{
// series: make([][]prom.Series, 0),
// namers: make([]MetricNamer, 0),
// }
// startTime := pmodel.Now().Add(-1 * l.updateInterval)
// // these can take a while on large clusters, so launch in parallel
// // and don't duplicate
// selectors := make(map[prom.Selector]struct{})
// selectorSeriesChan := make(chan selectorSeries, len(l.namers))
// errs := make(chan error, len(l.namers))
// for _, namer := range l.namers {
// sel := namer.Selector()
// if _, ok := selectors[sel]; ok {
// errs <- nil
// selectorSeriesChan <- selectorSeries{}
// continue
// }
// selectors[sel] = struct{}{}
// go func() {
// series, err := l.promClient.Series(context.TODO(), pmodel.Interval{startTime, 0}, sel)
// if err != nil {
// errs <- fmt.Errorf("unable to fetch metrics for query %q: %v", sel, err)
// return
// }
// errs <- nil
// selectorSeriesChan <- selectorSeries{
// selector: sel,
// series: series,
// }
// }()
// }
// // don't do duplicate queries when it's just the matchers that change
// seriesCacheByQuery := make(map[prom.Selector][]prom.Series)
// // iterate through, blocking until we've got all results
// for range l.namers {
// if err := <-errs; err != nil {
// return result, fmt.Errorf("unable to update list of all metrics: %v", err)
// }
// if ss := <-selectorSeriesChan; ss.series != nil {
// seriesCacheByQuery[ss.selector] = ss.series
// }
// }
// close(errs)
// newSeries := make([][]prom.Series, len(l.namers))
// for i, namer := range l.namers {
// series, cached := seriesCacheByQuery[namer.Selector()]
// if !cached {
// return result, fmt.Errorf("unable to update list of all metrics: no metrics retrieved for query %q", namer.Selector())
// }
// newSeries[i] = namer.FilterSeries(series)
// }
// glog.V(10).Infof("Set available metric list from Prometheus to: %v", newSeries)
// result.series = newSeries
// result.namers = l.namers
// return result, nil
// }

View file

@ -46,12 +46,11 @@ type prometheusProvider struct {
SeriesRegistry
}
//NewPrometheusProvider creates an CustomMetricsProvider capable of responding to Kubernetes requests for custom metric data.
func NewPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.Interface, promClient prom.Client, namers []MetricNamer, updateInterval time.Duration) (provider.CustomMetricsProvider, Runnable) {
//TODO: AC - Consider injecting these objects and calling .Run() before calling this function.
basicLister := NewBasicMetricLister(promClient, namers, updateInterval)
//TODO: Be sure to run this runnable.
// periodicLister, periodicRunnable := NewPeriodicMetricLister(basicLister, updateInterval)
periodicLister, _ := NewPeriodicMetricLister(basicLister, updateInterval)
seriesRegistry := NewBasicSeriesRegistry(periodicLister, mapper)
return &prometheusProvider{

View file

@ -9,6 +9,7 @@ import (
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
)
//QueryBuilder provides functions for generating Prometheus queries.
type QueryBuilder interface {
BuildSelector(seriesName string, groupBy string, groupBySlice []string, queryParts []queryPart) (prom.Selector, error)
}
@ -17,6 +18,7 @@ type queryBuilder struct {
metricsQueryTemplate *template.Template
}
//NewQueryBuilder creates a QueryBuilder.
func NewQueryBuilder(metricsQuery string) (QueryBuilder, error) {
metricsQueryTemplate, err := template.New("metrics-query").Delims("<<", ">>").Parse(metricsQuery)
if err != nil {

View file

@ -79,4 +79,4 @@ func TestQueryWithGroupBy(t *testing.T) {
require.Equal(t, selector, expectation)
}
//TODO: Ensure that the LabelValuesByName and GroupBySlice placeholders function correctly.
//TODO: AC - Ensure that the LabelValuesByName and GroupBySlice placeholders function correctly.

View file

@ -17,6 +17,9 @@ import (
pmodel "github.com/prometheus/common/model"
)
//ResourceConverter is a type for extracting associated Kubernetes GroupResource objects from
//Prometheus series and generating appropriate labels to target specific Kubernetes GroupResource
//objects.
type ResourceConverter interface {
// ResourcesForSeries returns the group-resources associated with the given series,
// as well as whether or not the given series has the "namespace" resource).
@ -34,6 +37,7 @@ type resourceConverter struct {
labelTemplate *template.Template
}
//NewResourceConverter creates a ResourceConverter that will use the provided parameters to map data between Prometheus and Kubernetes.
func NewResourceConverter(resourceTemplate string, overrides map[string]config.GroupResource, mapper apimeta.RESTMapper) (ResourceConverter, error) {
converter := &resourceConverter{
labelToResource: make(map[pmodel.LabelName]schema.GroupResource),

View file

@ -7,6 +7,8 @@ import (
"github.com/directxman12/k8s-prometheus-adapter/pkg/config"
)
//SeriesFilterer provides functions for filtering collections of Prometheus series
//to only those that meet certain requirements.
type SeriesFilterer interface {
FilterSeries(series []prom.Series) []prom.Series
AddRequirement(filter config.RegexFilter) error
@ -16,6 +18,8 @@ type seriesFilterer struct {
seriesMatchers []*reMatcher
}
//NewSeriesFilterer creates a SeriesFilterer that will remove any series that do not
//meet the requirements of the provided RegexFilter(s).
func NewSeriesFilterer(filters []config.RegexFilter) (SeriesFilterer, error) {
seriesMatchers := make([]*reMatcher, len(filters))
for i, filterRaw := range filters {

View file

@ -21,7 +21,6 @@ import (
"github.com/kubernetes-incubator/custom-metrics-apiserver/pkg/provider"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
"github.com/directxman12/k8s-prometheus-adapter/pkg/config"
@ -49,8 +48,6 @@ type SeriesRegistry interface {
// SeriesForMetric looks up the minimum required series information to make a query for the given metric
// against the given resource (namespace may be empty for non-namespaced resources)
QueryForMetric(info provider.CustomMetricInfo, namespace string, resourceNames ...string) (query prom.Selector, found bool)
// TODO: Don't house the external metric stuff side-by-side with the custom metric stuff.
QueryForExternalMetric(info provider.ExternalMetricInfo, metricSelector labels.Selector) (query prom.Selector, found bool)
// MatchValuesToNames matches result values to resource names for the given metric and value set
MatchValuesToNames(metricInfo provider.CustomMetricInfo, values pmodel.Vector) (matchedValues map[string]pmodel.SampleValue, found bool)
}
@ -78,6 +75,7 @@ type basicSeriesRegistry struct {
metricLister MetricListerWithNotification
}
//NewBasicSeriesRegistry creates a SeriesRegistry driven by the data from the provided MetricLister.
func NewBasicSeriesRegistry(lister MetricListerWithNotification, mapper apimeta.RESTMapper) SeriesRegistry {
var registry = basicSeriesRegistry{
mapper: mapper,
@ -93,7 +91,7 @@ func (r *basicSeriesRegistry) filterMetrics(result metricUpdateResult) metricUpd
namers := make([]MetricNamer, 0)
series := make([][]prom.Series, 0)
targetType := config.MetricType("Custom")
targetType := config.Custom
for i, namer := range result.namers {
if namer.MetricType() == targetType {
@ -205,30 +203,6 @@ func (r *basicSeriesRegistry) QueryForMetric(metricInfo provider.CustomMetricInf
return query, true
}
func (r *basicSeriesRegistry) QueryForExternalMetric(metricInfo provider.ExternalMetricInfo, metricSelector labels.Selector) (query prom.Selector, found bool) {
r.mu.RLock()
defer r.mu.RUnlock()
//TODO: Implementation
return "", false
// info, infoFound := r.info[metricInfo]
// if !infoFound {
// //TODO: Weird that it switches between types here.
// glog.V(10).Infof("metric %v not registered", metricInfo)
// return "", false
// }
// query, err := info.namer.QueryForExternalSeries(info.seriesName, metricSelector)
// if err != nil {
// //TODO: See what was being .String() and implement that for ExternalMetricInfo.
// // errorVal := metricInfo.String()
// errorVal := "something"
// glog.Errorf("unable to construct query for metric %s: %v", errorVal, err)
// return "", false
// }
// return query, true
}
func (r *basicSeriesRegistry) MatchValuesToNames(metricInfo provider.CustomMetricInfo, values pmodel.Vector) (matchedValues map[string]pmodel.SampleValue, found bool) {
r.mu.RLock()
defer r.mu.RUnlock()