mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-07 22:25:03 +00:00
Fixing some refactoring bugs, first half-decent external metrics attempt.
Fixed: * `basicMetricLister` wasn't applying the appropriate start time because I had forgotten to set the `lookback`. There are still a number of issues: * The `externalPrometheusProvider` is not hooked up to the web application yet, so it doesn't serve requests. * The namespace and label approach used in `external_info_map.go` is horrifically incorrect. It doesn't appropriately store multiple series with the same name but different labels. * The configuration is still not updated to appropriately handle external metrics, it's sort of half-piggy-backing on the pre-existing work.
This commit is contained in:
parent
056cb7f7f2
commit
9641e70005
14 changed files with 637 additions and 77 deletions
37
pkg/custom-provider/metric-converter/matrix_converter.go
Normal file
37
pkg/custom-provider/metric-converter/matrix_converter.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
|
||||
"github.com/prometheus/common/model"
|
||||
"k8s.io/metrics/pkg/apis/external_metrics"
|
||||
)
|
||||
|
||||
type matrixConverter struct {
|
||||
}
|
||||
|
||||
//NewMatrixConverter creates a MatrixConverter capable of converting
|
||||
//matrix Prometheus query results into external metric types.
|
||||
func NewMatrixConverter() MetricConverter {
|
||||
return &matrixConverter{}
|
||||
}
|
||||
|
||||
func (c *matrixConverter) Convert(queryResult prom.QueryResult) (*external_metrics.ExternalMetricValueList, error) {
|
||||
if queryResult.Type != model.ValMatrix {
|
||||
return nil, errors.New("matrixConverter can only convert scalar query results")
|
||||
}
|
||||
|
||||
toConvert := queryResult.Matrix
|
||||
|
||||
if toConvert == nil {
|
||||
return nil, errors.New("the provided input did not contain matrix query results")
|
||||
}
|
||||
|
||||
return c.convert(toConvert)
|
||||
}
|
||||
|
||||
func (c *matrixConverter) convert(result *model.Matrix) (*external_metrics.ExternalMetricValueList, error) {
|
||||
//TODO: Implementation.
|
||||
return nil, errors.New("converting Matrix results is not yet supported")
|
||||
}
|
||||
52
pkg/custom-provider/metric-converter/metric_converter.go
Normal file
52
pkg/custom-provider/metric-converter/metric_converter.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
|
||||
"github.com/prometheus/common/model"
|
||||
"k8s.io/metrics/pkg/apis/external_metrics"
|
||||
)
|
||||
|
||||
//MetricConverter provides a unified interface for converting the results of
|
||||
//Prometheus queries into external metric types.
|
||||
type MetricConverter interface {
|
||||
Convert(queryResult prom.QueryResult) (*external_metrics.ExternalMetricValueList, error)
|
||||
}
|
||||
|
||||
type metricConverter struct {
|
||||
scalarConverter MetricConverter
|
||||
vectorConverter MetricConverter
|
||||
matrixConverter MetricConverter
|
||||
}
|
||||
|
||||
func DefaultMetricConverter() MetricConverter {
|
||||
sampleConverter := NewSampleConverter()
|
||||
return NewMetricConverter(NewScalarConverter(), NewVectorConverter(&sampleConverter), NewMatrixConverter())
|
||||
}
|
||||
|
||||
//NewMetricConverter creates a MetricCoverter, capable of converting any of the three metric types
|
||||
//returned by the Prometheus client into external metrics types.
|
||||
func NewMetricConverter(scalar MetricConverter, vector MetricConverter, matrix MetricConverter) MetricConverter {
|
||||
return &metricConverter{
|
||||
scalarConverter: scalar,
|
||||
vectorConverter: vector,
|
||||
matrixConverter: matrix,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *metricConverter) Convert(queryResult prom.QueryResult) (*external_metrics.ExternalMetricValueList, error) {
|
||||
if queryResult.Type == model.ValScalar {
|
||||
return c.scalarConverter.Convert(queryResult)
|
||||
}
|
||||
|
||||
if queryResult.Type == model.ValVector {
|
||||
return c.vectorConverter.Convert(queryResult)
|
||||
}
|
||||
|
||||
if queryResult.Type == model.ValMatrix {
|
||||
return c.matrixConverter.Convert(queryResult)
|
||||
}
|
||||
|
||||
return nil, errors.New("encountered an unexpected query result type")
|
||||
}
|
||||
52
pkg/custom-provider/metric-converter/sample_converter.go
Normal file
52
pkg/custom-provider/metric-converter/sample_converter.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"github.com/prometheus/common/model"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/metrics/pkg/apis/external_metrics"
|
||||
)
|
||||
|
||||
type sampleConverter struct {
|
||||
}
|
||||
|
||||
//SampleConverter is capable of translating Prometheus Sample objects
|
||||
//into ExternamMetricValue objects.
|
||||
type SampleConverter interface {
|
||||
Convert(sample *model.Sample) (*external_metrics.ExternalMetricValue, error)
|
||||
}
|
||||
|
||||
//NewSampleConverter creates a SampleConverter capable of translating Prometheus Sample objects
|
||||
//into ExternamMetricValue objects.
|
||||
func NewSampleConverter() SampleConverter {
|
||||
return &sampleConverter{}
|
||||
}
|
||||
|
||||
func (c *sampleConverter) Convert(sample *model.Sample) (*external_metrics.ExternalMetricValue, error) {
|
||||
labels := c.convertLabels(sample.Metric)
|
||||
|
||||
singleMetric := external_metrics.ExternalMetricValue{
|
||||
MetricName: string(sample.Metric[model.LabelName("__name__")]),
|
||||
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),
|
||||
MetricLabels: labels,
|
||||
}
|
||||
|
||||
//TODO: Actual errors?
|
||||
return &singleMetric, nil
|
||||
}
|
||||
|
||||
func (c *sampleConverter) convertLabels(inLabels model.Metric) map[string]string {
|
||||
numLabels := len(inLabels)
|
||||
outLabels := make(map[string]string, numLabels)
|
||||
for labelName, labelVal := range inLabels {
|
||||
outLabels[string(labelName)] = string(labelVal)
|
||||
}
|
||||
|
||||
return outLabels
|
||||
}
|
||||
55
pkg/custom-provider/metric-converter/scalar_converter.go
Normal file
55
pkg/custom-provider/metric-converter/scalar_converter.go
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
|
||||
"github.com/prometheus/common/model"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/metrics/pkg/apis/external_metrics"
|
||||
)
|
||||
|
||||
type scalarConverter struct {
|
||||
}
|
||||
|
||||
//NewScalarConverter creates a ScalarConverter capable of converting
|
||||
//scalar Prometheus query results into external metric types.
|
||||
func NewScalarConverter() MetricConverter {
|
||||
return &scalarConverter{}
|
||||
}
|
||||
|
||||
func (c *scalarConverter) Convert(queryResult prom.QueryResult) (*external_metrics.ExternalMetricValueList, error) {
|
||||
if queryResult.Type != model.ValScalar {
|
||||
return nil, errors.New("scalarConverter can only convert scalar query results")
|
||||
}
|
||||
|
||||
toConvert := queryResult.Scalar
|
||||
|
||||
if toConvert == nil {
|
||||
return nil, errors.New("the provided input did not contain scalar query results")
|
||||
}
|
||||
|
||||
return c.convert(toConvert)
|
||||
}
|
||||
|
||||
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),
|
||||
},
|
||||
},
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
58
pkg/custom-provider/metric-converter/vector_converter.go
Normal file
58
pkg/custom-provider/metric-converter/vector_converter.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
|
||||
"github.com/prometheus/common/model"
|
||||
"k8s.io/metrics/pkg/apis/external_metrics"
|
||||
)
|
||||
|
||||
type vectorConverter struct {
|
||||
SampleConverter SampleConverter
|
||||
}
|
||||
|
||||
//NewVectorConverter creates a VectorConverter capable of converting
|
||||
//vector Prometheus query results into external metric types.
|
||||
func NewVectorConverter(sampleConverter *SampleConverter) MetricConverter {
|
||||
return &vectorConverter{
|
||||
SampleConverter: *sampleConverter,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *vectorConverter) Convert(queryResult prom.QueryResult) (*external_metrics.ExternalMetricValueList, error) {
|
||||
if queryResult.Type != model.ValVector {
|
||||
return nil, errors.New("vectorConverter can only convert scalar query results")
|
||||
}
|
||||
|
||||
toConvert := *queryResult.Vector
|
||||
|
||||
if toConvert == nil {
|
||||
return nil, errors.New("the provided input did not contain vector query results")
|
||||
}
|
||||
|
||||
return c.convert(toConvert)
|
||||
}
|
||||
|
||||
func (c *vectorConverter) convert(result model.Vector) (*external_metrics.ExternalMetricValueList, error) {
|
||||
items := []external_metrics.ExternalMetricValue{}
|
||||
metricValueList := external_metrics.ExternalMetricValueList{
|
||||
Items: items,
|
||||
}
|
||||
|
||||
numSamples := result.Len()
|
||||
if numSamples == 0 {
|
||||
return &metricValueList, nil
|
||||
}
|
||||
|
||||
for _, val := range result {
|
||||
//TODO: Care about potential errors here.
|
||||
singleMetric, _ := c.SampleConverter.Convert(val)
|
||||
items = append(items, *singleMetric)
|
||||
}
|
||||
|
||||
metricValueList = external_metrics.ExternalMetricValueList{
|
||||
Items: items,
|
||||
}
|
||||
return &metricValueList, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue