diff --git a/pkg/collector/hostname_collector.go b/pkg/collector/hostname_collector.go index d2d5ae2..ab4b182 100644 --- a/pkg/collector/hostname_collector.go +++ b/pkg/collector/hostname_collector.go @@ -3,6 +3,7 @@ package collector import ( "fmt" "regexp" + "strconv" "strings" "time" @@ -11,7 +12,7 @@ import ( const ( HostnameMetricType = "hostname-rps" - HostnameRPSQuery = `scalar(sum(rate(%s{host=~"%s"}[1m])))` + HostnameRPSQuery = `scalar(sum(rate(%s{host=~"%s"}[1m])) * %.4f)` ) type HostnameCollectorPlugin struct { @@ -51,19 +52,37 @@ func (p *HostnameCollectorPlugin) NewCollector( // RPS data from a specific hostname from prometheus. The idea // of the copy is to not modify the original config struct. confCopy := *config - hostnames := config.Config["hostname"] + //hostnames := config.Config["hostnames"] + //weights := config.Config["weights"] - if ok, err := regexp.MatchString("^[a-zA-Z0-9.,-]+$", hostnames); !ok || err != nil { - return nil, fmt.Errorf( - "hostname is not specified or invalid format, unable to create collector", - ) + if _, ok := config.Config["hostnames"]; !ok { + return nil, fmt.Errorf("hostname is not specified, unable to create collector") + } + hostnames := strings.Split(config.Config["hostnames"], ",") + for _, h := range hostnames { + if ok, err := regexp.MatchString("^[a-zA-Z0-9.-]+$", h); !ok || err != nil { + return nil, fmt.Errorf( + "Invalid hostname format, unable to create collector: %s", + h, + ) + } + } + + weight := 1.0 + if w, ok := config.Config["weight"]; ok { + num, err := strconv.ParseFloat(w, 64) + if err != nil { + return nil, fmt.Errorf("Could not parse weight annotation, unable to create collector: %s", w) + } + weight = num / 100.0 } confCopy.Config = map[string]string{ "query": fmt.Sprintf( HostnameRPSQuery, p.metricName, - strings.Replace(strings.Replace(hostnames, ",", "|", -1), ".", "_", -1), + strings.Replace(strings.Join(hostnames, "|"), ".", "_", -1), + weight, ), } diff --git a/pkg/collector/hostname_collector_test.go b/pkg/collector/hostname_collector_test.go index 91a9b6a..6f7bf7b 100644 --- a/pkg/collector/hostname_collector_test.go +++ b/pkg/collector/hostname_collector_test.go @@ -68,22 +68,28 @@ func TestHostnamePluginNewCollector(tt *testing.T) { }, { "Valid hostname no prom query config", - &MetricConfig{Config: map[string]string{"hostname": "foo.bar.baz"}}, - `scalar(sum(rate(a_valid_one{host=~"foo_bar_baz"}[1m])))`, + &MetricConfig{Config: map[string]string{"hostnames": "foo.bar.baz"}}, + `scalar(sum(rate(a_valid_one{host=~"foo_bar_baz"}[1m])) * 1.0000)`, + true, + }, + { + "Valid hostname no prom query config", + &MetricConfig{Config: map[string]string{"hostnames": "foo.bar.baz", "weight": "42"}}, + `scalar(sum(rate(a_valid_one{host=~"foo_bar_baz"}[1m])) * 0.4200)`, true, }, { "Multiple valid hostnames no prom query config", - &MetricConfig{Config: map[string]string{"hostname": "foo.bar.baz,foz.bax.bas"}}, - `scalar(sum(rate(a_valid_one{host=~"foo_bar_baz|foz_bax_bas"}[1m])))`, + &MetricConfig{Config: map[string]string{"hostnames": "foo.bar.baz,foz.bax.bas"}}, + `scalar(sum(rate(a_valid_one{host=~"foo_bar_baz|foz_bax_bas"}[1m])) * 1.0000)`, true, }, { "Valid hostname with prom query config", &MetricConfig{ - Config: map[string]string{"hostname": "foo.bar.baz", "query": "some_other_query"}, + Config: map[string]string{"hostnames": "foo.bar.baz", "query": "some_other_query"}, }, - `scalar(sum(rate(a_valid_one{host=~"foo_bar_baz"}[1m])))`, + `scalar(sum(rate(a_valid_one{host=~"foo_bar_baz"}[1m])) * 1.0000)`, true, }, } { @@ -169,7 +175,7 @@ func TestHostnameCollectorInterval(t *testing.T) { } c, err := plugin.NewCollector( &autoscalingv2.HorizontalPodAutoscaler{}, - &MetricConfig{Config: map[string]string{"hostname": "foo.bar.baz"}}, + &MetricConfig{Config: map[string]string{"hostnames": "foo.bar.baz"}}, interval, ) @@ -179,11 +185,12 @@ func TestHostnameCollectorInterval(t *testing.T) { } func TestHostnameCollectorAndCollectorFabricInteraction(t *testing.T) { - expectedQuery := `scalar(sum(rate(a_metric{host=~"just_testing_com"}[1m])))` + expectedQuery := `scalar(sum(rate(a_metric{host=~"just_testing_com"}[1m])) * 0.4200)` hpa := &autoscalingv2.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - "metric-config.external.foo.hostname-rps/hostname": "just.testing.com", + "metric-config.external.foo.hostname-rps/hostnames": "just.testing.com", + "metric-config.external.foo.hostname-rps/weight": "42", }, }, Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ @@ -222,13 +229,14 @@ func TestHostnameCollectorAndCollectorFabricInteraction(t *testing.T) { } func TestHostnamePrometheusCollectorInteraction(t *testing.T) { - hostnameQuery := `scalar(sum(rate(a_metric{host=~"just_testing_com"}[1m])))` + hostnameQuery := `scalar(sum(rate(a_metric{host=~"just_testing_com"}[1m])) * 0.4200)` promQuery := "sum(rate(rps[1m]))" hpa := &autoscalingv2.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - "metric-config.external.foo.hostname-rps/hostname": "just.testing.com", - "metric-config.external.bar.prometheus/query": promQuery, + "metric-config.external.foo.hostname-rps/hostnames": "just.testing.com", + "metric-config.external.foo.hostname-rps/weight": "42", + "metric-config.external.bar.prometheus/query": promQuery, }, }, Spec: autoscalingv2.HorizontalPodAutoscalerSpec{