Rename collector to external RPS

Signed-off-by: Lucas Thiesen <lucas.thiesen@zalando.de>
This commit is contained in:
Lucas Thiesen
2023-05-23 15:40:56 +02:00
parent a276b64576
commit b89ca19e6a
3 changed files with 41 additions and 41 deletions

View File

@ -11,25 +11,25 @@ import (
) )
const ( const (
HostnameMetricType = "requests-per-second" ExternalRPSMetricType = "requests-per-second"
HostnameRPSQuery = `scalar(sum(rate(%s{host=~"%s"}[1m])) * %.4f)` ExternalRPSQuery = `scalar(sum(rate(%s{host=~"%s"}[1m])) * %.4f)`
) )
type HostnameCollectorPlugin struct { type ExternalRPSCollectorPlugin struct {
metricName string metricName string
promPlugin CollectorPlugin promPlugin CollectorPlugin
pattern *regexp.Regexp pattern *regexp.Regexp
} }
type HostnameCollector struct { type ExternalRPSCollector struct {
interval time.Duration interval time.Duration
promCollector Collector promCollector Collector
} }
func NewHostnameCollectorPlugin( func NewExternalRPSCollectorPlugin(
promPlugin CollectorPlugin, promPlugin CollectorPlugin,
metricName string, metricName string,
) (*HostnameCollectorPlugin, error) { ) (*ExternalRPSCollectorPlugin, error) {
if metricName == "" { if metricName == "" {
return nil, fmt.Errorf("failed to initialize hostname collector plugin, metric name was not defined") return nil, fmt.Errorf("failed to initialize hostname collector plugin, metric name was not defined")
} }
@ -39,7 +39,7 @@ func NewHostnameCollectorPlugin(
return nil, fmt.Errorf("failed to create regular expression to match hostname format") return nil, fmt.Errorf("failed to create regular expression to match hostname format")
} }
return &HostnameCollectorPlugin{ return &ExternalRPSCollectorPlugin{
metricName: metricName, metricName: metricName,
promPlugin: promPlugin, promPlugin: promPlugin,
pattern: p, pattern: p,
@ -47,7 +47,7 @@ func NewHostnameCollectorPlugin(
} }
// NewCollector initializes a new skipper collector from the specified HPA. // NewCollector initializes a new skipper collector from the specified HPA.
func (p *HostnameCollectorPlugin) NewCollector( func (p *ExternalRPSCollectorPlugin) NewCollector(
hpa *autoscalingv2.HorizontalPodAutoscaler, hpa *autoscalingv2.HorizontalPodAutoscaler,
config *MetricConfig, config *MetricConfig,
interval time.Duration, interval time.Duration,
@ -90,7 +90,7 @@ func (p *HostnameCollectorPlugin) NewCollector(
confCopy.Config = map[string]string{ confCopy.Config = map[string]string{
"query": fmt.Sprintf( "query": fmt.Sprintf(
HostnameRPSQuery, ExternalRPSQuery,
p.metricName, p.metricName,
strings.ReplaceAll(strings.Join(hostnames, "|"), ".", "_"), strings.ReplaceAll(strings.Join(hostnames, "|"), ".", "_"),
weight, weight,
@ -102,14 +102,14 @@ func (p *HostnameCollectorPlugin) NewCollector(
return nil, err return nil, err
} }
return &HostnameCollector{ return &ExternalRPSCollector{
interval: interval, interval: interval,
promCollector: c, promCollector: c,
}, nil }, nil
} }
// GetMetrics gets hostname metrics from Prometheus // GetMetrics gets hostname metrics from Prometheus
func (c *HostnameCollector) GetMetrics() ([]CollectedMetric, error) { func (c *ExternalRPSCollector) GetMetrics() ([]CollectedMetric, error) {
v, err := c.promCollector.GetMetrics() v, err := c.promCollector.GetMetrics()
if err != nil { if err != nil {
return nil, err return nil, err
@ -122,7 +122,7 @@ func (c *HostnameCollector) GetMetrics() ([]CollectedMetric, error) {
} }
// Interval returns the interval at which the collector should run. // Interval returns the interval at which the collector should run.
func (c *HostnameCollector) Interval() time.Duration { func (c *ExternalRPSCollector) Interval() time.Duration {
return c.interval return c.interval
} }

View File

@ -13,7 +13,7 @@ import (
"k8s.io/metrics/pkg/apis/external_metrics" "k8s.io/metrics/pkg/apis/external_metrics"
) )
func TestHostnameCollectorPluginConstructor(tt *testing.T) { func TestExternalRPSCollectorPluginConstructor(tt *testing.T) {
for _, testcase := range []struct { for _, testcase := range []struct {
msg string msg string
name string name string
@ -25,7 +25,7 @@ func TestHostnameCollectorPluginConstructor(tt *testing.T) {
tt.Run(testcase.msg, func(t *testing.T) { tt.Run(testcase.msg, func(t *testing.T) {
fakePlugin := &FakeCollectorPlugin{} fakePlugin := &FakeCollectorPlugin{}
plugin, err := NewHostnameCollectorPlugin(fakePlugin, testcase.name) plugin, err := NewExternalRPSCollectorPlugin(fakePlugin, testcase.name)
if testcase.isValid { if testcase.isValid {
require.NoError(t, err) require.NoError(t, err)
@ -40,13 +40,13 @@ func TestHostnameCollectorPluginConstructor(tt *testing.T) {
} }
} }
func TestHostnamePluginNewCollector(tt *testing.T) { func TestExternalRPSPluginNewCollector(tt *testing.T) {
fakePlugin := &FakeCollectorPlugin{} fakePlugin := &FakeCollectorPlugin{}
pattern, err := regexp.Compile("^[a-zA-Z0-9.-]+$") pattern, err := regexp.Compile("^[a-zA-Z0-9.-]+$")
require.Nil(tt, err, "Something is up, regex compiling failed.") require.Nil(tt, err, "Something is up, regex compiling failed.")
plugin := &HostnameCollectorPlugin{ plugin := &ExternalRPSCollectorPlugin{
metricName: "a_valid_one", metricName: "a_valid_one",
promPlugin: fakePlugin, promPlugin: fakePlugin,
pattern: pattern, pattern: pattern,
@ -117,7 +117,7 @@ func TestHostnamePluginNewCollector(tt *testing.T) {
} }
} }
func TestHostnameCollectorGetMetrics(tt *testing.T) { func TestExternalRPSCollectorGetMetrics(tt *testing.T) {
genericErr := fmt.Errorf("This is an error") genericErr := fmt.Errorf("This is an error")
expectedMetric := *resource.NewQuantity(int64(42), resource.DecimalSI) expectedMetric := *resource.NewQuantity(int64(42), resource.DecimalSI)
@ -155,7 +155,7 @@ func TestHostnameCollectorGetMetrics(tt *testing.T) {
} { } {
tt.Run(testcase.msg, func(t *testing.T) { tt.Run(testcase.msg, func(t *testing.T) {
fake := makeCollectorWithStub(testcase.stub) fake := makeCollectorWithStub(testcase.stub)
c := &HostnameCollector{promCollector: fake} c := &ExternalRPSCollector{promCollector: fake}
m, err := c.GetMetrics() m, err := c.GetMetrics()
if testcase.shouldWork { if testcase.shouldWork {
@ -171,12 +171,12 @@ func TestHostnameCollectorGetMetrics(tt *testing.T) {
} }
} }
func TestHostnameCollectorInterval(t *testing.T) { func TestExternalRPSCollectorInterval(t *testing.T) {
interval := time.Duration(42) interval := time.Duration(42)
fakePlugin := &FakeCollectorPlugin{} fakePlugin := &FakeCollectorPlugin{}
pattern, err := regexp.Compile("^[a-zA-Z0-9.-]+$") pattern, err := regexp.Compile("^[a-zA-Z0-9.-]+$")
require.Nil(t, err, "Something is up, regex compiling failed.") require.Nil(t, err, "Something is up, regex compiling failed.")
plugin := &HostnameCollectorPlugin{ plugin := &ExternalRPSCollectorPlugin{
metricName: "a_valid_one", metricName: "a_valid_one",
promPlugin: fakePlugin, promPlugin: fakePlugin,
pattern: pattern, pattern: pattern,
@ -192,7 +192,7 @@ func TestHostnameCollectorInterval(t *testing.T) {
require.Equal(t, interval, c.Interval()) require.Equal(t, interval, c.Interval())
} }
func TestHostnameCollectorAndCollectorFabricInteraction(t *testing.T) { func TestExternalRPSCollectorAndCollectorFabricInteraction(t *testing.T) {
expectedQuery := `scalar(sum(rate(a_metric{host=~"just_testing_com"}[1m])) * 0.4200)` expectedQuery := `scalar(sum(rate(a_metric{host=~"just_testing_com"}[1m])) * 0.4200)`
hpa := &autoscalingv2.HorizontalPodAutoscaler{ hpa := &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
@ -220,9 +220,9 @@ func TestHostnameCollectorAndCollectorFabricInteraction(t *testing.T) {
factory := NewCollectorFactory() factory := NewCollectorFactory()
fakePlugin := makePlugin(42) fakePlugin := makePlugin(42)
hostnamePlugin, err := NewHostnameCollectorPlugin(fakePlugin, "a_metric") hostnamePlugin, err := NewExternalRPSCollectorPlugin(fakePlugin, "a_metric")
require.NoError(t, err) require.NoError(t, err)
factory.RegisterExternalCollector([]string{HostnameMetricType}, hostnamePlugin) factory.RegisterExternalCollector([]string{ExternalRPSMetricType}, hostnamePlugin)
conf, err := ParseHPAMetrics(hpa) conf, err := ParseHPAMetrics(hpa)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, conf, 1) require.Len(t, conf, 1)
@ -230,14 +230,14 @@ func TestHostnameCollectorAndCollectorFabricInteraction(t *testing.T) {
c, err := factory.NewCollector(hpa, conf[0], 0) c, err := factory.NewCollector(hpa, conf[0], 0)
require.NoError(t, err) require.NoError(t, err)
_, ok := c.(*HostnameCollector) _, ok := c.(*ExternalRPSCollector)
require.True(t, ok) require.True(t, ok)
require.Equal(t, expectedQuery, fakePlugin.config["query"]) require.Equal(t, expectedQuery, fakePlugin.config["query"])
} }
func TestHostnamePrometheusCollectorInteraction(t *testing.T) { func TestExternalRPSPrometheusCollectorInteraction(t *testing.T) {
hostnameQuery := `scalar(sum(rate(a_metric{host=~"just_testing_com"}[1m])) * 0.4200)` externalRPSQuery := `scalar(sum(rate(a_metric{host=~"just_testing_com"}[1m])) * 0.4200)`
promQuery := "sum(rate(rps[1m]))" promQuery := "sum(rate(rps[1m]))"
hpa := &autoscalingv2.HorizontalPodAutoscaler{ hpa := &autoscalingv2.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
@ -279,9 +279,9 @@ func TestHostnamePrometheusCollectorInteraction(t *testing.T) {
promPlugin, err := NewPrometheusCollectorPlugin(nil, "http://prometheus") promPlugin, err := NewPrometheusCollectorPlugin(nil, "http://prometheus")
require.NoError(t, err) require.NoError(t, err)
factory.RegisterExternalCollector([]string{PrometheusMetricType, PrometheusMetricNameLegacy}, promPlugin) factory.RegisterExternalCollector([]string{PrometheusMetricType, PrometheusMetricNameLegacy}, promPlugin)
hostnamePlugin, err := NewHostnameCollectorPlugin(promPlugin, "a_metric") hostnamePlugin, err := NewExternalRPSCollectorPlugin(promPlugin, "a_metric")
require.NoError(t, err) require.NoError(t, err)
factory.RegisterExternalCollector([]string{HostnameMetricType}, hostnamePlugin) factory.RegisterExternalCollector([]string{ExternalRPSMetricType}, hostnamePlugin)
conf, err := ParseHPAMetrics(hpa) conf, err := ParseHPAMetrics(hpa)
require.NoError(t, err) require.NoError(t, err)
@ -295,11 +295,11 @@ func TestHostnamePrometheusCollectorInteraction(t *testing.T) {
prom, ok := collectors["prom"].(*PrometheusCollector) prom, ok := collectors["prom"].(*PrometheusCollector)
require.True(t, ok) require.True(t, ok)
hostname, ok := collectors["hostname"].(*HostnameCollector) hostname, ok := collectors["hostname"].(*ExternalRPSCollector)
require.True(t, ok) require.True(t, ok)
hostnameProm, ok := hostname.promCollector.(*PrometheusCollector) hostnameProm, ok := hostname.promCollector.(*PrometheusCollector)
require.True(t, ok) require.True(t, ok)
require.Equal(t, promQuery, prom.query) require.Equal(t, promQuery, prom.query)
require.Equal(t, hostnameQuery, hostnameProm.query) require.Equal(t, externalRPSQuery, hostnameProm.query)
} }

View File

@ -65,7 +65,7 @@ func NewCommandStartAdapterServer(stopCh <-chan struct{}) *cobra.Command {
MetricsAddress: ":7979", MetricsAddress: ":7979",
ZMONTokenName: "zmon", ZMONTokenName: "zmon",
CredentialsDir: "/meta/credentials", CredentialsDir: "/meta/credentials",
HostnameRPSMetricName: "skipper_serve_host_duration_seconds_count", ExternalRPSMetricName: "skipper_serve_host_duration_seconds_count",
} }
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -133,9 +133,9 @@ func NewCommandStartAdapterServer(stopCh <-chan struct{}) *cobra.Command {
flags.DurationVar(&o.DefaultScheduledScalingWindow, "scaling-schedule-default-scaling-window", 10*time.Minute, "Default rampup and rampdown window duration for ScalingSchedules") flags.DurationVar(&o.DefaultScheduledScalingWindow, "scaling-schedule-default-scaling-window", 10*time.Minute, "Default rampup and rampdown window duration for ScalingSchedules")
flags.IntVar(&o.RampSteps, "scaling-schedule-ramp-steps", 10, "Number of steps used to rampup and rampdown ScalingSchedules. It's used to guarantee won't avoid reaching the max scaling due to the 10% minimum change rule.") flags.IntVar(&o.RampSteps, "scaling-schedule-ramp-steps", 10, "Number of steps used to rampup and rampdown ScalingSchedules. It's used to guarantee won't avoid reaching the max scaling due to the 10% minimum change rule.")
flags.StringVar(&o.DefaultTimeZone, "scaling-schedule-default-time-zone", "Europe/Berlin", "Default time zone to use for ScalingSchedules.") flags.StringVar(&o.DefaultTimeZone, "scaling-schedule-default-time-zone", "Europe/Berlin", "Default time zone to use for ScalingSchedules.")
flags.StringVar(&o.HostnameRPSMetricName, "hostname-rps-metric-name", o.HostnameRPSMetricName, ""+ flags.StringVar(&o.ExternalRPSMetricName, "hostname-rps-metric-name", o.ExternalRPSMetricName, ""+
"The name of the metric that should be used to query prometheus for RPS per hostname.") "The name of the metric that should be used to query prometheus for RPS per hostname.")
flags.BoolVar(&o.HostnameRPSMetrics, "hostname-rps-metrics", o.HostnameRPSMetrics, ""+ flags.BoolVar(&o.ExternalRPSMetrics, "hostname-rps-metrics", o.ExternalRPSMetrics, ""+
"whether to enable hostname RPS metric collector or not") "whether to enable hostname RPS metric collector or not")
return cmd return cmd
} }
@ -224,13 +224,13 @@ func (o AdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-chan struct
} }
} }
// Hostname collector, like skipper's, depends on prometheus being enabled. // External RPS collector, like skipper's, depends on prometheus being enabled.
// Also, to enable hostname metric its necessary to pass the metric name that // Also, to enable hostname metric its necessary to pass the metric name that
// will be used. This was built this way so we can support hostname metrics to // will be used. This was built this way so we can support hostname metrics to
// any ingress provider, e.g. Skipper, Nginx, envoy etc, in a simple way. // any ingress provider, e.g. Skipper, Nginx, envoy etc, in a simple way.
if o.HostnameRPSMetrics && o.HostnameRPSMetricName != "" { if o.ExternalRPSMetrics && o.ExternalRPSMetricName != "" {
hostnamePlugin, err := collector.NewHostnameCollectorPlugin(promPlugin, o.HostnameRPSMetricName) externalRPSPlugin, err := collector.NewExternalRPSCollectorPlugin(promPlugin, o.ExternalRPSMetricName)
collectorFactory.RegisterExternalCollector([]string{collector.HostnameMetricType}, hostnamePlugin) collectorFactory.RegisterExternalCollector([]string{collector.ExternalRPSMetricType}, externalRPSPlugin)
if err != nil { if err != nil {
return fmt.Errorf("failed to register hostname collector plugin: %v", err) return fmt.Errorf("failed to register hostname collector plugin: %v", err)
} }
@ -462,8 +462,8 @@ type AdapterServerOptions struct {
RampSteps int RampSteps int
// Default time zone to use for ScalingSchedules. // Default time zone to use for ScalingSchedules.
DefaultTimeZone string DefaultTimeZone string
// Feature flag to enable hostname rps metric collector // Feature flag to enable external rps metric collector
HostnameRPSMetrics bool ExternalRPSMetrics bool
// Name of the Prometheus metric that stores RPS by hostname for Hostname RPS metrics. // Name of the Prometheus metric that stores RPS by hostname for external RPS metrics.
HostnameRPSMetricName string ExternalRPSMetricName string
} }