mirror of
https://github.com/zalando-incubator/kube-metrics-adapter.git
synced 2025-09-02 12:04:46 +00:00
Namespace external metrics (#259)
Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>
This commit is contained in:

committed by
GitHub

parent
942e753f87
commit
b7aa886546
@@ -33,7 +33,7 @@ func NewAWSCollectorPlugin(sessions map[string]*session.Session) *AWSCollectorPl
|
||||
|
||||
// NewCollector initializes a new skipper collector from the specified HPA.
|
||||
func (c *AWSCollectorPlugin) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
|
||||
return NewAWSSQSCollector(c.sessions, config, interval)
|
||||
return NewAWSSQSCollector(c.sessions, hpa, config, interval)
|
||||
}
|
||||
|
||||
type AWSSQSCollector struct {
|
||||
@@ -42,11 +42,12 @@ type AWSSQSCollector struct {
|
||||
region string
|
||||
queueURL string
|
||||
queueName string
|
||||
namespace string
|
||||
metric autoscalingv2.MetricIdentifier
|
||||
metricType autoscalingv2.MetricSourceType
|
||||
}
|
||||
|
||||
func NewAWSSQSCollector(sessions map[string]*session.Session, config *MetricConfig, interval time.Duration) (*AWSSQSCollector, error) {
|
||||
func NewAWSSQSCollector(sessions map[string]*session.Session, hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (*AWSSQSCollector, error) {
|
||||
if config.Metric.Selector == nil {
|
||||
return nil, fmt.Errorf("selector for queue is not specified")
|
||||
}
|
||||
@@ -80,6 +81,7 @@ func NewAWSSQSCollector(sessions map[string]*session.Session, config *MetricConf
|
||||
interval: interval,
|
||||
queueURL: aws.StringValue(resp.QueueUrl),
|
||||
queueName: name,
|
||||
namespace: hpa.Namespace,
|
||||
metric: config.Metric,
|
||||
metricType: config.Type,
|
||||
}, nil
|
||||
@@ -103,6 +105,7 @@ func (c *AWSSQSCollector) GetMetrics() ([]CollectedMetric, error) {
|
||||
}
|
||||
|
||||
metricValue := CollectedMetric{
|
||||
Namespace: c.namespace,
|
||||
Type: c.metricType,
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: c.metric.Name,
|
||||
|
@@ -178,6 +178,7 @@ type MetricTypeName struct {
|
||||
|
||||
type CollectedMetric struct {
|
||||
Type autoscalingv2.MetricSourceType
|
||||
Namespace string
|
||||
Custom custom_metrics.MetricValue
|
||||
External external_metrics.ExternalMetricValue
|
||||
}
|
||||
|
@@ -27,8 +27,10 @@ func NewHTTPCollectorPlugin() (*HTTPCollectorPlugin, error) {
|
||||
return &HTTPCollectorPlugin{}, nil
|
||||
}
|
||||
|
||||
func (p *HTTPCollectorPlugin) NewCollector(_ *v2beta2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
|
||||
collector := &HTTPCollector{}
|
||||
func (p *HTTPCollectorPlugin) NewCollector(hpa *v2beta2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
|
||||
collector := &HTTPCollector{
|
||||
namespace: hpa.Namespace,
|
||||
}
|
||||
var (
|
||||
value string
|
||||
ok bool
|
||||
@@ -74,6 +76,7 @@ func (p *HTTPCollectorPlugin) NewCollector(_ *v2beta2.HorizontalPodAutoscaler, c
|
||||
type HTTPCollector struct {
|
||||
endpoint *url.URL
|
||||
interval time.Duration
|
||||
namespace string
|
||||
metricType v2beta2.MetricSourceType
|
||||
metricsGetter *httpmetrics.JSONPathMetricsGetter
|
||||
metric v2beta2.MetricIdentifier
|
||||
@@ -86,6 +89,7 @@ func (c *HTTPCollector) GetMetrics() ([]CollectedMetric, error) {
|
||||
}
|
||||
|
||||
value := CollectedMetric{
|
||||
Namespace: c.namespace,
|
||||
Type: c.metricType,
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: c.metric.Name,
|
||||
|
@@ -8,6 +8,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/api/autoscaling/v2beta2"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2beta2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
@@ -60,7 +62,12 @@ func TestHTTPCollector(t *testing.T) {
|
||||
plugin, err := NewHTTPCollectorPlugin()
|
||||
require.NoError(t, err)
|
||||
testConfig := makeTestHTTPCollectorConfig(testServer, tc.aggregator)
|
||||
collector, err := plugin.NewCollector(nil, testConfig, testInterval)
|
||||
hpa := &autoscalingv2.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
collector, err := plugin.NewCollector(hpa, testConfig, testInterval)
|
||||
require.NoError(t, err)
|
||||
metrics, err := collector.GetMetrics()
|
||||
require.NoError(t, err)
|
||||
|
@@ -40,7 +40,7 @@ func NewInfluxDBCollectorPlugin(client kubernetes.Interface, address, token, org
|
||||
}
|
||||
|
||||
func (p *InfluxDBCollectorPlugin) NewCollector(hpa *v2beta2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
|
||||
return NewInfluxDBCollector(p.address, p.token, p.org, config, interval)
|
||||
return NewInfluxDBCollector(hpa, p.address, p.token, p.org, config, interval)
|
||||
}
|
||||
|
||||
type InfluxDBCollector struct {
|
||||
@@ -53,13 +53,15 @@ type InfluxDBCollector struct {
|
||||
metric autoscalingv2.MetricIdentifier
|
||||
metricType autoscalingv2.MetricSourceType
|
||||
query string
|
||||
namespace string
|
||||
}
|
||||
|
||||
func NewInfluxDBCollector(address string, token string, org string, config *MetricConfig, interval time.Duration) (*InfluxDBCollector, error) {
|
||||
func NewInfluxDBCollector(hpa *v2beta2.HorizontalPodAutoscaler, address string, token string, org string, config *MetricConfig, interval time.Duration) (*InfluxDBCollector, error) {
|
||||
collector := &InfluxDBCollector{
|
||||
interval: interval,
|
||||
metric: config.Metric,
|
||||
metricType: config.Type,
|
||||
namespace: hpa.Namespace,
|
||||
}
|
||||
switch configType := config.Type; configType {
|
||||
case autoscalingv2.ObjectMetricSourceType:
|
||||
@@ -135,6 +137,7 @@ func (c *InfluxDBCollector) GetMetrics() ([]CollectedMetric, error) {
|
||||
return nil, err
|
||||
}
|
||||
cm := CollectedMetric{
|
||||
Namespace: c.namespace,
|
||||
Type: c.metricType,
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: c.metric.Name,
|
||||
|
@@ -6,10 +6,17 @@ import (
|
||||
"time"
|
||||
|
||||
"k8s.io/api/autoscaling/v2beta2"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2beta2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestInfluxDBCollector_New(t *testing.T) {
|
||||
hpa := &autoscalingv2.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
t.Run("simple", func(t *testing.T) {
|
||||
m := &MetricConfig{
|
||||
MetricTypeName: MetricTypeName{
|
||||
@@ -32,7 +39,7 @@ func TestInfluxDBCollector_New(t *testing.T) {
|
||||
"query-name": "range2m",
|
||||
},
|
||||
}
|
||||
c, err := NewInfluxDBCollector("http://localhost:9999", "secret", "deadbeef", m, time.Second)
|
||||
c, err := NewInfluxDBCollector(hpa, "http://localhost:9999", "secret", "deadbeef", m, time.Second)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -73,7 +80,7 @@ func TestInfluxDBCollector_New(t *testing.T) {
|
||||
"query-name": "range3m",
|
||||
},
|
||||
}
|
||||
c, err := NewInfluxDBCollector("http://localhost:8888", "secret", "deadbeef", m, time.Second)
|
||||
c, err := NewInfluxDBCollector(hpa, "http://localhost:8888", "secret", "deadbeef", m, time.Second)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -143,7 +150,7 @@ func TestInfluxDBCollector_New(t *testing.T) {
|
||||
CollectorType: "influxdb",
|
||||
Config: tc.config,
|
||||
}
|
||||
_, err := NewInfluxDBCollector("http://localhost:9999", "secret", "deadbeef", m, time.Second)
|
||||
_, err := NewInfluxDBCollector(hpa, "http://localhost:9999", "secret", "deadbeef", m, time.Second)
|
||||
if err == nil {
|
||||
t.Fatal("expected error got none")
|
||||
}
|
||||
|
@@ -118,6 +118,7 @@ func (c *PodCollector) getPodMetric(pod corev1.Pod, ch chan CollectedMetric, err
|
||||
}
|
||||
|
||||
ch <- CollectedMetric{
|
||||
Namespace: c.namespace,
|
||||
Type: c.metricType,
|
||||
Custom: custom_metrics.MetricValue{
|
||||
DescribedObject: custom_metrics.ObjectReference{
|
||||
|
@@ -174,6 +174,7 @@ func (c *PrometheusCollector) GetMetrics() ([]CollectedMetric, error) {
|
||||
switch c.metricType {
|
||||
case autoscalingv2.ObjectMetricSourceType:
|
||||
metricValue = CollectedMetric{
|
||||
Namespace: c.hpa.Namespace,
|
||||
Type: c.metricType,
|
||||
Custom: custom_metrics.MetricValue{
|
||||
DescribedObject: c.objectReference,
|
||||
@@ -184,6 +185,7 @@ func (c *PrometheusCollector) GetMetrics() ([]CollectedMetric, error) {
|
||||
}
|
||||
case autoscalingv2.ExternalMetricSourceType:
|
||||
metricValue = CollectedMetric{
|
||||
Namespace: c.hpa.Namespace,
|
||||
Type: c.metricType,
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: c.metric.Name,
|
||||
|
@@ -43,7 +43,7 @@ func NewZMONCollectorPlugin(zmon zmon.ZMON) (*ZMONCollectorPlugin, error) {
|
||||
|
||||
// NewCollector initializes a new ZMON collector from the specified HPA.
|
||||
func (c *ZMONCollectorPlugin) NewCollector(hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
|
||||
return NewZMONCollector(c.zmon, config, interval)
|
||||
return NewZMONCollector(c.zmon, hpa, config, interval)
|
||||
}
|
||||
|
||||
// ZMONCollector defines a collector that is able to collect metrics from ZMON.
|
||||
@@ -57,10 +57,11 @@ type ZMONCollector struct {
|
||||
aggregators []string
|
||||
metric autoscalingv2.MetricIdentifier
|
||||
metricType autoscalingv2.MetricSourceType
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewZMONCollector initializes a new ZMONCollector.
|
||||
func NewZMONCollector(zmon zmon.ZMON, config *MetricConfig, interval time.Duration) (*ZMONCollector, error) {
|
||||
func NewZMONCollector(zmon zmon.ZMON, hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (*ZMONCollector, error) {
|
||||
if config.Metric.Selector == nil {
|
||||
return nil, fmt.Errorf("selector for zmon-check is not specified")
|
||||
}
|
||||
@@ -117,6 +118,7 @@ func NewZMONCollector(zmon zmon.ZMON, config *MetricConfig, interval time.Durati
|
||||
aggregators: aggregators,
|
||||
metric: config.Metric,
|
||||
metricType: config.Type,
|
||||
namespace: hpa.Namespace,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -136,6 +138,7 @@ func (c *ZMONCollector) GetMetrics() ([]CollectedMetric, error) {
|
||||
point := dataPoints[len(dataPoints)-1]
|
||||
|
||||
metricValue := CollectedMetric{
|
||||
Namespace: c.namespace,
|
||||
Type: c.metricType,
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: c.metric.Name,
|
||||
|
@@ -96,6 +96,7 @@ func TestZMONCollectorGetMetrics(tt *testing.T) {
|
||||
},
|
||||
collectedMetrics: []CollectedMetric{
|
||||
{
|
||||
Namespace: "default",
|
||||
Type: config.Type,
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: config.Metric.Name,
|
||||
@@ -115,7 +116,13 @@ func TestZMONCollectorGetMetrics(tt *testing.T) {
|
||||
dataPoints: ti.dataPoints,
|
||||
}
|
||||
|
||||
zmonCollector, err := NewZMONCollector(z, config, 1*time.Second)
|
||||
hpa := &autoscalingv2.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
zmonCollector, err := NewZMONCollector(z, hpa, config, 1*time.Second)
|
||||
require.NoError(t, err)
|
||||
|
||||
metrics, _ := zmonCollector.GetMetrics()
|
||||
|
@@ -129,6 +129,7 @@ func (p *HPAProvider) updateHPAs() error {
|
||||
newHPAs := 0
|
||||
|
||||
for _, hpa := range hpas.Items {
|
||||
hpa := *hpa.DeepCopy()
|
||||
resourceRef := resourceReference{
|
||||
Name: hpa.Name,
|
||||
Namespace: hpa.Namespace,
|
||||
@@ -246,7 +247,8 @@ func (p *HPAProvider) collectMetrics(ctx context.Context) {
|
||||
value.Custom.DescribedObject.Name,
|
||||
)
|
||||
case autoscalingv2.ExternalMetricSourceType:
|
||||
p.logger.Infof("Collected new external metric '%s' (%s) [%s]",
|
||||
p.logger.Infof("Collected new external metric '%s/%s' (%s) [%s]",
|
||||
value.Namespace,
|
||||
value.External.MetricName,
|
||||
value.External.Value.String(),
|
||||
labels.Set(value.External.MetricLabels).String(),
|
||||
|
@@ -31,8 +31,10 @@ type externalMetricsStoredMetric struct {
|
||||
|
||||
// MetricStore is a simple in-memory Metrics Store for HPA metrics.
|
||||
type MetricStore struct {
|
||||
// metricName -> referencedResource -> objectNamespace -> objectName -> metric
|
||||
customMetricsStore map[string]map[schema.GroupResource]map[string]map[string]customMetricsStoredMetric
|
||||
externalMetricsStore map[string]map[string]externalMetricsStoredMetric
|
||||
// namespace -> metricName -> labels -> metric
|
||||
externalMetricsStore map[string]map[string]map[string]externalMetricsStoredMetric
|
||||
metricsTTLCalculator func() time.Time
|
||||
sync.RWMutex
|
||||
}
|
||||
@@ -41,7 +43,7 @@ type MetricStore struct {
|
||||
func NewMetricStore(ttlCalculator func() time.Time) *MetricStore {
|
||||
return &MetricStore{
|
||||
customMetricsStore: make(map[string]map[schema.GroupResource]map[string]map[string]customMetricsStoredMetric, 0),
|
||||
externalMetricsStore: make(map[string]map[string]externalMetricsStoredMetric, 0),
|
||||
externalMetricsStore: make(map[string]map[string]map[string]externalMetricsStoredMetric, 0),
|
||||
metricsTTLCalculator: ttlCalculator,
|
||||
}
|
||||
}
|
||||
@@ -52,7 +54,7 @@ func (s *MetricStore) Insert(value collector.CollectedMetric) {
|
||||
case autoscalingv2.ObjectMetricSourceType, autoscalingv2.PodsMetricSourceType:
|
||||
s.insertCustomMetric(value.Custom)
|
||||
case autoscalingv2.ExternalMetricSourceType:
|
||||
s.insertExternalMetric(value.External)
|
||||
s.insertExternalMetric(value.Namespace, value.External)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +122,7 @@ func (s *MetricStore) insertCustomMetric(value custom_metrics.MetricValue) {
|
||||
}
|
||||
|
||||
// insertExternalMetric inserts an external metric into the store.
|
||||
func (s *MetricStore) insertExternalMetric(metric external_metrics.ExternalMetricValue) {
|
||||
func (s *MetricStore) insertExternalMetric(namespace string, metric external_metrics.ExternalMetricValue) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
@@ -131,13 +133,21 @@ func (s *MetricStore) insertExternalMetric(metric external_metrics.ExternalMetri
|
||||
|
||||
labelsKey := hashLabelMap(metric.MetricLabels)
|
||||
|
||||
if metrics, ok := s.externalMetricsStore[metric.MetricName]; ok {
|
||||
metrics[labelsKey] = storedMetric
|
||||
if metrics, ok := s.externalMetricsStore[namespace]; ok {
|
||||
if labels, ok := metrics[metric.MetricName]; ok {
|
||||
labels[labelsKey] = storedMetric
|
||||
} else {
|
||||
s.externalMetricsStore[metric.MetricName] = map[string]externalMetricsStoredMetric{
|
||||
metrics[metric.MetricName] = map[string]externalMetricsStoredMetric{
|
||||
labelsKey: storedMetric,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s.externalMetricsStore[namespace] = map[string]map[string]externalMetricsStoredMetric{
|
||||
metric.MetricName: {
|
||||
labelsKey: storedMetric,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hashLabelMap converts a map into a sorted string to provide a stable
|
||||
@@ -250,10 +260,12 @@ func (s *MetricStore) GetExternalMetric(namespace string, selector labels.Select
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
if metrics, ok := s.externalMetricsStore[info.Metric]; ok {
|
||||
for _, metric := range metrics {
|
||||
if selector.Matches(labels.Set(metric.Value.MetricLabels)) {
|
||||
matchedMetrics = append(matchedMetrics, metric.Value)
|
||||
if metrics, ok := s.externalMetricsStore[namespace]; ok {
|
||||
if selectors, ok := metrics[info.Metric]; ok {
|
||||
for _, sel := range selectors {
|
||||
if selector.Matches(labels.Set(sel.Value.MetricLabels)) {
|
||||
matchedMetrics = append(matchedMetrics, sel.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,12 +280,14 @@ func (s *MetricStore) ListAllExternalMetrics() []provider.ExternalMetricInfo {
|
||||
|
||||
metricsInfo := make([]provider.ExternalMetricInfo, 0, len(s.externalMetricsStore))
|
||||
|
||||
for metricName := range s.externalMetricsStore {
|
||||
for _, metrics := range s.externalMetricsStore {
|
||||
for metricName := range metrics {
|
||||
info := provider.ExternalMetricInfo{
|
||||
Metric: metricName,
|
||||
}
|
||||
metricsInfo = append(metricsInfo, info)
|
||||
}
|
||||
}
|
||||
return metricsInfo
|
||||
}
|
||||
|
||||
@@ -306,14 +320,19 @@ func (s *MetricStore) RemoveExpired() {
|
||||
}
|
||||
|
||||
// cleanup external metrics
|
||||
for metricName, metrics := range s.externalMetricsStore {
|
||||
for k, metric := range metrics {
|
||||
for namespace, metrics := range s.externalMetricsStore {
|
||||
for metricName, selectors := range metrics {
|
||||
for k, metric := range selectors {
|
||||
if metric.TTL.Before(time.Now().UTC()) {
|
||||
delete(metrics, k)
|
||||
delete(selectors, k)
|
||||
}
|
||||
}
|
||||
if len(selectors) == 0 {
|
||||
delete(metrics, metricName)
|
||||
}
|
||||
}
|
||||
if len(metrics) == 0 {
|
||||
delete(s.externalMetricsStore, metricName)
|
||||
delete(s.externalMetricsStore, namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ func TestInternalMetricStorage(t *testing.T) {
|
||||
test string
|
||||
insert collector.CollectedMetric
|
||||
list []provider.CustomMetricInfo
|
||||
expectedFound bool
|
||||
byName struct {
|
||||
name types.NamespacedName
|
||||
info provider.CustomMetricInfo
|
||||
@@ -54,6 +55,7 @@ func TestInternalMetricStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedFound: true,
|
||||
list: []provider.CustomMetricInfo{
|
||||
{
|
||||
GroupResource: schema.GroupResource{},
|
||||
@@ -101,6 +103,7 @@ func TestInternalMetricStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedFound: true,
|
||||
list: []provider.CustomMetricInfo{
|
||||
{
|
||||
GroupResource: schema.GroupResource{
|
||||
@@ -156,6 +159,7 @@ func TestInternalMetricStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedFound: true,
|
||||
list: []provider.CustomMetricInfo{
|
||||
{
|
||||
GroupResource: schema.GroupResource{},
|
||||
@@ -202,6 +206,7 @@ func TestInternalMetricStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedFound: true,
|
||||
list: []provider.CustomMetricInfo{
|
||||
{
|
||||
GroupResource: schema.GroupResource{
|
||||
@@ -243,6 +248,63 @@ func TestInternalMetricStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: "get an Ingress metric from wrong namespace",
|
||||
insert: collector.CollectedMetric{
|
||||
Type: autoscalingv2.MetricSourceType("Object"),
|
||||
Custom: custom_metrics.MetricValue{
|
||||
Metric: newMetricIdentifier("metric-per-unit"),
|
||||
Value: *resource.NewQuantity(0, ""),
|
||||
DescribedObject: custom_metrics.ObjectReference{
|
||||
Name: "metricObject",
|
||||
Namespace: "right",
|
||||
Kind: "Ingress",
|
||||
APIVersion: "extensions/v1beta1",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedFound: false,
|
||||
list: []provider.CustomMetricInfo{
|
||||
{
|
||||
GroupResource: schema.GroupResource{
|
||||
Group: "extensions",
|
||||
Resource: "ingresses",
|
||||
},
|
||||
Namespaced: true,
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
},
|
||||
byName: struct {
|
||||
name types.NamespacedName
|
||||
info provider.CustomMetricInfo
|
||||
}{
|
||||
name: types.NamespacedName{Name: "metricObject", Namespace: "wrong"},
|
||||
info: provider.CustomMetricInfo{
|
||||
GroupResource: schema.GroupResource{
|
||||
Group: "extensions",
|
||||
Resource: "ingresses",
|
||||
},
|
||||
Namespaced: true,
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
},
|
||||
byLabel: struct {
|
||||
namespace string
|
||||
selector labels.Selector
|
||||
info provider.CustomMetricInfo
|
||||
}{
|
||||
namespace: "wrong",
|
||||
selector: labels.Everything(),
|
||||
info: provider.CustomMetricInfo{
|
||||
GroupResource: schema.GroupResource{
|
||||
Group: "extensions",
|
||||
Resource: "ingresses",
|
||||
},
|
||||
Namespaced: true,
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range metricStoreTests {
|
||||
@@ -261,14 +323,14 @@ func TestInternalMetricStorage(t *testing.T) {
|
||||
// Get the metric by name
|
||||
metric := metricsStore.GetMetricsByName(tc.byName.name, tc.byName.info)
|
||||
|
||||
if tc.insert.Custom != (custom_metrics.MetricValue{}) {
|
||||
if tc.expectedFound {
|
||||
require.Equal(t, tc.insert.Custom, *metric)
|
||||
metrics := metricsStore.GetMetricsBySelector(tc.byLabel.namespace, tc.byLabel.selector, tc.byLabel.info)
|
||||
require.Equal(t, tc.insert.Custom, metrics.Items[0])
|
||||
} else {
|
||||
require.Nil(t, metric)
|
||||
metrics := metricsStore.GetMetricsBySelector(tc.byLabel.namespace, tc.byLabel.selector, tc.byLabel.info)
|
||||
require.Nil(t, metrics)
|
||||
require.Len(t, metrics.Items, 0)
|
||||
}
|
||||
|
||||
})
|
||||
@@ -707,11 +769,39 @@ func TestExternalMetricStorage(t *testing.T) {
|
||||
namespace string
|
||||
selector labels.Selector
|
||||
info provider.ExternalMetricInfo
|
||||
}{namespace: "",
|
||||
}{
|
||||
namespace: "",
|
||||
selector: labels.Everything(),
|
||||
info: provider.ExternalMetricInfo{
|
||||
Metric: "metric-per-unit",
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: "insert/list/get an external metric with namespace",
|
||||
insert: collector.CollectedMetric{
|
||||
Namespace: "foo",
|
||||
Type: autoscalingv2.MetricSourceType("External"),
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: "metric-per-unit",
|
||||
Value: *resource.NewQuantity(0, ""),
|
||||
MetricLabels: map[string]string{"application": "some-app"},
|
||||
},
|
||||
},
|
||||
list: provider.ExternalMetricInfo{
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
get: struct {
|
||||
namespace string
|
||||
selector labels.Selector
|
||||
info provider.ExternalMetricInfo
|
||||
}{
|
||||
namespace: "foo",
|
||||
selector: labels.Everything(),
|
||||
info: provider.ExternalMetricInfo{
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -742,7 +832,8 @@ func TestMultipleExternalMetricStorage(t *testing.T) {
|
||||
var metricStoreTests = []struct {
|
||||
test string
|
||||
insert []collector.CollectedMetric
|
||||
list provider.ExternalMetricInfo
|
||||
expectedIdx int
|
||||
list []provider.ExternalMetricInfo
|
||||
get struct {
|
||||
namespace string
|
||||
selector labels.Selector
|
||||
@@ -769,18 +860,117 @@ func TestMultipleExternalMetricStorage(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
list: provider.ExternalMetricInfo{
|
||||
expectedIdx: 1,
|
||||
list: []provider.ExternalMetricInfo{
|
||||
{
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
},
|
||||
get: struct {
|
||||
namespace string
|
||||
selector labels.Selector
|
||||
info provider.ExternalMetricInfo
|
||||
}{namespace: "",
|
||||
}{
|
||||
namespace: "",
|
||||
selector: labels.Everything(),
|
||||
info: provider.ExternalMetricInfo{
|
||||
Metric: "metric-per-unit",
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: "external metrics are namespaced",
|
||||
insert: []collector.CollectedMetric{
|
||||
{
|
||||
Namespace: "one",
|
||||
Type: autoscalingv2.MetricSourceType("External"),
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: "metric-per-unit",
|
||||
Value: *resource.NewQuantity(0, ""),
|
||||
MetricLabels: map[string]string{"application": "some-app"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Namespace: "two",
|
||||
Type: autoscalingv2.MetricSourceType("External"),
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: "metric-per-unit",
|
||||
Value: *resource.NewQuantity(1, ""),
|
||||
MetricLabels: map[string]string{"application": "some-app"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedIdx: 1,
|
||||
list: []provider.ExternalMetricInfo{
|
||||
{
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
{
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
},
|
||||
get: struct {
|
||||
namespace string
|
||||
selector labels.Selector
|
||||
info provider.ExternalMetricInfo
|
||||
}{
|
||||
namespace: "two",
|
||||
selector: labels.Everything(),
|
||||
info: provider.ExternalMetricInfo{
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: "external metrics looked up by labels",
|
||||
insert: []collector.CollectedMetric{
|
||||
{
|
||||
Type: autoscalingv2.MetricSourceType("External"),
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: "metric-per-unit",
|
||||
Value: *resource.NewQuantity(0, ""),
|
||||
MetricLabels: map[string]string{"application": "some-app-one"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: autoscalingv2.MetricSourceType("External"),
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: "metric-per-unit",
|
||||
Value: *resource.NewQuantity(1, ""),
|
||||
MetricLabels: map[string]string{"application": "some-app-two"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: autoscalingv2.MetricSourceType("External"),
|
||||
External: external_metrics.ExternalMetricValue{
|
||||
MetricName: "metric-per-unit-x",
|
||||
Value: *resource.NewQuantity(1, ""),
|
||||
MetricLabels: map[string]string{"application": "some-app-two"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedIdx: 0,
|
||||
list: []provider.ExternalMetricInfo{
|
||||
{
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
{
|
||||
Metric: "metric-per-unit-x",
|
||||
},
|
||||
},
|
||||
get: struct {
|
||||
namespace string
|
||||
selector labels.Selector
|
||||
info provider.ExternalMetricInfo
|
||||
}{
|
||||
namespace: "",
|
||||
selector: labels.Set(map[string]string{
|
||||
"application": "some-app-one",
|
||||
}).AsSelector(),
|
||||
info: provider.ExternalMetricInfo{
|
||||
Metric: "metric-per-unit",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -799,12 +989,12 @@ func TestMultipleExternalMetricStorage(t *testing.T) {
|
||||
// Get the metric by name
|
||||
metrics, err := metricsStore.GetExternalMetric(tc.get.namespace, tc.get.selector, tc.get.info)
|
||||
require.NoError(t, err)
|
||||
require.NotContains(t, metrics.Items, tc.insert[0].External)
|
||||
require.Contains(t, metrics.Items, tc.insert[1].External)
|
||||
require.Len(t, metrics.Items, 1)
|
||||
require.Contains(t, metrics.Items, tc.insert[tc.expectedIdx].External)
|
||||
|
||||
// List a metric with value
|
||||
metricInfos := metricsStore.ListAllExternalMetrics()
|
||||
require.Equal(t, tc.list, metricInfos[0])
|
||||
require.EqualValues(t, tc.list, metricInfos)
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user