Re-implementing changes on top of the latest master.

This commit is contained in:
Tony Compton 2018-06-27 17:29:49 -04:00
parent 7b606a79fc
commit e9af0455ba
5 changed files with 181 additions and 16 deletions

15
Gopkg.lock generated
View file

@ -68,6 +68,19 @@
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/directxman12/k8s-prometheus-adapter"
packages = [
"cmd/adapter/app",
"cmd/config-gen/utils",
"pkg/client",
"pkg/client/metrics",
"pkg/config",
"pkg/custom-provider"
]
revision = "7b606a79fc2fdc4246e455e8f28503e0b4807a92"
[[projects]]
name = "github.com/elazarl/go-bindata-assetfs"
packages = ["."]
@ -802,6 +815,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "922da691d7be0fa3bde2ab628c629fea6718792cb234a2e5c661a193f0545d6f"
inputs-digest = "66b8ba4b829725e88ff6ba39c022bdf9670bdffa53ef9f8094c84e0c1447d2db"
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -189,7 +189,7 @@ func (o PrometheusAdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-c
return fmt.Errorf("unable to construct naming scheme from metrics rules: %v", err)
}
cmProvider, runner := cmprov.NewPrometheusProvider(dynamicMapper, dynamicClient, promClient, namers, o.MetricsRelistInterval)
cmProvider, runner := cmprov.NewCustomPrometheusProvider(dynamicMapper, dynamicClient, promClient, namers, o.MetricsRelistInterval)
runner.RunUntil(stopCh)
server, err := config.Complete().New("prometheus-custom-metrics-adapter", cmProvider, nil)

View file

