Stubbing out metric converters.

This commit is contained in:
Tony Compton 2018-06-28 22:08:21 -04:00
parent b3d99534a8
commit a69a5cbbcc
5 changed files with 213 additions and 30 deletions

View file

@ -1,29 +1,14 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package provider
import (
"context"
"fmt"
"time"
pmodel "github.com/prometheus/common/model"
conv "github.com/directxman12/k8s-prometheus-adapter/pkg/custom-provider/metric-converter"
"github.com/kubernetes-incubator/custom-metrics-apiserver/pkg/provider"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/dynamic"
@ -32,16 +17,22 @@ import (
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
)
//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.
type externalPrometheusProvider struct {
mapper apimeta.RESTMapper
kubeClient dynamic.Interface
promClient prom.Client
queryBuilder ExternalMetricQueryBuilder
mapper apimeta.RESTMapper
kubeClient dynamic.Interface
promClient prom.Client
queryBuilder ExternalMetricQueryBuilder
metricConverter conv.MetricConverter
SeriesRegistry
}
@ -52,7 +43,8 @@ type externalPrometheusProvider struct {
//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.
func NewExternalPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.Interface, promClient prom.Client, namers []MetricNamer, updateInterval time.Duration, queryBuilder ExternalMetricQueryBuilder) (provider.ExternalMetricsProvider, Runnable) {
func NewExternalPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.Interface, promClient prom.Client, namers []MetricNamer, updateInterval time.Duration, queryBuilder ExternalMetricQueryBuilder, metricConverter conv.MetricConverter) (provider.ExternalMetricsProvider, Runnable) {
lister := &cachingMetricsLister{
updateInterval: updateInterval,
promClient: promClient,
@ -64,9 +56,10 @@ func NewExternalPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic
}
return &externalPrometheusProvider{
mapper: mapper,
kubeClient: kubeClient,
promClient: promClient,
mapper: mapper,
kubeClient: kubeClient,
promClient: promClient,
metricConverter: metricConverter,
SeriesRegistry: lister,
}, lister
@ -79,12 +72,13 @@ func (p *externalPrometheusProvider) GetExternalMetric(namespace string, metricN
//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)
//TODO: Only here to stop compiler issues in this incomplete code.
fmt.Printf("%s, %s", queryResults, err)
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
}
//TODO: Check for errors. See what the custromPrometheusProvider does for errors.
//TODO: Adapt the results in queryResults to the appropriate return type.
return nil, nil
return p.metricConverter.Convert(queryResults)
}
func (p *externalPrometheusProvider) ListAllExternalMetrics() []provider.ExternalMetricInfo {

View 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, nil
}

View file

@ -0,0 +1,47 @@
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
}
//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")
}

View file

@ -0,0 +1,68 @@
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) {
tempWindow := int64(0)
result := external_metrics.ExternalMetricValueList{
//TODO: Where should all of these values come from?
TypeMeta: metav1.TypeMeta{
Kind: "?",
APIVersion: "?",
},
ListMeta: metav1.ListMeta{
SelfLink: "?",
ResourceVersion: "?",
Continue: "?",
},
Items: []external_metrics.ExternalMetricValue{
external_metrics.ExternalMetricValue{
TypeMeta: metav1.TypeMeta{
Kind: "?",
APIVersion: "?",
},
//TODO: Carry forward the metric name so we can set it here.
MetricName: "?",
Timestamp: metav1.Time{
input.Timestamp.Time(),
},
//TODO: Carry forward some information about our configuration so we can provide it here.
WindowSeconds: &tempWindow,
//TODO: Jump through the necessary hoops to convert our number into the proper type.
Value: resource.Quantity{},
},
},
}
return &result, nil
}

View 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 vectorConverter struct {
}
//NewVectorConverter creates a VectorConverter capable of converting
//vector Prometheus query results into external metric types.
func NewVectorConverter() MetricConverter {
return &vectorConverter{}
}
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) {
//TODO: Implementation.
return nil, nil
}