Namespace external metrics (#259)

Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>
This commit is contained in:
Mikkel Oscar Lyderik Larsen
2021-02-19 11:11:29 +01:00
committed by GitHub
parent 942e753f87
commit b7aa886546
13 changed files with 317 additions and 68 deletions

View File

@@ -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,

View File

@@ -178,6 +178,7 @@ type MetricTypeName struct {
type CollectedMetric struct {
Type autoscalingv2.MetricSourceType
Namespace string
Custom custom_metrics.MetricValue
External external_metrics.ExternalMetricValue
}

View File

@@ -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,

View File

@@ -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)

View File

@@ -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,

View File

@@ -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")
}

View File

@@ -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{

View File

@@ -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,

View File

@@ -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,

View File

@@ -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()

View File

@@ -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(),

View File

@@ -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)
}
}
}

View File

@@ -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)
})
}