@ -48,7 +48,7 @@ type Runnable interface {
RunUntil(stopChan <-chan struct{})
}
type prometheusProvider struct {
type customPrometheusProvider struct {
mapper apimeta.RESTMapper
kubeClient dynamic.Interface
promClient prom.Client
@ -56,7 +56,7 @@ type prometheusProvider struct {
SeriesRegistry
}
func NewPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.Interface, promClient prom.Client, namers []MetricNamer, updateInterval time.Duration) (provider.CustomMetricsProvider, Runnable) {
func NewCustomPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.Interface, promClient prom.Client, namers []MetricNamer, updateInterval time.Duration) (provider.CustomMetricsProvider, Runnable) {
lister := &cachingMetricsLister{
updateInterval: updateInterval,
promClient: promClient,
@ -67,7 +67,7 @@ func NewPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.Interfa
},
}
return &prometheusProvider{
return &customPrometheusProvider{
mapper: mapper,
kubeClient: kubeClient,
promClient: promClient,
@ -76,7 +76,7 @@ func NewPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.Interfa
}, lister
}
func (p *prometheusProvider) metricFor(value pmodel.SampleValue, groupResource schema.GroupResource, namespace string, name string, metricName string) (*custom_metrics.MetricValue, error) {
func (p *customPrometheusProvider) metricFor(value pmodel.SampleValue, groupResource schema.GroupResource, namespace string, name string, metricName string) (*custom_metrics.MetricValue, error) {
kind, err := p.mapper.KindFor(groupResource.WithVersion(""))
if err != nil {
return nil, err
@ -95,7 +95,7 @@ func (p *prometheusProvider) metricFor(value pmodel.SampleValue, groupResource s
}, nil
}
func (p *prometheusProvider) metricsFor(valueSet pmodel.Vector, info provider.CustomMetricInfo, list runtime.Object) (*custom_metrics.MetricValueList, error) {
func (p *customPrometheusProvider) metricsFor(valueSet pmodel.Vector, info provider.CustomMetricInfo, list runtime.Object) (*custom_metrics.MetricValueList, error) {
if !apimeta.IsListType(list) {
return nil, apierr.NewInternalError(fmt.Errorf("result of label selector list operation was not a list"))
}
@ -129,7 +129,7 @@ func (p *prometheusProvider) metricsFor(valueSet pmodel.Vector, info provider.Cu
}, nil
}
func (p *prometheusProvider) buildQuery(info provider.CustomMetricInfo, namespace string, names ...string) (pmodel.Vector, error) {
func (p *customPrometheusProvider) buildQuery(info provider.CustomMetricInfo, namespace string, names ...string) (pmodel.Vector, error) {
query, found := p.QueryForMetric(info, namespace, names...)
if !found {
return nil, provider.NewMetricNotFoundError(info.GroupResource, info.Metric)
@ -151,7 +151,7 @@ func (p *prometheusProvider) buildQuery(info provider.CustomMetricInfo, namespac
return *queryResults.Vector, nil
}
func (p *prometheusProvider) getSingle(info provider.CustomMetricInfo, namespace, name string) (*custom_metrics.MetricValue, error) {
func (p *customPrometheusProvider) getSingle(info provider.CustomMetricInfo, namespace, name string) (*custom_metrics.MetricValue, error) {
queryResults, err := p.buildQuery(info, namespace, name)
if err != nil {
return nil, err
@ -179,7 +179,7 @@ func (p *prometheusProvider) getSingle(info provider.CustomMetricInfo, namespace
return p.metricFor(resultValue, info.GroupResource, "", name, info.Metric)
}
func (p *prometheusProvider) getMultiple(info provider.CustomMetricInfo, namespace string, selector labels.Selector) (*custom_metrics.MetricValueList, error) {
func (p *customPrometheusProvider) getMultiple(info provider.CustomMetricInfo, namespace string, selector labels.Selector) (*custom_metrics.MetricValueList, error) {
fullResources, err := p.mapper.ResourcesFor(info.GroupResource.WithVersion(""))
if err == nil && len(fullResources) == 0 {
err = fmt.Errorf("no fully versioned resources known for group-resource %v", info.GroupResource)
@ -225,7 +225,7 @@ func (p *prometheusProvider) getMultiple(info provider.CustomMetricInfo, namespa
return p.metricsFor(queryResults, info, matchingObjectsRaw)
}
func (p *prometheusProvider) GetRootScopedMetricByName(groupResource schema.GroupResource, name string, metricName string) (*custom_metrics.MetricValue, error) {
func (p *customPrometheusProvider) GetRootScopedMetricByName(groupResource schema.GroupResource, name string, metricName string) (*custom_metrics.MetricValue, error) {
info := provider.CustomMetricInfo{
GroupResource: groupResource,
Metric: metricName,
@ -235,7 +235,7 @@ func (p *prometheusProvider) GetRootScopedMetricByName(groupResource schema.Grou
return p.getSingle(info, "", name)
}
func (p *prometheusProvider) GetRootScopedMetricBySelector(groupResource schema.GroupResource, selector labels.Selector, metricName string) (*custom_metrics.MetricValueList, error) {
func (p *customPrometheusProvider) GetRootScopedMetricBySelector(groupResource schema.GroupResource, selector labels.Selector, metricName string) (*custom_metrics.MetricValueList, error) {
info := provider.CustomMetricInfo{
GroupResource: groupResource,
Metric: metricName,
@ -244,7 +244,7 @@ func (p *prometheusProvider) GetRootScopedMetricBySelector(groupResource schema.
return p.getMultiple(info, "", selector)
}
func (p *prometheusProvider) GetNamespacedMetricByName(groupResource schema.GroupResource, namespace string, name string, metricName string) (*custom_metrics.MetricValue, error) {
func (p *customPrometheusProvider) GetNamespacedMetricByName(groupResource schema.GroupResource, namespace string, name string, metricName string) (*custom_metrics.MetricValue, error) {
info := provider.CustomMetricInfo{
GroupResource: groupResource,
Metric: metricName,
@ -254,7 +254,7 @@ func (p *prometheusProvider) GetNamespacedMetricByName(groupResource schema.Grou
return p.getSingle(info, namespace, name)
}
func (p *prometheusProvider) GetNamespacedMetricBySelector(groupResource schema.GroupResource, namespace string, selector labels.Selector, metricName string) (*custom_metrics.MetricValueList, error) {
func (p *customPrometheusProvider) GetNamespacedMetricBySelector(groupResource schema.GroupResource, namespace string, selector labels.Selector, metricName string) (*custom_metrics.MetricValueList, error) {
info := provider.CustomMetricInfo{
GroupResource: groupResource,
Metric: metricName,

View file

@ -95,7 +95,7 @@ func setupPrometheusProvider(t *testing.T) (provider.CustomMetricsProvider, *fak
namers, err := NamersFromConfig(cfg, restMapper())
require.NoError(t, err)
prov, _ := NewPrometheusProvider(restMapper(), fakeKubeClient, fakeProm, namers, fakeProviderUpdateInterval)
prov, _ := NewCustomPrometheusProvider(restMapper(), fakeKubeClient, fakeProm, namers, fakeProviderUpdateInterval)
containerSel := prom.MatchSeries("", prom.NameMatches("^container_.*"), prom.LabelNeq("container_name", "POD"), prom.LabelNeq("namespace", ""), prom.LabelNeq("pod_name", ""))
namespacedSel := prom.MatchSeries("", prom.LabelNeq("namespace", ""), prom.NameNotMatches("^container_.*"))
@ -141,7 +141,7 @@ func TestListAllMetrics(t *testing.T) {
fakeProm.acceptibleInterval = pmodel.Interval{Start: startTime, End: 0}
// update the metrics (without actually calling RunUntil, so we can avoid timing issues)
lister := prov.(*prometheusProvider).SeriesRegistry.(*cachingMetricsLister)
lister := prov.(*customPrometheusProvider).SeriesRegistry.(*cachingMetricsLister)
require.NoError(t, lister.updateMetrics())
// list/sort the metrics

View file

@ -0,0 +1,152 @@
/*
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 (
"fmt"
s "strings"
"time"
"github.com/kubernetes-incubator/custom-metrics-apiserver/pkg/provider"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/dynamic"
"k8s.io/metrics/pkg/apis/external_metrics"
prom "github.com/directxman12/k8s-prometheus-adapter/pkg/client"
)
type externalPrometheusProvider struct {
mapper apimeta.RESTMapper
kubeClient dynamic.Interface
promClient prom.Client
SeriesRegistry
}
func NewExternalPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.Interface, promClient prom.Client, namers []MetricNamer, updateInterval time.Duration) (provider.ExternalMetricsProvider, Runnable) {
lister := &cachingMetricsLister{
updateInterval: updateInterval,
promClient: promClient,
namers: namers,
SeriesRegistry: &basicSeriesRegistry{
mapper: mapper,
},
}
return &externalPrometheusProvider{
mapper: mapper,
kubeClient: kubeClient,
promClient: promClient,
SeriesRegistry: lister,
}, lister
}
func (p *externalPrometheusProvider) GetExternalMetric(namespace string, metricName string, metricSelector labels.Selector) (*external_metrics.ExternalMetricValueList, error) {
//TODO: Steps
//1. Generate a Prometheus Query.
// Something like my_metric{namespace="namespace" some_label="some_value"}
//2. Send that query to Prometheus.
//3. Adapt the results.
//The query generation for external metrics is much more straightforward
//than for custom metrics because no renaming is applied.
//So we'll just start with some simple string operations and see how far that gets us.
//Then I'll circle back and figure out how much code reuse I can get out of the original implementation.
namespaceSelector := p.makeLabelFilter("namespace", "=", namespace)
otherSelectors := p.convertSelectors(metricSelector)
finalTargets := append([]string{namespaceSelector}, otherSelectors...)
//TODO: Only here to stop compiler issues in this incomplete code.
fmt.Printf("len=%d", len(finalTargets))
//TODO: Construct a real result.
return nil, nil
}
func (p *externalPrometheusProvider) makeLabelFilter(labelName string, operator string, targetValue string) string {
return fmt.Sprintf("%s%s\"%s\"", labelName, operator, targetValue)
}
func (p *externalPrometheusProvider) 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 *externalPrometheusProvider) 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 *externalPrometheusProvider) selectOperator(operator selection.Operator, valueCount int) string {
if valueCount > 1 {
return p.selectRegexOperator(operator)
}
return p.selectSingleValueOperator(operator)
}
func (p *externalPrometheusProvider) 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 *externalPrometheusProvider) 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 "="
}
func (p *externalPrometheusProvider) ListAllExternalMetrics() []provider.ExternalMetricInfo {
//TODO: Provide a real response.
return nil
}