From 1dbd37cf1eb3422df42a9df15f121983f5ce354e Mon Sep 17 00:00:00 2001 From: Zbynek Roubalik Date: Tue, 15 Nov 2022 21:50:36 +0100 Subject: [PATCH] Metrics Adapter: use gRPC connection to get metrics from Operator Signed-off-by: Zbynek Roubalik --- CREATE-NEW-SCALER.md | 1 - Makefile | 1 + adapter/main.go | 15 +- apis/keda/v1alpha1/indentifier.go | 27 +++ apis/keda/v1alpha1/withtriggers_types.go | 4 +- config/manager/kustomization.yaml | 1 + config/manager/service.yaml | 17 ++ controllers/keda/hpa.go | 2 +- controllers/keda/hpa_test.go | 2 +- controllers/keda/scaledobject_controller.go | 70 +++---- .../keda/scaledobject_controller_test.go | 2 +- controllers/keda/scaledobject_finalizer.go | 4 +- controllers/keda/suite_test.go | 14 +- main.go | 41 +++- pkg/{provider => fallback}/fallback.go | 29 +-- pkg/{provider => fallback}/fallback_test.go | 74 +++---- pkg/k8s/scaleclient.go | 56 +++++ pkg/metricsservice/api/metrics.pb.go | 192 ++++++++++++++++++ pkg/metricsservice/api/metrics.proto | 32 +++ pkg/metricsservice/api/metrics_grpc.pb.go | 106 ++++++++++ pkg/metricsservice/client.go | 70 +++++++ pkg/metricsservice/server.go | 86 ++++++++ pkg/mock/mock_scaler/mock_scaler.go | 17 +- pkg/mock/mock_scaling/mock_interface.go | 32 +++ pkg/provider/provider.go | 72 ++----- pkg/scalers/activemq_scaler.go | 3 +- pkg/scalers/artemis_scaler.go | 3 +- pkg/scalers/aws_cloudwatch_scaler.go | 3 +- pkg/scalers/aws_cloudwatch_scaler_test.go | 4 +- pkg/scalers/aws_dynamodb_scaler.go | 3 +- pkg/scalers/aws_dynamodb_scaler_test.go | 5 +- pkg/scalers/aws_dynamodb_streams_scaler.go | 3 +- .../aws_dynamodb_streams_scaler_test.go | 4 +- pkg/scalers/aws_kinesis_stream_scaler.go | 3 +- pkg/scalers/aws_kinesis_stream_scaler_test.go | 4 +- pkg/scalers/aws_sqs_queue_scaler.go | 3 +- pkg/scalers/aws_sqs_queue_scaler_test.go | 4 +- pkg/scalers/azure_app_insights_scaler.go | 3 +- pkg/scalers/azure_blob_scaler.go | 3 +- pkg/scalers/azure_data_explorer_scaler.go | 3 +- pkg/scalers/azure_eventhub_scaler.go | 3 +- pkg/scalers/azure_log_analytics_scaler.go | 3 +- pkg/scalers/azure_monitor_scaler.go | 3 +- pkg/scalers/azure_pipelines_scaler.go | 3 +- pkg/scalers/azure_queue_scaler.go | 3 +- pkg/scalers/azure_servicebus_scaler.go | 3 +- pkg/scalers/cassandra_scaler.go | 3 +- pkg/scalers/cpu_memory_scaler.go | 3 +- pkg/scalers/cron_scaler.go | 3 +- pkg/scalers/cron_scaler_test.go | 4 +- pkg/scalers/datadog_scaler.go | 3 +- pkg/scalers/elasticsearch_scaler.go | 3 +- pkg/scalers/external_mock_scaler.go | 3 +- pkg/scalers/external_scaler.go | 3 +- pkg/scalers/gcp_pubsub_scaler.go | 3 +- pkg/scalers/gcp_stackdriver_scaler.go | 3 +- pkg/scalers/gcp_storage_scaler.go | 3 +- pkg/scalers/graphite_scaler.go | 3 +- pkg/scalers/huawei_cloudeye_scaler.go | 3 +- pkg/scalers/ibmmq_scaler.go | 3 +- pkg/scalers/influxdb_scaler.go | 3 +- pkg/scalers/kafka_scaler.go | 3 +- pkg/scalers/kubernetes_workload_scaler.go | 2 +- pkg/scalers/liiklus_scaler.go | 3 +- pkg/scalers/liiklus_scaler_test.go | 4 +- pkg/scalers/loki_scaler.go | 3 +- pkg/scalers/metrics_api_scaler.go | 3 +- pkg/scalers/metrics_api_scaler_test.go | 2 +- pkg/scalers/mongo_scaler.go | 3 +- pkg/scalers/mssql_scaler.go | 3 +- pkg/scalers/mysql_scaler.go | 3 +- pkg/scalers/nats_jetstream_scaler.go | 3 +- pkg/scalers/newrelic_scaler.go | 3 +- pkg/scalers/openstack_metrics_scaler.go | 3 +- pkg/scalers/openstack_swift_scaler.go | 3 +- pkg/scalers/postgresql_scaler.go | 3 +- pkg/scalers/predictkube_scaler.go | 3 +- pkg/scalers/predictkube_scaler_test.go | 2 +- pkg/scalers/prometheus_scaler.go | 3 +- pkg/scalers/pulsar_scaler.go | 3 +- pkg/scalers/pulsar_scaler_test.go | 2 +- pkg/scalers/rabbitmq_scaler.go | 3 +- pkg/scalers/redis_scaler.go | 3 +- pkg/scalers/redis_streams_scaler.go | 3 +- pkg/scalers/scaler.go | 3 +- pkg/scalers/selenium_grid_scaler.go | 3 +- pkg/scalers/solace_scaler.go | 3 +- pkg/scalers/stan_scaler.go | 3 +- pkg/scaling/cache/scalers_cache.go | 24 +-- pkg/scaling/cache/scalers_cache_test.go | 2 +- pkg/scaling/scale_handler.go | 124 ++++++++++- 91 files changed, 978 insertions(+), 332 deletions(-) create mode 100644 apis/keda/v1alpha1/indentifier.go create mode 100644 config/manager/service.yaml rename pkg/{provider => fallback}/fallback.go (72%) rename pkg/{provider => fallback}/fallback_test.go (85%) create mode 100644 pkg/k8s/scaleclient.go create mode 100644 pkg/metricsservice/api/metrics.pb.go create mode 100644 pkg/metricsservice/api/metrics.proto create mode 100644 pkg/metricsservice/api/metrics_grpc.pb.go create mode 100644 pkg/metricsservice/client.go create mode 100644 pkg/metricsservice/server.go diff --git a/CREATE-NEW-SCALER.md b/CREATE-NEW-SCALER.md index 726f670105a..73f535622cc 100644 --- a/CREATE-NEW-SCALER.md +++ b/CREATE-NEW-SCALER.md @@ -40,7 +40,6 @@ KEDA works in conjunction with Kubernetes Horizontal Pod Autoscaler (HPA). When The return type of this function is `MetricSpec`, but in KEDA's case we will mostly write External metrics. So the property that should be filled is `ExternalMetricSource`, where the: - `MetricName`: the name of our metric we are returning in this scaler. The name should be unique, to allow setting multiple (even the same type) Triggers in one ScaledObject, but each function call should return the same name. -- `MetricSelector`: //TODO - `TargetValue`: is the value of the metric we want to reach at all times at all costs. As long as the current metric doesn't match TargetValue, HPA will increase the number of the pods until it reaches the maximum number of pods allowed to scale to. - `TargetAverageValue`: the value of the metric for which we require one pod to handle. e.g. if we are have a scaler based on the length of a message queue, and we specificy 10 for `TargetAverageValue`, we are saying that each pod will handle 10 messages. So if the length of the queue becomes 30, we expect that we have 3 pods in our cluster. (`TargetAverage` and `TargetValue` are mutually exclusive) diff --git a/Makefile b/Makefile index a27af09f023..f7207fef934 100644 --- a/Makefile +++ b/Makefile @@ -151,6 +151,7 @@ clientset-generate: ## Generate client-go clientset, listers and informers. proto-gen: protoc-gen ## Generate Liiklus, ExternalScaler and MetricsService proto PATH=$(LOCALBIN):$(PATH) protoc -I vendor --proto_path=hack LiiklusService.proto --go_out=pkg/scalers/liiklus --go-grpc_out=pkg/scalers/liiklus PATH=$(LOCALBIN):$(PATH) protoc -I vendor --proto_path=pkg/scalers/externalscaler externalscaler.proto --go_out=pkg/scalers/externalscaler --go-grpc_out=pkg/scalers/externalscaler + PATH=$(LOCALBIN):$(PATH) protoc -I vendor --proto_path=pkg/metricsservice/api metrics.proto --go_out=pkg/metricsservice/api --go-grpc_out=pkg/metricsservice/api .PHONY: mockgen-gen mockgen-gen: mockgen pkg/mock/mock_scaling/mock_interface.go pkg/mock/mock_scaler/mock_scaler.go pkg/mock/mock_scale/mock_interfaces.go pkg/mock/mock_client/mock_interfaces.go pkg/scalers/liiklus/mocks/mock_liiklus.go diff --git a/adapter/main.go b/adapter/main.go index 1887c0f4d72..d14ebdee699 100644 --- a/adapter/main.go +++ b/adapter/main.go @@ -44,6 +44,7 @@ import ( generatedopenapi "github.com/kedacore/keda/v2/adapter/generated/openapi" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" kedacontrollers "github.com/kedacore/keda/v2/controllers/keda" + "github.com/kedacore/keda/v2/pkg/metricsservice" "github.com/kedacore/keda/v2/pkg/prommetrics" kedaprovider "github.com/kedacore/keda/v2/pkg/provider" "github.com/kedacore/keda/v2/pkg/scaling" @@ -138,13 +139,21 @@ func (a *Adapter) makeProvider(ctx context.Context, globalHTTPTimeout time.Durat prometheusServer := &prommetrics.PrometheusMetricServer{} go func() { prometheusServer.NewServer(fmt.Sprintf(":%v", prometheusMetricsPort), prometheusMetricsPath) }() - stopCh := make(chan struct{}) - if err := runScaledObjectController(ctx, mgr, handler, logger, externalMetricsInfo, externalMetricsInfoLock, maxConcurrentReconciles, stopCh); err != nil { + // TODO make the address configurable + grpcServerAddr := "keda-operator.keda.svc.cluster.local:9666" + logger.Info("Connecting Metrics Service gRPC client to the server", "address", grpcServerAddr) + grpcClient, err := metricsservice.NewGrpcClient(grpcServerAddr) + if err != nil { + logger.Error(err, "error connecting Metrics Service gRPC client to the server", "address", grpcServerAddr) return nil, nil, err } - return kedaprovider.NewProvider(ctx, logger, handler, mgr.GetClient(), namespace, externalMetricsInfo, externalMetricsInfoLock), stopCh, nil + stopCh := make(chan struct{}) + if err := runScaledObjectController(ctx, mgr, handler, logger, externalMetricsInfo, externalMetricsInfoLock, maxConcurrentReconciles, stopCh); err != nil { + return nil, nil, err + } + return kedaprovider.NewProvider(ctx, logger, handler, mgr.GetClient(), *grpcClient, namespace, externalMetricsInfo, externalMetricsInfoLock), stopCh, nil } func runScaledObjectController(ctx context.Context, mgr manager.Manager, scaleHandler scaling.ScaleHandler, logger logr.Logger, externalMetricsInfo *[]provider.ExternalMetricInfo, externalMetricsInfoLock *sync.RWMutex, maxConcurrentReconciles int, stopCh chan<- struct{}) error { diff --git a/apis/keda/v1alpha1/indentifier.go b/apis/keda/v1alpha1/indentifier.go new file mode 100644 index 00000000000..caa6ce6accd --- /dev/null +++ b/apis/keda/v1alpha1/indentifier.go @@ -0,0 +1,27 @@ +/* +Copyright 2022 The KEDA 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 v1alpha1 + +import ( + "fmt" + "strings" +) + +// GenerateIdenitifier returns identifier for the object in form "kind.namespace.name" +func GenerateIdenitifier(kind, name, namespace string) string { + return strings.ToLower(fmt.Sprintf("%s.%s.%s", kind, namespace, name)) +} diff --git a/apis/keda/v1alpha1/withtriggers_types.go b/apis/keda/v1alpha1/withtriggers_types.go index 00b9821cff7..8d8a08e82c4 100644 --- a/apis/keda/v1alpha1/withtriggers_types.go +++ b/apis/keda/v1alpha1/withtriggers_types.go @@ -17,8 +17,6 @@ limitations under the License. package v1alpha1 import ( - "fmt" - "strings" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -91,5 +89,5 @@ func (t *WithTriggers) GetPollingInterval() time.Duration { // GenerateIdenitifier returns identifier for the object in for "kind.namespace.name" func (t *WithTriggers) GenerateIdenitifier() string { - return strings.ToLower(fmt.Sprintf("%s.%s.%s", t.Kind, t.Namespace, t.Name)) + return GenerateIdenitifier(t.Kind, t.Namespace, t.Name) } diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 77c0cd34eaf..1ca9f662392 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -1,5 +1,6 @@ resources: - manager.yaml +- service.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization diff --git a/config/manager/service.yaml b/config/manager/service.yaml new file mode 100644 index 00000000000..cb995b808cd --- /dev/null +++ b/config/manager/service.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: keda-operator + app.kubernetes.io/version: latest + app.kubernetes.io/part-of: keda-operator + name: keda-operator + namespace: keda +spec: + ports: + - name: metricsservice + port: 9666 + targetPort: 9666 + selector: + app: keda-operator diff --git a/controllers/keda/hpa.go b/controllers/keda/hpa.go index 3832cca665e..85e1f37ab56 100644 --- a/controllers/keda/hpa.go +++ b/controllers/keda/hpa.go @@ -197,7 +197,7 @@ func (r *ScaledObjectReconciler) getScaledObjectMetricSpecs(ctx context.Context, var externalMetricNames []string var resourceMetricNames []string - cache, err := r.scaleHandler.GetScalersCache(ctx, scaledObject) + cache, err := r.ScaleHandler.GetScalersCache(ctx, scaledObject) if err != nil { logger.Error(err, "Error getting scalers") return nil, err diff --git a/controllers/keda/hpa_test.go b/controllers/keda/hpa_test.go index 898587eb8cd..7cef70233db 100644 --- a/controllers/keda/hpa_test.go +++ b/controllers/keda/hpa_test.go @@ -54,7 +54,7 @@ var _ = Describe("hpa", func() { logger = logr.Discard() reconciler = ScaledObjectReconciler{ Client: client, - scaleHandler: scaleHandler, + ScaleHandler: scaleHandler, } }) diff --git a/controllers/keda/scaledobject_controller.go b/controllers/keda/scaledobject_controller.go index 1a928a533d0..24a4b4390f6 100644 --- a/controllers/keda/scaledobject_controller.go +++ b/controllers/keda/scaledobject_controller.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "sync" - "time" "github.com/go-logr/logr" autoscalingv1 "k8s.io/api/autoscaling/v1" @@ -32,8 +31,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/discovery" - "k8s.io/client-go/dynamic" "k8s.io/client-go/scale" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" @@ -42,7 +39,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/predicate" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -65,16 +61,14 @@ import ( // ScaledObjectReconciler reconciles a ScaledObject object type ScaledObjectReconciler struct { - Client client.Client - Scheme *runtime.Scheme - GlobalHTTPTimeout time.Duration - Recorder record.EventRecorder + Client client.Client + Scheme *runtime.Scheme + Recorder record.EventRecorder + ScaleClient scale.ScalesGetter + ScaleHandler scaling.ScaleHandler - scaleClient scale.ScalesGetter restMapper meta.RESTMapper scaledObjectsGenerations *sync.Map - scaleHandler scaling.ScaleHandler - kubeVersion kedautil.K8sVersion } type scaledObjectMetricsData struct { @@ -102,33 +96,24 @@ func init() { // SetupWithManager initializes the ScaledObjectReconciler instance and starts a new controller managed by the passed Manager instance. func (r *ScaledObjectReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { - setupLog := log.Log.WithName("setup") + r.restMapper = mgr.GetRESTMapper() + r.scaledObjectsGenerations = &sync.Map{} - // create Discovery clientset - // TODO If we need to increase the QPS of scaling API calls, copy and tweak this RESTConfig. - clientset, err := discovery.NewDiscoveryClientForConfig(mgr.GetConfig()) - if err != nil { - setupLog.Error(err, "Not able to create Discovery clientset") - return err + if r.ScaleHandler == nil { + return fmt.Errorf("ScaledObjectReconciler.ScaleHandler is not initialized") } - - // Find out Kubernetes version - version, err := clientset.ServerVersion() - if err == nil { - r.kubeVersion = kedautil.NewK8sVersion(version) - setupLog.Info("Running on Kubernetes "+r.kubeVersion.PrettyVersion, "version", version) - } else { - setupLog.Error(err, "Not able to get Kubernetes version") + if r.Client == nil { + return fmt.Errorf("ScaledObjectReconciler.Client is not initialized") + } + if r.ScaleClient == nil { + return fmt.Errorf("ScaledObjectReconciler.ScaleClient is not initialized") + } + if r.Scheme == nil { + return fmt.Errorf("ScaledObjectReconciler.Scheme is not initialized") + } + if r.Recorder == nil { + return fmt.Errorf("ScaledObjectReconciler.Recorder is not initialized") } - - // Create Scale Client - scaleClient := initScaleClient(mgr, clientset) - r.scaleClient = scaleClient - - // Init the rest of ScaledObjectReconciler - r.restMapper = mgr.GetRESTMapper() - r.scaledObjectsGenerations = &sync.Map{} - r.scaleHandler = scaling.NewScaleHandler(mgr.GetClient(), r.scaleClient, mgr.GetScheme(), r.GlobalHTTPTimeout, r.Recorder) // Start controller return ctrl.NewControllerManagedBy(mgr). @@ -147,15 +132,6 @@ func (r *ScaledObjectReconciler) SetupWithManager(mgr ctrl.Manager, options cont Complete(r) } -func initScaleClient(mgr manager.Manager, clientset *discovery.DiscoveryClient) scale.ScalesGetter { - scaleKindResolver := scale.NewDiscoveryScaleKindResolver(clientset) - return scale.New( - clientset.RESTClient(), mgr.GetRESTMapper(), - dynamic.LegacyAPIPathResolverFunc, - scaleKindResolver, - ) -} - // Reconcile performs reconciliation on the identified ScaledObject resource based on the request information passed, returns the result and an error (if any). func (r *ScaledObjectReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { reqLogger := log.FromContext(ctx) @@ -319,7 +295,7 @@ func (r *ScaledObjectReconciler) checkTargetResourceIsScalable(ctx context.Conte // not cached, let's try to detect /scale subresource // also rechecks when we need to update the status. var errScale error - scale, errScale = (r.scaleClient).Scales(scaledObject.Namespace).Get(ctx, gr, scaledObject.Spec.ScaleTargetRef.Name, metav1.GetOptions{}) + scale, errScale = (r.ScaleClient).Scales(scaledObject.Namespace).Get(ctx, gr, scaledObject.Spec.ScaleTargetRef.Name, metav1.GetOptions{}) if errScale != nil { // not able to get /scale subresource -> let's check if the resource even exist in the cluster unstruct := &unstructured.Unstructured{} @@ -467,7 +443,7 @@ func (r *ScaledObjectReconciler) requestScaleLoop(ctx context.Context, logger lo return err } - if err = r.scaleHandler.HandleScalableObject(ctx, scaledObject); err != nil { + if err = r.ScaleHandler.HandleScalableObject(ctx, scaledObject); err != nil { return err } @@ -485,7 +461,7 @@ func (r *ScaledObjectReconciler) stopScaleLoop(ctx context.Context, logger logr. return err } - if err := r.scaleHandler.DeleteScalableObject(ctx, scaledObject); err != nil { + if err := r.ScaleHandler.DeleteScalableObject(ctx, scaledObject); err != nil { return err } // delete ScaledObject's current Generation diff --git a/controllers/keda/scaledobject_controller_test.go b/controllers/keda/scaledobject_controller_test.go index c5a24d41639..746697f69e5 100644 --- a/controllers/keda/scaledobject_controller_test.go +++ b/controllers/keda/scaledobject_controller_test.go @@ -76,7 +76,7 @@ var _ = Describe("ScaledObjectController", func() { mockStatusWriter = mock_client.NewMockStatusWriter(ctrl) metricNameTestReconciler = ScaledObjectReconciler{ - scaleHandler: mockScaleHandler, + ScaleHandler: mockScaleHandler, Client: mockClient, } }) diff --git a/controllers/keda/scaledobject_finalizer.go b/controllers/keda/scaledobject_finalizer.go index c0fa1aeab62..4c26caaa844 100644 --- a/controllers/keda/scaledobject_finalizer.go +++ b/controllers/keda/scaledobject_finalizer.go @@ -53,7 +53,7 @@ func (r *ScaledObjectReconciler) finalizeScaledObject(ctx context.Context, logge logger.V(1).Info("Failed to restore scaleTarget's replica count back to the original, the scaling haven't been probably initialized yet.") } else { // We have enough information about the scaleTarget, let's proceed. - scale, err := r.scaleClient.Scales(scaledObject.Namespace).Get(ctx, scaledObject.Status.ScaleTargetGVKR.GroupResource(), scaledObject.Spec.ScaleTargetRef.Name, metav1.GetOptions{}) + scale, err := r.ScaleClient.Scales(scaledObject.Namespace).Get(ctx, scaledObject.Status.ScaleTargetGVKR.GroupResource(), scaledObject.Spec.ScaleTargetRef.Name, metav1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { logger.V(1).Info("Failed to get scaleTarget's scale status, because it was probably deleted", "error", err) @@ -62,7 +62,7 @@ func (r *ScaledObjectReconciler) finalizeScaledObject(ctx context.Context, logge } } else { scale.Spec.Replicas = *scaledObject.Status.OriginalReplicaCount - _, err = r.scaleClient.Scales(scaledObject.Namespace).Update(ctx, scaledObject.Status.ScaleTargetGVKR.GroupResource(), scale, metav1.UpdateOptions{}) + _, err = r.ScaleClient.Scales(scaledObject.Namespace).Update(ctx, scaledObject.Status.ScaleTargetGVKR.GroupResource(), scale, metav1.UpdateOptions{}) if err != nil { logger.Error(err, "Failed to restore scaleTarget's replica count back to the original", "finalizer", scaledObjectFinalizer) } diff --git a/controllers/keda/suite_test.go b/controllers/keda/suite_test.go index 62ecb1a60cb..be88c4d53d3 100644 --- a/controllers/keda/suite_test.go +++ b/controllers/keda/suite_test.go @@ -20,6 +20,7 @@ import ( "context" "path/filepath" "testing" + "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -34,6 +35,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" + "github.com/kedacore/keda/v2/pkg/k8s" + "github.com/kedacore/keda/v2/pkg/scaling" // +kubebuilder:scaffold:imports ) @@ -81,10 +84,15 @@ var _ = BeforeSuite(func(done Done) { }) Expect(err).ToNot(HaveOccurred()) + scaleClient, _, err := k8s.InitScaleClient(k8sManager) + Expect(err).ToNot(HaveOccurred()) + err = (&ScaledObjectReconciler{ - Client: k8sManager.GetClient(), - Scheme: k8sManager.GetScheme(), - Recorder: k8sManager.GetEventRecorderFor("keda-operator"), + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + Recorder: k8sManager.GetEventRecorderFor("keda-operator"), + ScaleHandler: scaling.NewScaleHandler(k8sManager.GetClient(), scaleClient, k8sManager.GetScheme(), time.Duration(10), k8sManager.GetEventRecorderFor("keda-operator")), + ScaleClient: scaleClient, }).SetupWithManager(k8sManager, controller.Options{}) Expect(err).ToNot(HaveOccurred()) diff --git a/main.go b/main.go index 2c547f1493c..f4cb26de348 100644 --- a/main.go +++ b/main.go @@ -35,6 +35,9 @@ import ( kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" kedacontrollers "github.com/kedacore/keda/v2/controllers/keda" + "github.com/kedacore/keda/v2/pkg/k8s" + "github.com/kedacore/keda/v2/pkg/metricsservice" + "github.com/kedacore/keda/v2/pkg/scaling" kedautil "github.com/kedacore/keda/v2/pkg/util" "github.com/kedacore/keda/v2/version" //+kubebuilder:scaffold:imports @@ -64,21 +67,23 @@ func getWatchNamespace() (string, error) { func main() { var metricsAddr string - var enableLeaderElection bool var probeAddr string + var metricsServiceAddr string + var enableLeaderElection bool var adapterClientRequestQPS float32 var adapterClientRequestBurst int pflag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") pflag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + pflag.StringVar(&metricsServiceAddr, "metrics-service-bind-address", ":9666", "The address the gRPRC Metrics Service endpoint binds to.") pflag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") pflag.Float32Var(&adapterClientRequestQPS, "kube-api-qps", 20.0, "Set the QPS rate for throttling requests sent to the apiserver") pflag.IntVar(&adapterClientRequestBurst, "kube-api-burst", 30, "Set the burst for throttling requests sent to the apiserver") + opts := zap.Options{} opts.BindFlags(flag.CommandLine) pflag.CommandLine.AddGoFlagSet(flag.CommandLine) - pflag.Parse() ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) @@ -131,30 +136,39 @@ func main() { // default to 3 seconds if they don't pass the env var globalHTTPTimeoutMS, err := kedautil.ResolveOsEnvInt("KEDA_HTTP_DEFAULT_TIMEOUT", 3000) if err != nil { - setupLog.Error(err, "Invalid KEDA_HTTP_DEFAULT_TIMEOUT") + setupLog.Error(err, "invalid KEDA_HTTP_DEFAULT_TIMEOUT") os.Exit(1) } scaledObjectMaxReconciles, err := kedautil.ResolveOsEnvInt("KEDA_SCALEDOBJECT_CTRL_MAX_RECONCILES", 5) if err != nil { - setupLog.Error(err, "Invalid KEDA_SCALEDOBJECT_CTRL_MAX_RECONCILES") + setupLog.Error(err, "invalid KEDA_SCALEDOBJECT_CTRL_MAX_RECONCILES") os.Exit(1) } scaledJobMaxReconciles, err := kedautil.ResolveOsEnvInt("KEDA_SCALEDJOB_CTRL_MAX_RECONCILES", 1) if err != nil { - setupLog.Error(err, "Invalid KEDA_SCALEDJOB_CTRL_MAX_RECONCILES") + setupLog.Error(err, "invalid KEDA_SCALEDJOB_CTRL_MAX_RECONCILES") os.Exit(1) } globalHTTPTimeout := time.Duration(globalHTTPTimeoutMS) * time.Millisecond eventRecorder := mgr.GetEventRecorderFor("keda-operator") + scaleClient, kubeVersion, err := k8s.InitScaleClient(mgr) + if err != nil { + setupLog.Error(err, "unable to init scale client") + os.Exit(1) + } + + scaledHandler := scaling.NewScaleHandler(mgr.GetClient(), scaleClient, mgr.GetScheme(), globalHTTPTimeout, eventRecorder) + if err = (&kedacontrollers.ScaledObjectReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - GlobalHTTPTimeout: globalHTTPTimeout, - Recorder: eventRecorder, + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Recorder: eventRecorder, + ScaleClient: scaleClient, + ScaleHandler: scaledHandler, }).SetupWithManager(mgr, controller.Options{MaxConcurrentReconciles: scaledObjectMaxReconciles}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "ScaledObject") os.Exit(1) @@ -198,6 +212,15 @@ func main() { setupLog.Info(fmt.Sprintf("Git Commit: %s", version.GitCommit)) setupLog.Info(fmt.Sprintf("Go Version: %s", runtime.Version())) setupLog.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)) + setupLog.Info(fmt.Sprintf("Running on Kubernetes %s", kubeVersion.PrettyVersion), "version", kubeVersion.Version) + + go func() { + setupLog.Info("Starting Metrics Service gRPC Server", "address", metricsServiceAddr) + if err := metricsservice.StartServer(&scaledHandler, metricsServiceAddr); err != nil { + setupLog.Error(err, "unable to start Metrics Service gRPC server") + os.Exit(1) + } + }() if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { setupLog.Error(err, "problem running manager") diff --git a/pkg/provider/fallback.go b/pkg/fallback/fallback.go similarity index 72% rename from pkg/provider/fallback.go rename to pkg/fallback/fallback.go index ba25facca04..2cc3b740f2d 100644 --- a/pkg/provider/fallback.go +++ b/pkg/fallback/fallback.go @@ -1,5 +1,5 @@ /* -Copyright 2021 The KEDA Authors +Copyright 2022 The KEDA Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,12 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -package provider +package fallback import ( "context" "fmt" + "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -29,7 +30,7 @@ import ( kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" ) -func isFallbackEnabled(scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpec) bool { +func isFallbackEnabled(logger logr.Logger, scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpec) bool { if scaledObject.Spec.Fallback == nil { return false } @@ -42,7 +43,7 @@ func isFallbackEnabled(scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.Me return true } -func (p *KedaProvider) getMetricsWithFallback(ctx context.Context, metrics []external_metrics.ExternalMetricValue, suppressedError error, metricName string, scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpec) ([]external_metrics.ExternalMetricValue, error) { +func GetMetricsWithFallback(ctx context.Context, client runtimeclient.Client, logger logr.Logger, metrics []external_metrics.ExternalMetricValue, suppressedError error, metricName string, scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpec) ([]external_metrics.ExternalMetricValue, error) { status := scaledObject.Status.DeepCopy() initHealthStatus(status) @@ -54,7 +55,7 @@ func (p *KedaProvider) getMetricsWithFallback(ctx context.Context, metrics []ext healthStatus.Status = kedav1alpha1.HealthStatusHappy status.Health[metricName] = *healthStatus - p.updateStatus(ctx, scaledObject, status, metricSpec) + updateStatus(ctx, client, logger, scaledObject, status, metricSpec) return metrics, nil } @@ -62,23 +63,23 @@ func (p *KedaProvider) getMetricsWithFallback(ctx context.Context, metrics []ext *healthStatus.NumberOfFailures++ status.Health[metricName] = *healthStatus - p.updateStatus(ctx, scaledObject, status, metricSpec) + updateStatus(ctx, client, logger, scaledObject, status, metricSpec) switch { - case !isFallbackEnabled(scaledObject, metricSpec): + case !isFallbackEnabled(logger, scaledObject, metricSpec): return nil, suppressedError case !validateFallback(scaledObject): logger.Info("Failed to validate ScaledObject Spec. Please check that parameters are positive integers") return nil, suppressedError case *healthStatus.NumberOfFailures > scaledObject.Spec.Fallback.FailureThreshold: - return doFallback(scaledObject, metricSpec, metricName, suppressedError), nil + return doFallback(logger, scaledObject, metricSpec, metricName, suppressedError), nil default: return nil, suppressedError } } -func fallbackExistsInScaledObject(scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpec) bool { - if !isFallbackEnabled(scaledObject, metricSpec) || !validateFallback(scaledObject) { +func fallbackExistsInScaledObject(logger logr.Logger, scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpec) bool { + if !isFallbackEnabled(logger, scaledObject, metricSpec) || !validateFallback(scaledObject) { return false } @@ -96,7 +97,7 @@ func validateFallback(scaledObject *kedav1alpha1.ScaledObject) bool { scaledObject.Spec.Fallback.Replicas >= 0 } -func doFallback(scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpec, metricName string, suppressedError error) []external_metrics.ExternalMetricValue { +func doFallback(logger logr.Logger, scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpec, metricName string, suppressedError error) []external_metrics.ExternalMetricValue { replicas := int64(scaledObject.Spec.Fallback.Replicas) normalisationValue, _ := metricSpec.External.Target.AverageValue.AsInt64() metric := external_metrics.ExternalMetricValue{ @@ -110,17 +111,17 @@ func doFallback(scaledObject *kedav1alpha1.ScaledObject, metricSpec v2.MetricSpe return fallbackMetrics } -func (p *KedaProvider) updateStatus(ctx context.Context, scaledObject *kedav1alpha1.ScaledObject, status *kedav1alpha1.ScaledObjectStatus, metricSpec v2.MetricSpec) { +func updateStatus(ctx context.Context, client runtimeclient.Client, logger logr.Logger, scaledObject *kedav1alpha1.ScaledObject, status *kedav1alpha1.ScaledObjectStatus, metricSpec v2.MetricSpec) { patch := runtimeclient.MergeFrom(scaledObject.DeepCopy()) - if fallbackExistsInScaledObject(scaledObject, metricSpec) { + if fallbackExistsInScaledObject(logger, scaledObject, metricSpec) { status.Conditions.SetFallbackCondition(metav1.ConditionTrue, "FallbackExists", "At least one trigger is falling back on this scaled object") } else { status.Conditions.SetFallbackCondition(metav1.ConditionFalse, "NoFallbackFound", "No fallbacks are active on this scaled object") } scaledObject.Status = *status - err := p.client.Status().Patch(ctx, scaledObject, patch) + err := client.Status().Patch(ctx, scaledObject, patch) if err != nil { logger.Error(err, "Failed to patch ScaledObjects Status") } diff --git a/pkg/provider/fallback_test.go b/pkg/fallback/fallback_test.go similarity index 85% rename from pkg/provider/fallback_test.go rename to pkg/fallback/fallback_test.go index 9f9aa262416..2103d441ead 100644 --- a/pkg/provider/fallback_test.go +++ b/pkg/fallback/fallback_test.go @@ -1,5 +1,5 @@ /* -Copyright 2021 The KEDA Authors +Copyright 2022 The KEDA Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package provider +package fallback import ( "context" @@ -36,7 +36,6 @@ import ( kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" "github.com/kedacore/keda/v2/pkg/mock/mock_client" mock_scalers "github.com/kedacore/keda/v2/pkg/mock/mock_scaler" - "github.com/kedacore/keda/v2/pkg/mock/mock_scaling" ) const metricName = "some_metric_name" @@ -51,22 +50,15 @@ func TestFallback(t *testing.T) { var _ = Describe("fallback", func() { var ( - scaleHandler *mock_scaling.MockScaleHandler - client *mock_client.MockClient - providerUnderTest *KedaProvider - scaler *mock_scalers.MockScaler - ctrl *gomock.Controller + client *mock_client.MockClient + scaler *mock_scalers.MockScaler + ctrl *gomock.Controller + logger logr.Logger ) BeforeEach(func() { ctrl = gomock.NewController(GinkgoT()) - scaleHandler = mock_scaling.NewMockScaleHandler(ctrl) client = mock_client.NewMockClient(ctrl) - providerUnderTest = &KedaProvider{ - client: client, - scaleHandler: scaleHandler, - watchedNamespace: "", - } scaler = mock_scalers.NewMockScaler(ctrl) logger = logr.Discard() @@ -84,8 +76,8 @@ var _ = Describe("fallback", func() { metricSpec := createMetricSpec(3) expectStatusPatch(ctrl, client) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - metrics, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + metrics, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ToNot(HaveOccurred()) value, _ := metrics[0].Value.AsInt64() @@ -115,8 +107,8 @@ var _ = Describe("fallback", func() { metricSpec := createMetricSpec(3) expectStatusPatch(ctrl, client) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - metrics, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + metrics, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ToNot(HaveOccurred()) value, _ := metrics[0].Value.AsInt64() @@ -125,21 +117,21 @@ var _ = Describe("fallback", func() { }) It("should propagate the error when fallback is disabled", func() { - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName), gomock.Any()).Return(nil, errors.New("Some error")) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName)).Return(nil, errors.New("Some error")) so := buildScaledObject(nil, nil) metricSpec := createMetricSpec(3) expectStatusPatch(ctrl, client) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - _, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + _, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ShouldNot(BeNil()) Expect(err.Error()).Should(Equal("Some error")) }) It("should bump the number of failures when metrics call fails", func() { - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName), gomock.Any()).Return(nil, errors.New("Some error")) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName)).Return(nil, errors.New("Some error")) startingNumberOfFailures := int32(0) so := buildScaledObject( @@ -160,8 +152,8 @@ var _ = Describe("fallback", func() { metricSpec := createMetricSpec(10) expectStatusPatch(ctrl, client) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - _, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + _, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ShouldNot(BeNil()) Expect(err.Error()).Should(Equal("Some error")) @@ -169,7 +161,7 @@ var _ = Describe("fallback", func() { }) It("should return a normalised metric when number of failures are beyond threshold", func() { - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName), gomock.Any()).Return(nil, errors.New("Some error")) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName)).Return(nil, errors.New("Some error")) startingNumberOfFailures := int32(3) expectedMetricValue := int64(100) @@ -190,8 +182,8 @@ var _ = Describe("fallback", func() { metricSpec := createMetricSpec(10) expectStatusPatch(ctrl, client) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - metrics, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + metrics, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ToNot(HaveOccurred()) value, _ := metrics[0].Value.AsInt64() @@ -217,12 +209,12 @@ var _ = Describe("fallback", func() { }, } - isEnabled := isFallbackEnabled(so, metricsSpec) + isEnabled := isFallbackEnabled(logger, so, metricsSpec) Expect(isEnabled).Should(BeFalse()) }) It("should ignore error if we fail to update kubernetes status", func() { - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName), gomock.Any()).Return(nil, errors.New("Some error")) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName)).Return(nil, errors.New("Some error")) startingNumberOfFailures := int32(3) expectedMetricValue := int64(100) @@ -246,8 +238,8 @@ var _ = Describe("fallback", func() { statusWriter.EXPECT().Patch(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("Some error")) client.EXPECT().Status().Return(statusWriter) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - metrics, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + metrics, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ToNot(HaveOccurred()) value, _ := metrics[0].Value.AsInt64() @@ -256,7 +248,7 @@ var _ = Describe("fallback", func() { }) It("should return error when fallback is enabled but scaledobject has invalid parameter", func() { - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName), gomock.Any()).Return(nil, errors.New("Some error")) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName)).Return(nil, errors.New("Some error")) startingNumberOfFailures := int32(3) so := buildScaledObject( @@ -276,15 +268,15 @@ var _ = Describe("fallback", func() { metricSpec := createMetricSpec(10) expectStatusPatch(ctrl, client) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - _, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + _, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ShouldNot(BeNil()) Expect(err.Error()).Should(Equal("Some error")) }) It("should set the fallback condition when a fallback exists in the scaled object", func() { - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName), gomock.Any()).Return(nil, errors.New("Some error")) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName)).Return(nil, errors.New("Some error")) startingNumberOfFailures := int32(3) failingNumberOfFailures := int32(6) anotherMetricName := "another metric name" @@ -310,15 +302,15 @@ var _ = Describe("fallback", func() { metricSpec := createMetricSpec(10) expectStatusPatch(ctrl, client) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - _, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + _, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ToNot(HaveOccurred()) condition := so.Status.Conditions.GetFallbackCondition() Expect(condition.IsTrue()).Should(BeTrue()) }) It("should set the fallback condition to false if the config is invalid", func() { - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName), gomock.Any()).Return(nil, errors.New("Some error")) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName)).Return(nil, errors.New("Some error")) startingNumberOfFailures := int32(3) failingNumberOfFailures := int32(6) anotherMetricName := "another metric name" @@ -344,8 +336,8 @@ var _ = Describe("fallback", func() { metricSpec := createMetricSpec(10) expectStatusPatch(ctrl, client) - metrics, err := scaler.GetMetrics(context.Background(), metricName, nil) - _, err = providerUnderTest.getMetricsWithFallback(context.Background(), metrics, err, metricName, so, metricSpec) + metrics, err := scaler.GetMetrics(context.Background(), metricName) + _, err = GetMetricsWithFallback(context.Background(), client, logger, metrics, err, metricName, so, metricSpec) Expect(err).ShouldNot(BeNil()) Expect(err.Error()).Should(Equal("Some error")) condition := so.Status.Conditions.GetFallbackCondition() @@ -433,7 +425,7 @@ func primeGetMetrics(scaler *mock_scalers.MockScaler, value int64) { Timestamp: metav1.Now(), } - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName), gomock.Any()).Return([]external_metrics.ExternalMetricValue{expectedMetric}, nil) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Eq(metricName)).Return([]external_metrics.ExternalMetricValue{expectedMetric}, nil) } func createMetricSpec(averageValue int) v2.MetricSpec { diff --git a/pkg/k8s/scaleclient.go b/pkg/k8s/scaleclient.go new file mode 100644 index 00000000000..8564ff4255f --- /dev/null +++ b/pkg/k8s/scaleclient.go @@ -0,0 +1,56 @@ +/* +Copyright 2022 The KEDA 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 k8s + +import ( + "k8s.io/client-go/discovery" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/scale" + ctrl "sigs.k8s.io/controller-runtime" + + kedautil "github.com/kedacore/keda/v2/pkg/util" +) + +var log = ctrl.Log.WithName("scaleclient") + +// InitScaleClient initializes scale client and returns k8s version +func InitScaleClient(mgr ctrl.Manager) (scale.ScalesGetter, kedautil.K8sVersion, error) { + kubeVersion := kedautil.K8sVersion{} + + // create Discovery clientset + // TODO If we need to increase the QPS of scaling API calls, copy and tweak this RESTConfig. + clientset, err := discovery.NewDiscoveryClientForConfig(mgr.GetConfig()) + if err != nil { + log.Error(err, "not able to create Discovery clientset") + return nil, kubeVersion, err + } + + // Find out Kubernetes version + version, err := clientset.ServerVersion() + if err == nil { + kubeVersion = kedautil.NewK8sVersion(version) + } else { + log.Error(err, "not able to get Kubernetes version") + return nil, kubeVersion, err + } + + return scale.New( + clientset.RESTClient(), mgr.GetRESTMapper(), + dynamic.LegacyAPIPathResolverFunc, + scale.NewDiscoveryScaleKindResolver(clientset), + ), kubeVersion, nil +} diff --git a/pkg/metricsservice/api/metrics.pb.go b/pkg/metricsservice/api/metrics.pb.go new file mode 100644 index 00000000000..f9b994b4efc --- /dev/null +++ b/pkg/metricsservice/api/metrics.pb.go @@ -0,0 +1,192 @@ +// +//Copyright 2022 The KEDA 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.9 +// source: metrics.proto + +package api + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + v1beta1 "k8s.io/metrics/pkg/apis/external_metrics/v1beta1" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ScaledObjectRef struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + MetricName string `protobuf:"bytes,3,opt,name=metricName,proto3" json:"metricName,omitempty"` +} + +func (x *ScaledObjectRef) Reset() { + *x = ScaledObjectRef{} + if protoimpl.UnsafeEnabled { + mi := &file_metrics_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScaledObjectRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScaledObjectRef) ProtoMessage() {} + +func (x *ScaledObjectRef) ProtoReflect() protoreflect.Message { + mi := &file_metrics_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScaledObjectRef.ProtoReflect.Descriptor instead. +func (*ScaledObjectRef) Descriptor() ([]byte, []int) { + return file_metrics_proto_rawDescGZIP(), []int{0} +} + +func (x *ScaledObjectRef) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ScaledObjectRef) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *ScaledObjectRef) GetMetricName() string { + if x != nil { + return x.MetricName + } + return "" +} + +var File_metrics_proto protoreflect.FileDescriptor + +var file_metrics_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x03, 0x61, 0x70, 0x69, 0x1a, 0x40, 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x65, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x63, 0x0a, 0x0f, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x64, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x66, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4e, 0x61, 0x6d, 0x65, 0x32, 0x81, 0x01, 0x0a, 0x0e, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6f, + 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x14, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x66, 0x1a, 0x49, 0x2e, 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x2e, 0x70, 0x6b, 0x67, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x42, + 0x07, 0x5a, 0x05, 0x2e, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_metrics_proto_rawDescOnce sync.Once + file_metrics_proto_rawDescData = file_metrics_proto_rawDesc +) + +func file_metrics_proto_rawDescGZIP() []byte { + file_metrics_proto_rawDescOnce.Do(func() { + file_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_metrics_proto_rawDescData) + }) + return file_metrics_proto_rawDescData +} + +var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_metrics_proto_goTypes = []interface{}{ + (*ScaledObjectRef)(nil), // 0: api.ScaledObjectRef + (*v1beta1.ExternalMetricValueList)(nil), // 1: k8s.io.metrics.pkg.apis.external_metrics.v1beta1.ExternalMetricValueList +} +var file_metrics_proto_depIdxs = []int32{ + 0, // 0: api.MetricsService.GetMetrics:input_type -> api.ScaledObjectRef + 1, // 1: api.MetricsService.GetMetrics:output_type -> k8s.io.metrics.pkg.apis.external_metrics.v1beta1.ExternalMetricValueList + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_metrics_proto_init() } +func file_metrics_proto_init() { + if File_metrics_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScaledObjectRef); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_metrics_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_metrics_proto_goTypes, + DependencyIndexes: file_metrics_proto_depIdxs, + MessageInfos: file_metrics_proto_msgTypes, + }.Build() + File_metrics_proto = out.File + file_metrics_proto_rawDesc = nil + file_metrics_proto_goTypes = nil + file_metrics_proto_depIdxs = nil +} diff --git a/pkg/metricsservice/api/metrics.proto b/pkg/metricsservice/api/metrics.proto new file mode 100644 index 00000000000..883b2ed7ca2 --- /dev/null +++ b/pkg/metricsservice/api/metrics.proto @@ -0,0 +1,32 @@ +/* +Copyright 2022 The KEDA 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. +*/ + +syntax = "proto3"; + +package api; +option go_package = ".;api"; + +import "k8s.io/metrics/pkg/apis/external_metrics/v1beta1/generated.proto"; + +service MetricsService { + rpc GetMetrics (ScaledObjectRef) returns (k8s.io.metrics.pkg.apis.external_metrics.v1beta1.ExternalMetricValueList) {}; +} + +message ScaledObjectRef { + string name = 1; + string namespace = 2; + string metricName = 3; +} diff --git a/pkg/metricsservice/api/metrics_grpc.pb.go b/pkg/metricsservice/api/metrics_grpc.pb.go new file mode 100644 index 00000000000..103dec4eb9f --- /dev/null +++ b/pkg/metricsservice/api/metrics_grpc.pb.go @@ -0,0 +1,106 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.21.9 +// source: metrics.proto + +package api + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + v1beta1 "k8s.io/metrics/pkg/apis/external_metrics/v1beta1" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// MetricsServiceClient is the client API for MetricsService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type MetricsServiceClient interface { + GetMetrics(ctx context.Context, in *ScaledObjectRef, opts ...grpc.CallOption) (*v1beta1.ExternalMetricValueList, error) +} + +type metricsServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewMetricsServiceClient(cc grpc.ClientConnInterface) MetricsServiceClient { + return &metricsServiceClient{cc} +} + +func (c *metricsServiceClient) GetMetrics(ctx context.Context, in *ScaledObjectRef, opts ...grpc.CallOption) (*v1beta1.ExternalMetricValueList, error) { + out := new(v1beta1.ExternalMetricValueList) + err := c.cc.Invoke(ctx, "/api.MetricsService/GetMetrics", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MetricsServiceServer is the server API for MetricsService service. +// All implementations must embed UnimplementedMetricsServiceServer +// for forward compatibility +type MetricsServiceServer interface { + GetMetrics(context.Context, *ScaledObjectRef) (*v1beta1.ExternalMetricValueList, error) + mustEmbedUnimplementedMetricsServiceServer() +} + +// UnimplementedMetricsServiceServer must be embedded to have forward compatible implementations. +type UnimplementedMetricsServiceServer struct { +} + +func (UnimplementedMetricsServiceServer) GetMetrics(context.Context, *ScaledObjectRef) (*v1beta1.ExternalMetricValueList, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetMetrics not implemented") +} +func (UnimplementedMetricsServiceServer) mustEmbedUnimplementedMetricsServiceServer() {} + +// UnsafeMetricsServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MetricsServiceServer will +// result in compilation errors. +type UnsafeMetricsServiceServer interface { + mustEmbedUnimplementedMetricsServiceServer() +} + +func RegisterMetricsServiceServer(s grpc.ServiceRegistrar, srv MetricsServiceServer) { + s.RegisterService(&MetricsService_ServiceDesc, srv) +} + +func _MetricsService_GetMetrics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ScaledObjectRef) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MetricsServiceServer).GetMetrics(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.MetricsService/GetMetrics", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MetricsServiceServer).GetMetrics(ctx, req.(*ScaledObjectRef)) + } + return interceptor(ctx, in, info, handler) +} + +// MetricsService_ServiceDesc is the grpc.ServiceDesc for MetricsService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var MetricsService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "api.MetricsService", + HandlerType: (*MetricsServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetMetrics", + Handler: _MetricsService_GetMetrics_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "metrics.proto", +} diff --git a/pkg/metricsservice/client.go b/pkg/metricsservice/client.go new file mode 100644 index 00000000000..ea83358e8a9 --- /dev/null +++ b/pkg/metricsservice/client.go @@ -0,0 +1,70 @@ +/* +Copyright 2022 The KEDA 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 metricsservice + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "k8s.io/metrics/pkg/apis/external_metrics" + "k8s.io/metrics/pkg/apis/external_metrics/v1beta1" + + "github.com/kedacore/keda/v2/pkg/metricsservice/api" +) + +type GrpcClient struct { + client api.MetricsServiceClient +} + +func NewGrpcClient(url string) (*GrpcClient, error) { + retryPolicy := `{ + "methodConfig": [{ + "timeout": "3s", + "waitForReady": true, + "retryPolicy": { + "InitialBackoff": ".25s", + "MaxBackoff": "2.0s", + "BackoffMultiplier": 2, + "RetryableStatusCodes": [ "UNAVAILABLE" ] + } + }]}` + + // TODO fix Transport layer - use TLS + conn, err := grpc.Dial(url, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(retryPolicy)) + if err != nil { + return nil, err + } + + return &GrpcClient{client: api.NewMetricsServiceClient(conn)}, nil +} + +func (c *GrpcClient) GetMetrics(ctx context.Context, scaledObjectName, scaledObjectNamespace, metricName string) (*external_metrics.ExternalMetricValueList, error) { + v1beta1ExtMetrics, err := c.client.GetMetrics(ctx, &api.ScaledObjectRef{Name: scaledObjectName, Namespace: scaledObjectNamespace, MetricName: metricName}) + if err != nil { + return nil, err + } + + extMetrics := &external_metrics.ExternalMetricValueList{} + err = v1beta1.Convert_v1beta1_ExternalMetricValueList_To_external_metrics_ExternalMetricValueList(v1beta1ExtMetrics, extMetrics, nil) + if err != nil { + return nil, fmt.Errorf("error when converting metric values %s", err) + } + + return extMetrics, nil +} diff --git a/pkg/metricsservice/server.go b/pkg/metricsservice/server.go new file mode 100644 index 00000000000..ae4a5c2d85d --- /dev/null +++ b/pkg/metricsservice/server.go @@ -0,0 +1,86 @@ +/* +Copyright 2022 The KEDA 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 metricsservice + +import ( + "context" + "fmt" + "net" + + "google.golang.org/grpc" + "k8s.io/metrics/pkg/apis/external_metrics/v1beta1" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/kedacore/keda/v2/pkg/metricsservice/api" + "github.com/kedacore/keda/v2/pkg/scaling" +) + +var log = ctrl.Log.WithName("grpc_server") + +type grpcServer struct { + scalerHandler *scaling.ScaleHandler + api.UnimplementedMetricsServiceServer +} + +func (s *grpcServer) GetMetrics(ctx context.Context, in *api.ScaledObjectRef) (*v1beta1.ExternalMetricValueList, error) { + // TODO hit the metrics cache here first + + cache, err := (*s.scalerHandler).GetScalersCacheForScaledObject(ctx, in.Name, in.Namespace) + // TODO fix Prom metrics recorder + // metricsServer.RecordScalerObjectError(scaledObject.Namespace, scaledObject.Name, err) + if err != nil { + return nil, fmt.Errorf("error when getting scalers %s", err) + } + + v1beta1ExtMetrics := &v1beta1.ExternalMetricValueList{} + extMetrics, err := (*s.scalerHandler).GetExternalMetricsValuesList(ctx, cache, &cache.ScaledObject, in.MetricName) + if err != nil { + return nil, fmt.Errorf("error when getting metric values %s", err) + } + + err = v1beta1.Convert_external_metrics_ExternalMetricValueList_To_v1beta1_ExternalMetricValueList(extMetrics, v1beta1ExtMetrics, nil) + if err != nil { + return nil, fmt.Errorf("error when converting metric values %s", err) + } + + log.V(1).WithValues("scaledObjectName", in.Name, "scaledObjectNamespace", in.Namespace, "metrics", v1beta1ExtMetrics).Info("Providing metrics") + + return v1beta1ExtMetrics, nil +} + +func newGrpcServer(scaleHandler *scaling.ScaleHandler) *grpc.Server { + gsrv := grpc.NewServer() + srv := grpcServer{ + scalerHandler: scaleHandler, + } + + api.RegisterMetricsServiceServer(gsrv, &srv) + return gsrv +} + +func StartServer(scaleHandler *scaling.ScaleHandler, address string) error { + lis, err := net.Listen("tcp", address) + if err != nil { + return fmt.Errorf("failed to listen: %v", err) + } + + if err := newGrpcServer(scaleHandler).Serve(lis); err != nil { + return fmt.Errorf("failed to serve: %v", err) + } + + return nil +} diff --git a/pkg/mock/mock_scaler/mock_scaler.go b/pkg/mock/mock_scaler/mock_scaler.go index 7a0a4993584..7615887ae30 100644 --- a/pkg/mock/mock_scaler/mock_scaler.go +++ b/pkg/mock/mock_scaler/mock_scaler.go @@ -10,7 +10,6 @@ import ( gomock "github.com/golang/mock/gomock" v2 "k8s.io/api/autoscaling/v2" - labels "k8s.io/apimachinery/pkg/labels" external_metrics "k8s.io/metrics/pkg/apis/external_metrics" ) @@ -66,18 +65,18 @@ func (mr *MockScalerMockRecorder) GetMetricSpecForScaling(ctx interface{}) *gomo } // GetMetrics mocks base method. -func (m *MockScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (m *MockScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMetrics", ctx, metricName, metricSelector) + ret := m.ctrl.Call(m, "GetMetrics", ctx, metricName) ret0, _ := ret[0].([]external_metrics.ExternalMetricValue) ret1, _ := ret[1].(error) return ret0, ret1 } // GetMetrics indicates an expected call of GetMetrics. -func (mr *MockScalerMockRecorder) GetMetrics(ctx, metricName, metricSelector interface{}) *gomock.Call { +func (mr *MockScalerMockRecorder) GetMetrics(ctx, metricName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetrics", reflect.TypeOf((*MockScaler)(nil).GetMetrics), ctx, metricName, metricSelector) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetrics", reflect.TypeOf((*MockScaler)(nil).GetMetrics), ctx, metricName) } // IsActive mocks base method. @@ -147,18 +146,18 @@ func (mr *MockPushScalerMockRecorder) GetMetricSpecForScaling(ctx interface{}) * } // GetMetrics mocks base method. -func (m *MockPushScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (m *MockPushScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMetrics", ctx, metricName, metricSelector) + ret := m.ctrl.Call(m, "GetMetrics", ctx, metricName) ret0, _ := ret[0].([]external_metrics.ExternalMetricValue) ret1, _ := ret[1].(error) return ret0, ret1 } // GetMetrics indicates an expected call of GetMetrics. -func (mr *MockPushScalerMockRecorder) GetMetrics(ctx, metricName, metricSelector interface{}) *gomock.Call { +func (mr *MockPushScalerMockRecorder) GetMetrics(ctx, metricName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetrics", reflect.TypeOf((*MockPushScaler)(nil).GetMetrics), ctx, metricName, metricSelector) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetrics", reflect.TypeOf((*MockPushScaler)(nil).GetMetrics), ctx, metricName) } // IsActive mocks base method. diff --git a/pkg/mock/mock_scaling/mock_interface.go b/pkg/mock/mock_scaling/mock_interface.go index 3b46f343d62..c3838762761 100644 --- a/pkg/mock/mock_scaling/mock_interface.go +++ b/pkg/mock/mock_scaling/mock_interface.go @@ -9,7 +9,9 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" + v1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" cache "github.com/kedacore/keda/v2/pkg/scaling/cache" + external_metrics "k8s.io/metrics/pkg/apis/external_metrics" ) // MockScaleHandler is a mock of ScaleHandler interface. @@ -63,6 +65,21 @@ func (mr *MockScaleHandlerMockRecorder) DeleteScalableObject(ctx, scalableObject return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteScalableObject", reflect.TypeOf((*MockScaleHandler)(nil).DeleteScalableObject), ctx, scalableObject) } +// GetExternalMetricsValuesList mocks base method. +func (m *MockScaleHandler) GetExternalMetricsValuesList(ctx context.Context, cache *cache.ScalersCache, scaledObject *v1alpha1.ScaledObject, metricName string) (*external_metrics.ExternalMetricValueList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetExternalMetricsValuesList", ctx, cache, scaledObject, metricName) + ret0, _ := ret[0].(*external_metrics.ExternalMetricValueList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetExternalMetricsValuesList indicates an expected call of GetExternalMetricsValuesList. +func (mr *MockScaleHandlerMockRecorder) GetExternalMetricsValuesList(ctx, cache, scaledObject, metricName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExternalMetricsValuesList", reflect.TypeOf((*MockScaleHandler)(nil).GetExternalMetricsValuesList), ctx, cache, scaledObject, metricName) +} + // GetScalersCache mocks base method. func (m *MockScaleHandler) GetScalersCache(ctx context.Context, scalableObject interface{}) (*cache.ScalersCache, error) { m.ctrl.T.Helper() @@ -78,6 +95,21 @@ func (mr *MockScaleHandlerMockRecorder) GetScalersCache(ctx, scalableObject inte return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetScalersCache", reflect.TypeOf((*MockScaleHandler)(nil).GetScalersCache), ctx, scalableObject) } +// GetScalersCacheForScaledObject mocks base method. +func (m *MockScaleHandler) GetScalersCacheForScaledObject(ctx context.Context, scaledObjectName, scaledObjectNamespace string) (*cache.ScalersCache, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetScalersCacheForScaledObject", ctx, scaledObjectName, scaledObjectNamespace) + ret0, _ := ret[0].(*cache.ScalersCache) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetScalersCacheForScaledObject indicates an expected call of GetScalersCacheForScaledObject. +func (mr *MockScaleHandlerMockRecorder) GetScalersCacheForScaledObject(ctx, scaledObjectName, scaledObjectNamespace interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetScalersCacheForScaledObject", reflect.TypeOf((*MockScaleHandler)(nil).GetScalersCacheForScaledObject), ctx, scaledObjectName, scaledObjectNamespace) +} + // HandleScalableObject mocks base method. func (m *MockScaleHandler) HandleScalableObject(ctx context.Context, scalableObject interface{}) error { m.ctrl.T.Helper() diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index c1ae91303e5..2e3cd2b0a6d 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -19,7 +19,6 @@ package provider import ( "context" "fmt" - "strings" "sync" "github.com/go-logr/logr" @@ -32,6 +31,7 @@ import ( "sigs.k8s.io/custom-metrics-apiserver/pkg/provider" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" + "github.com/kedacore/keda/v2/pkg/metricsservice" "github.com/kedacore/keda/v2/pkg/prommetrics" "github.com/kedacore/keda/v2/pkg/scaling" ) @@ -44,6 +44,9 @@ type KedaProvider struct { ctx context.Context externalMetricsInfo *[]provider.ExternalMetricInfo externalMetricsInfoLock *sync.RWMutex + + grpcClient metricsservice.GrpcClient + grpcEnabled bool } var ( @@ -52,7 +55,7 @@ var ( ) // NewProvider returns an instance of KedaProvider -func NewProvider(ctx context.Context, adapterLogger logr.Logger, scaleHandler scaling.ScaleHandler, client client.Client, watchedNamespace string, externalMetricsInfo *[]provider.ExternalMetricInfo, externalMetricsInfoLock *sync.RWMutex) provider.MetricsProvider { +func NewProvider(ctx context.Context, adapterLogger logr.Logger, scaleHandler scaling.ScaleHandler, client client.Client, grpcClient metricsservice.GrpcClient, watchedNamespace string, externalMetricsInfo *[]provider.ExternalMetricInfo, externalMetricsInfoLock *sync.RWMutex) provider.MetricsProvider { provider := &KedaProvider{ client: client, scaleHandler: scaleHandler, @@ -60,6 +63,8 @@ func NewProvider(ctx context.Context, adapterLogger logr.Logger, scaleHandler sc ctx: ctx, externalMetricsInfo: externalMetricsInfo, externalMetricsInfoLock: externalMetricsInfoLock, + grpcClient: grpcClient, + grpcEnabled: true, } logger = adapterLogger.WithName("provider") logger.Info("starting") @@ -81,6 +86,15 @@ func (p *KedaProvider) GetExternalMetric(ctx context.Context, namespace string, return nil, err } + if p.grpcEnabled { + // selector is in form: `scaledobject.keda.sh/name: scaledobject-name` + scaledObjectName := selector.Get("scaledobject.keda.sh/name") + + metrics, err := p.grpcClient.GetMetrics(ctx, scaledObjectName, namespace, info.Metric) + logger.V(1).WithValues("scaledObjectName", scaledObjectName, "scaledObjectNamespace", namespace, "metrics", metrics).Info("Receiving metrics") + return metrics, err + } + // get the scaled objects matching namespace and labels scaledObjects := &kedav1alpha1.ScaledObjectList{} opts := []client.ListOption{ @@ -95,65 +109,13 @@ func (p *KedaProvider) GetExternalMetric(ctx context.Context, namespace string, } scaledObject := &scaledObjects.Items[0] - var matchingMetrics []external_metrics.ExternalMetricValue - cache, err := p.scaleHandler.GetScalersCache(ctx, scaledObject) metricsServer.RecordScalerObjectError(scaledObject.Namespace, scaledObject.Name, err) if err != nil { return nil, fmt.Errorf("error when getting scalers %s", err) } - // let's check metrics for all scalers in a ScaledObject - scalerError := false - scalers, scalerConfigs := cache.GetScalers() - for scalerIndex := 0; scalerIndex < len(scalers); scalerIndex++ { - metricSpecs := scalers[scalerIndex].GetMetricSpecForScaling(ctx) - scalerName := strings.Replace(fmt.Sprintf("%T", scalers[scalerIndex]), "*scalers.", "", 1) - if scalerConfigs[scalerIndex].TriggerName != "" { - scalerName = scalerConfigs[scalerIndex].TriggerName - } - - for _, metricSpec := range metricSpecs { - // skip cpu/memory resource scaler - if metricSpec.External == nil { - continue - } - // Filter only the desired metric - if strings.EqualFold(metricSpec.External.Metric.Name, info.Metric) { - metrics, err := cache.GetMetricsForScaler(ctx, scalerIndex, info.Metric, metricSelector) - metrics, err = p.getMetricsWithFallback(ctx, metrics, err, info.Metric, scaledObject, metricSpec) - if err != nil { - scalerError = true - logger.Error(err, "error getting metric for scaler", "scaledObject.Namespace", scaledObject.Namespace, "scaledObject.Name", scaledObject.Name, "scaler", scalerName) - } else { - for _, metric := range metrics { - metricValue := metric.Value.AsApproximateFloat64() - metricsServer.RecordHPAScalerMetric(namespace, scaledObject.Name, scalerName, scalerIndex, metric.MetricName, metricValue) - } - matchingMetrics = append(matchingMetrics, metrics...) - } - metricsServer.RecordHPAScalerError(namespace, scaledObject.Name, scalerName, scalerIndex, info.Metric, err) - } - } - } - - // invalidate the cache for the ScaledObject, if we hit an error in any scaler - // in this case we try to build all scalers (and resolve all secrets/creds) again in the next call - if scalerError { - err := p.scaleHandler.ClearScalersCache(ctx, scaledObject) - if err != nil { - logger.Error(err, "error clearing scalers cache") - } - logger.V(1).Info("scaler error encountered, clearing scaler cache") - } - - if len(matchingMetrics) == 0 { - return nil, fmt.Errorf("no matching metrics found for " + info.Metric) - } - - return &external_metrics.ExternalMetricValueList{ - Items: matchingMetrics, - }, nil + return p.scaleHandler.GetExternalMetricsValuesList(ctx, cache, scaledObject, info.Metric) } // ListAllExternalMetrics returns the supported external metrics for this provider diff --git a/pkg/scalers/activemq_scaler.go b/pkg/scalers/activemq_scaler.go index b7172d2d071..6bd22c72d25 100644 --- a/pkg/scalers/activemq_scaler.go +++ b/pkg/scalers/activemq_scaler.go @@ -14,7 +14,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -279,7 +278,7 @@ func (s *activeMQScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpe return []v2.MetricSpec{metricSpec} } -func (s *activeMQScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *activeMQScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { queueSize, err := s.getQueueMessageCount(ctx) if err != nil { return nil, fmt.Errorf("error inspecting ActiveMQ queue size: %s", err) diff --git a/pkg/scalers/artemis_scaler.go b/pkg/scalers/artemis_scaler.go index b2ea3acea70..df8d9a1480a 100644 --- a/pkg/scalers/artemis_scaler.go +++ b/pkg/scalers/artemis_scaler.go @@ -12,7 +12,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -279,7 +278,7 @@ func (s *artemisScaler) GetMetricSpecForScaling(ctx context.Context) []v2.Metric } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *artemisScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *artemisScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { messages, err := s.getQueueMessageCount(ctx) if err != nil { diff --git a/pkg/scalers/aws_cloudwatch_scaler.go b/pkg/scalers/aws_cloudwatch_scaler.go index f79dbf789d8..646988995eb 100644 --- a/pkg/scalers/aws_cloudwatch_scaler.go +++ b/pkg/scalers/aws_cloudwatch_scaler.go @@ -12,7 +12,6 @@ import ( "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -274,7 +273,7 @@ func computeQueryWindow(current time.Time, metricPeriodSec, metricEndTimeOffsetS return } -func (s *awsCloudwatchScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *awsCloudwatchScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { metricValue, err := s.GetCloudwatchMetrics() if err != nil { diff --git a/pkg/scalers/aws_cloudwatch_scaler_test.go b/pkg/scalers/aws_cloudwatch_scaler_test.go index 9e262f94842..e07153cdff0 100644 --- a/pkg/scalers/aws_cloudwatch_scaler_test.go +++ b/pkg/scalers/aws_cloudwatch_scaler_test.go @@ -11,7 +11,6 @@ import ( "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" "github.com/go-logr/logr" "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/labels" ) const ( @@ -500,10 +499,9 @@ func TestAWSCloudwatchGetMetricSpecForScaling(t *testing.T) { } func TestAWSCloudwatchScalerGetMetrics(t *testing.T) { - var selector labels.Selector for _, meta := range awsCloudwatchGetMetricTestData { mockAWSCloudwatchScaler := awsCloudwatchScaler{"", &meta, &mockCloudwatch{}, logr.Discard()} - value, err := mockAWSCloudwatchScaler.GetMetrics(context.Background(), meta.metricsName, selector) + value, err := mockAWSCloudwatchScaler.GetMetrics(context.Background(), meta.metricsName) switch meta.metricsName { case testAWSCloudwatchErrorMetric: assert.Error(t, err, "expect error because of cloudwatch api error") diff --git a/pkg/scalers/aws_dynamodb_scaler.go b/pkg/scalers/aws_dynamodb_scaler.go index 246924b5c97..935d4316e23 100644 --- a/pkg/scalers/aws_dynamodb_scaler.go +++ b/pkg/scalers/aws_dynamodb_scaler.go @@ -13,7 +13,6 @@ import ( "github.com/go-logr/logr" "go.mongodb.org/mongo-driver/bson" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -152,7 +151,7 @@ func createDynamoDBClient(metadata *awsDynamoDBMetadata) *dynamodb.DynamoDB { return dynamodb.New(sess, config) } -func (s *awsDynamoDBScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *awsDynamoDBScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { metricValue, err := s.GetQueryMetrics() if err != nil { s.logger.Error(err, "Error getting metric value") diff --git a/pkg/scalers/aws_dynamodb_scaler_test.go b/pkg/scalers/aws_dynamodb_scaler_test.go index c8be74c6215..12ebc276544 100644 --- a/pkg/scalers/aws_dynamodb_scaler_test.go +++ b/pkg/scalers/aws_dynamodb_scaler_test.go @@ -10,7 +10,6 @@ import ( "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface" "github.com/go-logr/logr" "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/labels" ) const ( @@ -302,13 +301,11 @@ var awsDynamoDBGetMetricTestData = []awsDynamoDBMetadata{ } func TestDynamoGetMetrics(t *testing.T) { - var selector labels.Selector - for _, meta := range awsDynamoDBGetMetricTestData { t.Run(meta.tableName, func(t *testing.T) { scaler := awsDynamoDBScaler{"", &meta, &mockDynamoDB{}, logr.Discard()} - value, err := scaler.GetMetrics(context.Background(), "aws-dynamodb", selector) + value, err := scaler.GetMetrics(context.Background(), "aws-dynamodb") switch meta.tableName { case testAWSDynamoErrorTable: assert.Error(t, err, "expect error because of dynamodb api error") diff --git a/pkg/scalers/aws_dynamodb_streams_scaler.go b/pkg/scalers/aws_dynamodb_streams_scaler.go index 5efbc939c1e..6f6c06d903c 100644 --- a/pkg/scalers/aws_dynamodb_streams_scaler.go +++ b/pkg/scalers/aws_dynamodb_streams_scaler.go @@ -13,7 +13,6 @@ import ( v2 "k8s.io/api/autoscaling/v2" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -174,7 +173,7 @@ func (s *awsDynamoDBStreamsScaler) GetMetricSpecForScaling(context.Context) []v2 } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *awsDynamoDBStreamsScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *awsDynamoDBStreamsScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { shardCount, err := s.GetDynamoDBStreamShardCount(ctx) if err != nil { diff --git a/pkg/scalers/aws_dynamodb_streams_scaler_test.go b/pkg/scalers/aws_dynamodb_streams_scaler_test.go index 011bfbbfb50..c9cf2fed967 100644 --- a/pkg/scalers/aws_dynamodb_streams_scaler_test.go +++ b/pkg/scalers/aws_dynamodb_streams_scaler_test.go @@ -15,7 +15,6 @@ import ( "github.com/aws/aws-sdk-go/service/dynamodbstreams/dynamodbstreamsiface" "github.com/go-logr/logr" "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" ) @@ -414,7 +413,6 @@ func TestAwsDynamoDBStreamsGetMetricSpecForScaling(t *testing.T) { } func TestAwsDynamoDBStreamsScalerGetMetrics(t *testing.T) { - var selector labels.Selector for _, meta := range awsDynamoDBStreamsGetMetricTestData { var value []external_metrics.ExternalMetricValue var err error @@ -423,7 +421,7 @@ func TestAwsDynamoDBStreamsScalerGetMetrics(t *testing.T) { streamArn, err = getDynamoDBStreamsArn(ctx, &mockAwsDynamoDB{}, &meta.tableName) if err == nil { scaler := awsDynamoDBStreamsScaler{"", meta, streamArn, &mockAwsDynamoDBStreams{}, logr.Discard()} - value, err = scaler.GetMetrics(context.Background(), "MetricName", selector) + value, err = scaler.GetMetrics(context.Background(), "MetricName") } switch meta.tableName { case testAWSDynamoDBErrorTable: diff --git a/pkg/scalers/aws_kinesis_stream_scaler.go b/pkg/scalers/aws_kinesis_stream_scaler.go index 906c5bef80b..99f877d4ca4 100644 --- a/pkg/scalers/aws_kinesis_stream_scaler.go +++ b/pkg/scalers/aws_kinesis_stream_scaler.go @@ -9,7 +9,6 @@ import ( "github.com/aws/aws-sdk-go/service/kinesis/kinesisiface" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -146,7 +145,7 @@ func (s *awsKinesisStreamScaler) GetMetricSpecForScaling(context.Context) []v2.M } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *awsKinesisStreamScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *awsKinesisStreamScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { shardCount, err := s.GetAwsKinesisOpenShardCount() if err != nil { diff --git a/pkg/scalers/aws_kinesis_stream_scaler_test.go b/pkg/scalers/aws_kinesis_stream_scaler_test.go index 05c5630bb30..2422308c309 100644 --- a/pkg/scalers/aws_kinesis_stream_scaler_test.go +++ b/pkg/scalers/aws_kinesis_stream_scaler_test.go @@ -11,7 +11,6 @@ import ( "github.com/aws/aws-sdk-go/service/kinesis/kinesisiface" "github.com/go-logr/logr" "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/labels" ) const ( @@ -350,10 +349,9 @@ func TestAWSKinesisGetMetricSpecForScaling(t *testing.T) { } func TestAWSKinesisStreamScalerGetMetrics(t *testing.T) { - var selector labels.Selector for _, meta := range awsKinesisGetMetricTestData { scaler := awsKinesisStreamScaler{"", meta, &mockKinesis{}, logr.Discard()} - value, err := scaler.GetMetrics(context.Background(), "MetricName", selector) + value, err := scaler.GetMetrics(context.Background(), "MetricName") switch meta.streamName { case testAWSKinesisErrorStream: assert.Error(t, err, "expect error because of kinesis api error") diff --git a/pkg/scalers/aws_sqs_queue_scaler.go b/pkg/scalers/aws_sqs_queue_scaler.go index 2bec847f11f..e585514b034 100644 --- a/pkg/scalers/aws_sqs_queue_scaler.go +++ b/pkg/scalers/aws_sqs_queue_scaler.go @@ -12,7 +12,6 @@ import ( "github.com/aws/aws-sdk-go/service/sqs/sqsiface" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -194,7 +193,7 @@ func (s *awsSqsQueueScaler) GetMetricSpecForScaling(context.Context) []v2.Metric } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *awsSqsQueueScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *awsSqsQueueScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { queuelen, err := s.getAwsSqsQueueLength() if err != nil { diff --git a/pkg/scalers/aws_sqs_queue_scaler_test.go b/pkg/scalers/aws_sqs_queue_scaler_test.go index 6881ef43317..35eba831582 100644 --- a/pkg/scalers/aws_sqs_queue_scaler_test.go +++ b/pkg/scalers/aws_sqs_queue_scaler_test.go @@ -10,7 +10,6 @@ import ( "github.com/aws/aws-sdk-go/service/sqs/sqsiface" "github.com/go-logr/logr" "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/labels" ) const ( @@ -344,10 +343,9 @@ func TestAWSSQSGetMetricSpecForScaling(t *testing.T) { } func TestAWSSQSScalerGetMetrics(t *testing.T) { - var selector labels.Selector for _, meta := range awsSQSGetMetricTestData { scaler := awsSqsQueueScaler{"", meta, &mockSqs{}, logr.Discard()} - value, err := scaler.GetMetrics(context.Background(), "MetricName", selector) + value, err := scaler.GetMetrics(context.Background(), "MetricName") switch meta.queueURL { case testAWSSQSErrorQueueURL: assert.Error(t, err, "expect error because of sqs api error") diff --git a/pkg/scalers/azure_app_insights_scaler.go b/pkg/scalers/azure_app_insights_scaler.go index badc4f4bf1b..8d12a565897 100644 --- a/pkg/scalers/azure_app_insights_scaler.go +++ b/pkg/scalers/azure_app_insights_scaler.go @@ -8,7 +8,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -191,7 +190,7 @@ func (s *azureAppInsightsScaler) GetMetricSpecForScaling(context.Context) []v2.M } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *azureAppInsightsScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *azureAppInsightsScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { val, err := azure.GetAzureAppInsightsMetricValue(ctx, s.metadata.azureAppInsightsInfo, s.podIdentity) if err != nil { s.logger.Error(err, "error getting azure app insights metric") diff --git a/pkg/scalers/azure_blob_scaler.go b/pkg/scalers/azure_blob_scaler.go index d3e3781ebd7..20913d40389 100644 --- a/pkg/scalers/azure_blob_scaler.go +++ b/pkg/scalers/azure_blob_scaler.go @@ -25,7 +25,6 @@ import ( "github.com/go-logr/logr" "github.com/gobwas/glob" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -214,7 +213,7 @@ func (s *azureBlobScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSp } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *azureBlobScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *azureBlobScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { bloblen, err := azure.GetAzureBlobListLength( ctx, s.httpClient, diff --git a/pkg/scalers/azure_data_explorer_scaler.go b/pkg/scalers/azure_data_explorer_scaler.go index c8bd6d2efcb..a95856b7f88 100644 --- a/pkg/scalers/azure_data_explorer_scaler.go +++ b/pkg/scalers/azure_data_explorer_scaler.go @@ -24,7 +24,6 @@ import ( "github.com/Azure/azure-kusto-go/kusto" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -170,7 +169,7 @@ func parseAzureDataExplorerAuthParams(config *ScalerConfig, logger logr.Logger) return &metadata, nil } -func (s azureDataExplorerScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s azureDataExplorerScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { metricValue, err := azure.GetAzureDataExplorerMetricValue(ctx, s.client, s.metadata.DatabaseName, s.metadata.Query) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("failed to get metrics for scaled object %s in namespace %s: %v", s.name, s.namespace, err) diff --git a/pkg/scalers/azure_eventhub_scaler.go b/pkg/scalers/azure_eventhub_scaler.go index 281451c75b9..8f87e0b49d3 100644 --- a/pkg/scalers/azure_eventhub_scaler.go +++ b/pkg/scalers/azure_eventhub_scaler.go @@ -30,7 +30,6 @@ import ( az "github.com/Azure/go-autorest/autorest/azure" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -355,7 +354,7 @@ func (s *azureEventHubScaler) GetMetricSpecForScaling(context.Context) []v2.Metr } // GetMetrics returns metric using total number of unprocessed events in event hub -func (s *azureEventHubScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *azureEventHubScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { totalUnprocessedEventCount := int64(0) runtimeInfo, err := s.client.GetRuntimeInformation(ctx) if err != nil { diff --git a/pkg/scalers/azure_log_analytics_scaler.go b/pkg/scalers/azure_log_analytics_scaler.go index 2979b08593c..e055e470feb 100644 --- a/pkg/scalers/azure_log_analytics_scaler.go +++ b/pkg/scalers/azure_log_analytics_scaler.go @@ -34,7 +34,6 @@ import ( "github.com/Azure/azure-amqp-common-go/v3/auth" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -283,7 +282,7 @@ func (s *azureLogAnalyticsScaler) GetMetricSpecForScaling(ctx context.Context) [ } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *azureLogAnalyticsScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *azureLogAnalyticsScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { receivedMetric, err := s.getMetricData(ctx) if err != nil { diff --git a/pkg/scalers/azure_monitor_scaler.go b/pkg/scalers/azure_monitor_scaler.go index eef54965f6e..fdb75607a16 100644 --- a/pkg/scalers/azure_monitor_scaler.go +++ b/pkg/scalers/azure_monitor_scaler.go @@ -25,7 +25,6 @@ import ( az "github.com/Azure/go-autorest/autorest/azure" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -241,7 +240,7 @@ func (s *azureMonitorScaler) GetMetricSpecForScaling(context.Context) []v2.Metri } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *azureMonitorScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *azureMonitorScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { val, err := azure.GetAzureMetricValue(ctx, s.metadata.azureMonitorInfo, s.podIdentity) if err != nil { s.logger.Error(err, "error getting azure monitor metric") diff --git a/pkg/scalers/azure_pipelines_scaler.go b/pkg/scalers/azure_pipelines_scaler.go index 5b4bc6a9ae1..7ec6eed649f 100644 --- a/pkg/scalers/azure_pipelines_scaler.go +++ b/pkg/scalers/azure_pipelines_scaler.go @@ -12,7 +12,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -310,7 +309,7 @@ func getAzurePipelineRequest(ctx context.Context, url string, metadata *azurePip return b, nil } -func (s *azurePipelinesScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *azurePipelinesScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { queuelen, err := s.GetAzurePipelinesQueueLength(ctx) if err != nil { diff --git a/pkg/scalers/azure_queue_scaler.go b/pkg/scalers/azure_queue_scaler.go index 78d43e8044d..307836edaa6 100644 --- a/pkg/scalers/azure_queue_scaler.go +++ b/pkg/scalers/azure_queue_scaler.go @@ -24,7 +24,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -195,7 +194,7 @@ func (s *azureQueueScaler) GetMetricSpecForScaling(context.Context) []v2.MetricS } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *azureQueueScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *azureQueueScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { queuelen, err := azure.GetAzureQueueLength( ctx, s.httpClient, diff --git a/pkg/scalers/azure_servicebus_scaler.go b/pkg/scalers/azure_servicebus_scaler.go index a34fcb6d721..590624de52a 100755 --- a/pkg/scalers/azure_servicebus_scaler.go +++ b/pkg/scalers/azure_servicebus_scaler.go @@ -28,7 +28,6 @@ import ( az "github.com/Azure/go-autorest/autorest/azure" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" @@ -271,7 +270,7 @@ func (s *azureServiceBusScaler) GetMetricSpecForScaling(context.Context) []v2.Me } // Returns the current metrics to be served to the HPA -func (s *azureServiceBusScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *azureServiceBusScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { queuelen, err := s.getAzureServiceBusLength(ctx) if err != nil { diff --git a/pkg/scalers/cassandra_scaler.go b/pkg/scalers/cassandra_scaler.go index d07dfc8283c..88f4776c749 100644 --- a/pkg/scalers/cassandra_scaler.go +++ b/pkg/scalers/cassandra_scaler.go @@ -9,7 +9,6 @@ import ( "github.com/go-logr/logr" "github.com/gocql/gocql" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -206,7 +205,7 @@ func (s *cassandraScaler) GetMetricSpecForScaling(ctx context.Context) []v2.Metr } // GetMetrics returns a value for a supported metric or an error if there is a problem getting the metric. -func (s *cassandraScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *cassandraScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { num, err := s.GetQueryResult(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error inspecting cassandra: %s", err) diff --git a/pkg/scalers/cpu_memory_scaler.go b/pkg/scalers/cpu_memory_scaler.go index d403dd4159d..cfd7db7c84b 100644 --- a/pkg/scalers/cpu_memory_scaler.go +++ b/pkg/scalers/cpu_memory_scaler.go @@ -9,7 +9,6 @@ import ( v2 "k8s.io/api/autoscaling/v2" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" ) @@ -123,6 +122,6 @@ func (s *cpuMemoryScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSp } // GetMetrics no need for cpu/memory scaler -func (s *cpuMemoryScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *cpuMemoryScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { return nil, nil } diff --git a/pkg/scalers/cron_scaler.go b/pkg/scalers/cron_scaler.go index 472605f2350..df48185b923 100644 --- a/pkg/scalers/cron_scaler.go +++ b/pkg/scalers/cron_scaler.go @@ -10,7 +10,6 @@ import ( "github.com/go-logr/logr" "github.com/robfig/cron/v3" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -170,7 +169,7 @@ func (s *cronScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec { } // GetMetrics finds the current value of the metric -func (s *cronScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *cronScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { var currentReplicas = int64(defaultDesiredReplicas) isActive, err := s.IsActive(ctx) if err != nil { diff --git a/pkg/scalers/cron_scaler_test.go b/pkg/scalers/cron_scaler_test.go index e763956668c..33123800afb 100644 --- a/pkg/scalers/cron_scaler_test.go +++ b/pkg/scalers/cron_scaler_test.go @@ -93,7 +93,7 @@ func TestIsActiveRange(t *testing.T) { func TestGetMetrics(t *testing.T) { scaler, _ := NewCronScaler(&ScalerConfig{TriggerMetadata: validCronMetadata}) - metrics, _ := scaler.GetMetrics(context.TODO(), "ReplicaCount", nil) + metrics, _ := scaler.GetMetrics(context.TODO(), "ReplicaCount") assert.Equal(t, metrics[0].MetricName, "ReplicaCount") if currentDay == "Thursday" { assert.Equal(t, metrics[0].Value.Value(), int64(10)) @@ -104,7 +104,7 @@ func TestGetMetrics(t *testing.T) { func TestGetMetricsRange(t *testing.T) { scaler, _ := NewCronScaler(&ScalerConfig{TriggerMetadata: validCronMetadata2}) - metrics, _ := scaler.GetMetrics(context.TODO(), "ReplicaCount", nil) + metrics, _ := scaler.GetMetrics(context.TODO(), "ReplicaCount") assert.Equal(t, metrics[0].MetricName, "ReplicaCount") if currentHour%2 == 0 { assert.Equal(t, metrics[0].Value.Value(), int64(10)) diff --git a/pkg/scalers/datadog_scaler.go b/pkg/scalers/datadog_scaler.go index 216f1a27ca5..ffb6940f10c 100644 --- a/pkg/scalers/datadog_scaler.go +++ b/pkg/scalers/datadog_scaler.go @@ -11,7 +11,6 @@ import ( datadog "github.com/DataDog/datadog-api-client-go/api/v1/datadog" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -339,7 +338,7 @@ func (s *datadogScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *datadogScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *datadogScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { num, err := s.getQueryResult(ctx) if err != nil { s.logger.Error(err, "error getting metrics from Datadog") diff --git a/pkg/scalers/elasticsearch_scaler.go b/pkg/scalers/elasticsearch_scaler.go index 3b2803e4343..ae05d7a13ed 100644 --- a/pkg/scalers/elasticsearch_scaler.go +++ b/pkg/scalers/elasticsearch_scaler.go @@ -15,7 +15,6 @@ import ( "github.com/go-logr/logr" "github.com/tidwall/gjson" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -263,7 +262,7 @@ func (s *elasticsearchScaler) GetMetricSpecForScaling(context.Context) []v2.Metr } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *elasticsearchScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *elasticsearchScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { num, err := s.getQueryResult(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error inspecting elasticsearch: %s", err) diff --git a/pkg/scalers/external_mock_scaler.go b/pkg/scalers/external_mock_scaler.go index 982be7bf8ef..2e880e1b103 100644 --- a/pkg/scalers/external_mock_scaler.go +++ b/pkg/scalers/external_mock_scaler.go @@ -8,7 +8,6 @@ import ( v2 "k8s.io/api/autoscaling/v2" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" ) @@ -55,7 +54,7 @@ func (*externalMockScaler) GetMetricSpecForScaling(ctx context.Context) []v2.Met } // GetMetrics implements Scaler -func (*externalMockScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (*externalMockScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { if atomic.LoadInt32(&MockExternalServerStatus) != MockExternalServerStatusOnline { return nil, ErrMock } diff --git a/pkg/scalers/external_scaler.go b/pkg/scalers/external_scaler.go index fa89d80f6ec..2b83ee26cac 100644 --- a/pkg/scalers/external_scaler.go +++ b/pkg/scalers/external_scaler.go @@ -14,7 +14,6 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" pb "github.com/kedacore/keda/v2/pkg/scalers/externalscaler" @@ -186,7 +185,7 @@ func (s *externalScaler) GetMetricSpecForScaling(ctx context.Context) []v2.Metri } // GetMetrics connects calls the gRPC interface to get the metrics with a specific name -func (s *externalScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *externalScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { var metrics []external_metrics.ExternalMetricValue grpcClient, err := getClientForConnectionPool(s.metadata) if err != nil { diff --git a/pkg/scalers/gcp_pubsub_scaler.go b/pkg/scalers/gcp_pubsub_scaler.go index 3f081a17e5b..1e9571f092c 100644 --- a/pkg/scalers/gcp_pubsub_scaler.go +++ b/pkg/scalers/gcp_pubsub_scaler.go @@ -10,7 +10,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -189,7 +188,7 @@ func (s *pubsubScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec } // GetMetrics connects to Stack Driver and finds the size of the pub sub subscription -func (s *pubsubScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *pubsubScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { var value int64 var err error diff --git a/pkg/scalers/gcp_stackdriver_scaler.go b/pkg/scalers/gcp_stackdriver_scaler.go index 2280ad6f557..efb6e70593e 100644 --- a/pkg/scalers/gcp_stackdriver_scaler.go +++ b/pkg/scalers/gcp_stackdriver_scaler.go @@ -8,7 +8,6 @@ import ( monitoringpb "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -202,7 +201,7 @@ func (s *stackdriverScaler) GetMetricSpecForScaling(context.Context) []v2.Metric } // GetMetrics connects to Stack Driver and retrieves the metric -func (s *stackdriverScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *stackdriverScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { value, err := s.getMetrics(ctx) if err != nil { s.logger.Error(err, "error getting metric value") diff --git a/pkg/scalers/gcp_storage_scaler.go b/pkg/scalers/gcp_storage_scaler.go index 004451710d7..5600fc9a2ac 100644 --- a/pkg/scalers/gcp_storage_scaler.go +++ b/pkg/scalers/gcp_storage_scaler.go @@ -11,7 +11,6 @@ import ( "google.golang.org/api/iterator" option "google.golang.org/api/option" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -188,7 +187,7 @@ func (s *gcsScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec { } // GetMetrics returns the number of items in the bucket (up to s.metadata.maxBucketItemsToScan) -func (s *gcsScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *gcsScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { items, err := s.getItemCount(ctx, s.metadata.maxBucketItemsToScan) if err != nil { return []external_metrics.ExternalMetricValue{}, err diff --git a/pkg/scalers/graphite_scaler.go b/pkg/scalers/graphite_scaler.go index 1990e4ae257..0c14982016f 100644 --- a/pkg/scalers/graphite_scaler.go +++ b/pkg/scalers/graphite_scaler.go @@ -11,7 +11,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -224,7 +223,7 @@ func (s *graphiteScaler) executeGrapQuery(ctx context.Context) (float64, error) return -1, fmt.Errorf("no valid non-null response in query %s, try increasing your queryTime or check your query", s.metadata.query) } -func (s *graphiteScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *graphiteScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { val, err := s.executeGrapQuery(ctx) if err != nil { s.logger.Error(err, "error executing graphite query") diff --git a/pkg/scalers/huawei_cloudeye_scaler.go b/pkg/scalers/huawei_cloudeye_scaler.go index 2b6e6d1fc62..f80bcc629cc 100644 --- a/pkg/scalers/huawei_cloudeye_scaler.go +++ b/pkg/scalers/huawei_cloudeye_scaler.go @@ -12,7 +12,6 @@ import ( "github.com/Huawei/gophercloud/openstack/ces/v1/metricdata" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -241,7 +240,7 @@ func gethuaweiAuthorization(authParams map[string]string) (huaweiAuthorizationMe return meta, nil } -func (s *huaweiCloudeyeScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *huaweiCloudeyeScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { metricValue, err := s.GetCloudeyeMetrics() if err != nil { diff --git a/pkg/scalers/ibmmq_scaler.go b/pkg/scalers/ibmmq_scaler.go index db2a5fa1fd9..c6767d31b59 100644 --- a/pkg/scalers/ibmmq_scaler.go +++ b/pkg/scalers/ibmmq_scaler.go @@ -14,7 +14,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -230,7 +229,7 @@ func (s *IBMMQScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec { } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *IBMMQScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *IBMMQScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { queueDepth, err := s.getQueueDepthViaHTTP(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error inspecting IBM MQ queue depth: %s", err) diff --git a/pkg/scalers/influxdb_scaler.go b/pkg/scalers/influxdb_scaler.go index 25a380a7c27..cd1f48b8c5d 100644 --- a/pkg/scalers/influxdb_scaler.go +++ b/pkg/scalers/influxdb_scaler.go @@ -10,7 +10,6 @@ import ( influxdb2 "github.com/influxdata/influxdb-client-go/v2" api "github.com/influxdata/influxdb-client-go/v2/api" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -208,7 +207,7 @@ func queryInfluxDB(ctx context.Context, queryAPI api.QueryAPI, query string) (fl } // GetMetrics connects to influxdb via the client and returns a value based on the query -func (s *influxDBScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *influxDBScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { // Grab QueryAPI to make queries to influxdb instance queryAPI := s.client.QueryAPI(s.metadata.organizationName) diff --git a/pkg/scalers/kafka_scaler.go b/pkg/scalers/kafka_scaler.go index 9899c41c2e8..09fdb684030 100644 --- a/pkg/scalers/kafka_scaler.go +++ b/pkg/scalers/kafka_scaler.go @@ -11,7 +11,6 @@ import ( "github.com/Shopify/sarama" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -501,7 +500,7 @@ func (s *kafkaScaler) getConsumerAndProducerOffsets(topicPartitions map[string][ } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *kafkaScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *kafkaScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { totalLag, err := s.getTotalLag() if err != nil { return []external_metrics.ExternalMetricValue{}, err diff --git a/pkg/scalers/kubernetes_workload_scaler.go b/pkg/scalers/kubernetes_workload_scaler.go index 25ac5de95ea..07a7812655c 100644 --- a/pkg/scalers/kubernetes_workload_scaler.go +++ b/pkg/scalers/kubernetes_workload_scaler.go @@ -116,7 +116,7 @@ func (s *kubernetesWorkloadScaler) GetMetricSpecForScaling(context.Context) []v2 } // GetMetrics returns value for a supported metric -func (s *kubernetesWorkloadScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *kubernetesWorkloadScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { pods, err := s.getMetricValue(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error inspecting kubernetes workload: %s", err) diff --git a/pkg/scalers/liiklus_scaler.go b/pkg/scalers/liiklus_scaler.go index 9cca22035d8..04198828e0d 100644 --- a/pkg/scalers/liiklus_scaler.go +++ b/pkg/scalers/liiklus_scaler.go @@ -11,7 +11,6 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" liiklus_service "github.com/kedacore/keda/v2/pkg/scalers/liiklus" @@ -75,7 +74,7 @@ func NewLiiklusScaler(config *ScalerConfig) (Scaler, error) { return &scaler, nil } -func (s *liiklusScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *liiklusScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { totalLag, lags, err := s.getLag(ctx) if err != nil { return nil, err diff --git a/pkg/scalers/liiklus_scaler_test.go b/pkg/scalers/liiklus_scaler_test.go index f793d8c6611..16d95e65fca 100644 --- a/pkg/scalers/liiklus_scaler_test.go +++ b/pkg/scalers/liiklus_scaler_test.go @@ -140,7 +140,7 @@ func TestLiiklusScalerGetMetricsBehavior(t *testing.T) { GetEndOffsets(gomock.Any(), gomock.Any()). Return(&liiklus.GetEndOffsetsReply{Offsets: map[uint32]uint64{0: 20, 1: 30}}, nil) - values, err := scaler.GetMetrics(context.Background(), "m", nil) + values, err := scaler.GetMetrics(context.Background(), "m") if err != nil { t.Errorf("error calling IsActive: %v", err) return @@ -157,7 +157,7 @@ func TestLiiklusScalerGetMetricsBehavior(t *testing.T) { mockClient.EXPECT(). GetEndOffsets(gomock.Any(), gomock.Any()). Return(&liiklus.GetEndOffsetsReply{Offsets: map[uint32]uint64{0: 20, 1: 30}}, nil) - values, err = scaler.GetMetrics(context.Background(), "m", nil) + values, err = scaler.GetMetrics(context.Background(), "m") if err != nil { t.Errorf("error calling IsActive: %v", err) return diff --git a/pkg/scalers/loki_scaler.go b/pkg/scalers/loki_scaler.go index 0ad0fc41656..d5301ee58bc 100644 --- a/pkg/scalers/loki_scaler.go +++ b/pkg/scalers/loki_scaler.go @@ -11,7 +11,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" "github.com/kedacore/keda/v2/pkg/scalers/authentication" @@ -275,7 +274,7 @@ func (s *lokiScaler) ExecuteLokiQuery(ctx context.Context) (float64, error) { } // GetMetrics returns an external metric value for the loki -func (s *lokiScaler) GetMetrics(ctx context.Context, metricName string, _ labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *lokiScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { val, err := s.ExecuteLokiQuery(ctx) if err != nil { s.logger.Error(err, "error executing loki query") diff --git a/pkg/scalers/metrics_api_scaler.go b/pkg/scalers/metrics_api_scaler.go index f8e7fa33532..08433269e89 100644 --- a/pkg/scalers/metrics_api_scaler.go +++ b/pkg/scalers/metrics_api_scaler.go @@ -14,7 +14,6 @@ import ( "github.com/tidwall/gjson" v2 "k8s.io/api/autoscaling/v2" "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" "github.com/kedacore/keda/v2/pkg/scalers/authentication" @@ -283,7 +282,7 @@ func (s *metricsAPIScaler) GetMetricSpecForScaling(context.Context) []v2.MetricS } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *metricsAPIScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *metricsAPIScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { val, err := s.getMetricValue(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error requesting metrics endpoint: %s", err) diff --git a/pkg/scalers/metrics_api_scaler_test.go b/pkg/scalers/metrics_api_scaler_test.go index badefdfe1c9..7dca8cac2a4 100644 --- a/pkg/scalers/metrics_api_scaler_test.go +++ b/pkg/scalers/metrics_api_scaler_test.go @@ -219,7 +219,7 @@ func TestBearerAuth(t *testing.T) { t.Errorf("Error creating the Scaler") } - _, err = s.GetMetrics(context.TODO(), "test-metric", nil) + _, err = s.GetMetrics(context.TODO(), "test-metric") if err != nil { t.Errorf("Error getting the metric") } diff --git a/pkg/scalers/mongo_scaler.go b/pkg/scalers/mongo_scaler.go index 2c9a868fa79..1fb0b63a044 100644 --- a/pkg/scalers/mongo_scaler.go +++ b/pkg/scalers/mongo_scaler.go @@ -14,7 +14,6 @@ import ( "go.mongodb.org/mongo-driver/mongo/readpref" "go.mongodb.org/mongo-driver/x/bsonx" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -245,7 +244,7 @@ func (s *mongoDBScaler) getQueryResult(ctx context.Context) (int64, error) { } // GetMetrics query from mongoDB,and return to external metrics -func (s *mongoDBScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *mongoDBScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { num, err := s.getQueryResult(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("failed to inspect momgoDB, because of %v", err) diff --git a/pkg/scalers/mssql_scaler.go b/pkg/scalers/mssql_scaler.go index 5e5a82cc086..9bebcf3c521 100644 --- a/pkg/scalers/mssql_scaler.go +++ b/pkg/scalers/mssql_scaler.go @@ -11,7 +11,6 @@ import ( _ "github.com/denisenkom/go-mssqldb" "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -245,7 +244,7 @@ func (s *mssqlScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec { } // GetMetrics returns a value for a supported metric or an error if there is a problem getting the metric -func (s *mssqlScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *mssqlScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { num, err := s.getQueryResult(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error inspecting mssql: %s", err) diff --git a/pkg/scalers/mysql_scaler.go b/pkg/scalers/mysql_scaler.go index ac3e857c372..019e2bf3db3 100644 --- a/pkg/scalers/mysql_scaler.go +++ b/pkg/scalers/mysql_scaler.go @@ -10,7 +10,6 @@ import ( "github.com/go-logr/logr" "github.com/go-sql-driver/mysql" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -229,7 +228,7 @@ func (s *mySQLScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec { } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *mySQLScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *mySQLScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { num, err := s.getQueryResult(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error inspecting MySQL: %s", err) diff --git a/pkg/scalers/nats_jetstream_scaler.go b/pkg/scalers/nats_jetstream_scaler.go index b038551bd95..df25fe3a239 100644 --- a/pkg/scalers/nats_jetstream_scaler.go +++ b/pkg/scalers/nats_jetstream_scaler.go @@ -12,7 +12,6 @@ import ( v2 "k8s.io/api/autoscaling/v2" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -229,7 +228,7 @@ func (s *natsJetStreamScaler) GetMetricSpecForScaling(context.Context) []v2.Metr return []v2.MetricSpec{metricSpec} } -func (s *natsJetStreamScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *natsJetStreamScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, s.metadata.monitoringEndpoint, nil) if err != nil { return nil, err diff --git a/pkg/scalers/newrelic_scaler.go b/pkg/scalers/newrelic_scaler.go index 8ff30837278..cf2fd78bebb 100644 --- a/pkg/scalers/newrelic_scaler.go +++ b/pkg/scalers/newrelic_scaler.go @@ -10,7 +10,6 @@ import ( "github.com/newrelic/newrelic-client-go/newrelic" "github.com/newrelic/newrelic-client-go/pkg/nrdb" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -173,7 +172,7 @@ func (s *newrelicScaler) executeNewRelicQuery(ctx context.Context) (float64, err return 0, nil } -func (s *newrelicScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *newrelicScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { val, err := s.executeNewRelicQuery(ctx) if err != nil { s.logger.Error(err, "error executing NRQL query") diff --git a/pkg/scalers/openstack_metrics_scaler.go b/pkg/scalers/openstack_metrics_scaler.go index 17f82a4255f..e026948a445 100644 --- a/pkg/scalers/openstack_metrics_scaler.go +++ b/pkg/scalers/openstack_metrics_scaler.go @@ -13,7 +13,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" "github.com/kedacore/keda/v2/pkg/scalers/openstack" @@ -233,7 +232,7 @@ func (s *openstackMetricScaler) GetMetricSpecForScaling(context.Context) []v2.Me return []v2.MetricSpec{metricSpec} } -func (s *openstackMetricScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *openstackMetricScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { val, err := s.readOpenstackMetrics(ctx) if err != nil { diff --git a/pkg/scalers/openstack_swift_scaler.go b/pkg/scalers/openstack_swift_scaler.go index 2725443e3f9..3f0927e75ab 100644 --- a/pkg/scalers/openstack_swift_scaler.go +++ b/pkg/scalers/openstack_swift_scaler.go @@ -12,7 +12,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" "github.com/kedacore/keda/v2/pkg/scalers/openstack" @@ -383,7 +382,7 @@ func (s *openstackSwiftScaler) Close(context.Context) error { return nil } -func (s *openstackSwiftScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *openstackSwiftScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { objectCount, err := s.getOpenstackSwiftContainerObjectCount(ctx) if err != nil { diff --git a/pkg/scalers/postgresql_scaler.go b/pkg/scalers/postgresql_scaler.go index ca95ee07b46..6bd4203b05d 100644 --- a/pkg/scalers/postgresql_scaler.go +++ b/pkg/scalers/postgresql_scaler.go @@ -10,7 +10,6 @@ import ( // PostreSQL drive required for this scaler _ "github.com/lib/pq" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -203,7 +202,7 @@ func (s *postgreSQLScaler) GetMetricSpecForScaling(context.Context) []v2.MetricS } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *postgreSQLScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *postgreSQLScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { num, err := s.getActiveNumber(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error inspecting postgreSQL: %s", err) diff --git a/pkg/scalers/predictkube_scaler.go b/pkg/scalers/predictkube_scaler.go index b13df42e741..1436185aeb6 100644 --- a/pkg/scalers/predictkube_scaler.go +++ b/pkg/scalers/predictkube_scaler.go @@ -27,7 +27,6 @@ import ( health "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/status" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" "github.com/kedacore/keda/v2/pkg/scalers/authentication" @@ -220,7 +219,7 @@ func (s *PredictKubeScaler) GetMetricSpecForScaling(context.Context) []v2.Metric return []v2.MetricSpec{metricSpec} } -func (s *PredictKubeScaler) GetMetrics(ctx context.Context, metricName string, _ labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *PredictKubeScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { value, err := s.doPredictRequest(ctx) if err != nil { s.logger.Error(err, "error executing query to predict controller service") diff --git a/pkg/scalers/predictkube_scaler_test.go b/pkg/scalers/predictkube_scaler_test.go index a2ee3825a9a..97c072a604c 100644 --- a/pkg/scalers/predictkube_scaler_test.go +++ b/pkg/scalers/predictkube_scaler_test.go @@ -217,7 +217,7 @@ func TestPredictKubeGetMetrics(t *testing.T) { ) assert.NoError(t, err) - result, err := mockPredictKubeScaler.GetMetrics(context.Background(), predictKubeMetricPrefix, nil) + result, err := mockPredictKubeScaler.GetMetrics(context.Background(), predictKubeMetricPrefix) assert.NoError(t, err) assert.Equal(t, len(result), 1) assert.Equal(t, result[0].Value, *resource.NewMilliQuantity(mockPredictServer.val*1000, resource.DecimalSI)) diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index 38cacc0fc1b..c44acc5f812 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -13,7 +13,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" "github.com/kedacore/keda/v2/pkg/scalers/authentication" @@ -310,7 +309,7 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error return v, nil } -func (s *prometheusScaler) GetMetrics(ctx context.Context, metricName string, _ labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *prometheusScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { val, err := s.ExecutePromQuery(ctx) if err != nil { s.logger.Error(err, "error executing prometheus query") diff --git a/pkg/scalers/pulsar_scaler.go b/pkg/scalers/pulsar_scaler.go index a0286bdd91b..cd68b58d344 100644 --- a/pkg/scalers/pulsar_scaler.go +++ b/pkg/scalers/pulsar_scaler.go @@ -13,7 +13,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" "github.com/kedacore/keda/v2/pkg/scalers/authentication" @@ -271,7 +270,7 @@ func (s *pulsarScaler) IsActive(ctx context.Context) (bool, error) { } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *pulsarScaler) GetMetrics(ctx context.Context, metricName string, _ labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *pulsarScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { msgBacklog, found, err := s.getMsgBackLog(ctx) if err != nil { return nil, fmt.Errorf("error requesting stats from url: %s", err) diff --git a/pkg/scalers/pulsar_scaler_test.go b/pkg/scalers/pulsar_scaler_test.go index 7e3f000f6a9..2146c85e9e5 100644 --- a/pkg/scalers/pulsar_scaler_test.go +++ b/pkg/scalers/pulsar_scaler_test.go @@ -276,7 +276,7 @@ func TestPulsarGetMetric(t *testing.T) { metricSpec := mockPulsarScaler.GetMetricSpecForScaling(context.TODO()) metricName := metricSpec[0].External.Metric.Name - metric, err := mockPulsarScaler.GetMetrics(context.TODO(), metricName, nil) + metric, err := mockPulsarScaler.GetMetrics(context.TODO(), metricName) if err != nil { t.Fatal("Failed:", err) } diff --git a/pkg/scalers/rabbitmq_scaler.go b/pkg/scalers/rabbitmq_scaler.go index dcff282cdc5..a449f060ae4 100644 --- a/pkg/scalers/rabbitmq_scaler.go +++ b/pkg/scalers/rabbitmq_scaler.go @@ -14,7 +14,6 @@ import ( "github.com/go-logr/logr" "github.com/streadway/amqp" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -501,7 +500,7 @@ func (s *rabbitMQScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpe } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *rabbitMQScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *rabbitMQScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { messages, publishRate, err := s.getQueueStatus() if err != nil { return []external_metrics.ExternalMetricValue{}, s.anonimizeRabbitMQError(err) diff --git a/pkg/scalers/redis_scaler.go b/pkg/scalers/redis_scaler.go index 8f576156bbd..50a740da864 100644 --- a/pkg/scalers/redis_scaler.go +++ b/pkg/scalers/redis_scaler.go @@ -10,7 +10,6 @@ import ( "github.com/go-logr/logr" "github.com/go-redis/redis/v8" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -251,7 +250,7 @@ func (s *redisScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec { } // GetMetrics connects to Redis and finds the length of the list -func (s *redisScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *redisScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { listLen, err := s.getListLengthFn(ctx) if err != nil { diff --git a/pkg/scalers/redis_streams_scaler.go b/pkg/scalers/redis_streams_scaler.go index 6609a61bb7f..349a731cc9e 100644 --- a/pkg/scalers/redis_streams_scaler.go +++ b/pkg/scalers/redis_streams_scaler.go @@ -8,7 +8,6 @@ import ( "github.com/go-logr/logr" "github.com/go-redis/redis/v8" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -223,7 +222,7 @@ func (s *redisStreamsScaler) GetMetricSpecForScaling(context.Context) []v2.Metri } // GetMetrics fetches the number of pending entries for a consumer group in a stream -func (s *redisStreamsScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *redisStreamsScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { pendingEntriesCount, err := s.getPendingEntriesCountFn(ctx) if err != nil { diff --git a/pkg/scalers/scaler.go b/pkg/scalers/scaler.go index 210e6c6195a..8f8554df7c5 100644 --- a/pkg/scalers/scaler.go +++ b/pkg/scalers/scaler.go @@ -27,7 +27,6 @@ import ( v2 "k8s.io/api/autoscaling/v2" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" logf "sigs.k8s.io/controller-runtime/pkg/log" @@ -44,7 +43,7 @@ func init() { type Scaler interface { // The scaler returns the metric values for a metric Name and criteria matching the selector - GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) + GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) // Returns the metrics based on which this scaler determines that the ScaleTarget scales. This is used to construct the HPA spec that is created for // this scaled object. The labels used should match the selectors used in GetMetrics diff --git a/pkg/scalers/selenium_grid_scaler.go b/pkg/scalers/selenium_grid_scaler.go index e0bf4fda887..7273d572ac2 100644 --- a/pkg/scalers/selenium_grid_scaler.go +++ b/pkg/scalers/selenium_grid_scaler.go @@ -14,7 +14,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -153,7 +152,7 @@ func (s *seleniumGridScaler) Close(context.Context) error { return nil } -func (s *seleniumGridScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *seleniumGridScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { sessions, err := s.getSessionsCount(ctx, s.logger) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("error requesting selenium grid endpoint: %s", err) diff --git a/pkg/scalers/solace_scaler.go b/pkg/scalers/solace_scaler.go index 54ff215c0a9..91e67744a13 100644 --- a/pkg/scalers/solace_scaler.go +++ b/pkg/scalers/solace_scaler.go @@ -10,7 +10,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -348,7 +347,7 @@ func (s *SolaceScaler) getSolaceQueueMetricsFromSEMP(ctx context.Context) (Solac // INTERFACE METHOD // Call SEMP API to retrieve metrics // returns value for named metric -func (s *SolaceScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *SolaceScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { var metricValues, mv SolaceMetricValues var mve error if mv, mve = s.getSolaceQueueMetricsFromSEMP(ctx); mve != nil { diff --git a/pkg/scalers/stan_scaler.go b/pkg/scalers/stan_scaler.go index fc8cf697bb4..5dae5fe33d0 100644 --- a/pkg/scalers/stan_scaler.go +++ b/pkg/scalers/stan_scaler.go @@ -10,7 +10,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" - "k8s.io/apimachinery/pkg/labels" "k8s.io/metrics/pkg/apis/external_metrics" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -242,7 +241,7 @@ func (s *stanScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec { } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *stanScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *stanScaler) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { req, err := http.NewRequestWithContext(ctx, "GET", s.metadata.monitoringEndpoint, nil) if err != nil { return nil, err diff --git a/pkg/scaling/cache/scalers_cache.go b/pkg/scaling/cache/scalers_cache.go index 314c361fa12..8053a8ddd4d 100644 --- a/pkg/scaling/cache/scalers_cache.go +++ b/pkg/scaling/cache/scalers_cache.go @@ -24,7 +24,6 @@ import ( "github.com/go-logr/logr" v2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/record" "k8s.io/metrics/pkg/apis/external_metrics" logf "sigs.k8s.io/controller-runtime/pkg/log" @@ -35,10 +34,11 @@ import ( ) type ScalersCache struct { - Generation int64 - Scalers []ScalerBuilder - Logger logr.Logger - Recorder record.EventRecorder + ScaledObject kedav1alpha1.ScaledObject + Generation int64 + Scalers []ScalerBuilder + Logger logr.Logger + Recorder record.EventRecorder } type ScalerBuilder struct { @@ -68,11 +68,11 @@ func (c *ScalersCache) GetPushScalers() []scalers.PushScaler { return result } -func (c *ScalersCache) GetMetricsForScaler(ctx context.Context, id int, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (c *ScalersCache) GetMetricsForScaler(ctx context.Context, id int, metricName string) ([]external_metrics.ExternalMetricValue, error) { if id < 0 || id >= len(c.Scalers) { return nil, fmt.Errorf("scaler with id %d not found. Len = %d", id, len(c.Scalers)) } - m, err := c.Scalers[id].Scaler.GetMetrics(ctx, metricName, metricSelector) + m, err := c.Scalers[id].Scaler.GetMetrics(ctx, metricName) if err == nil { return m, nil } @@ -82,7 +82,7 @@ func (c *ScalersCache) GetMetricsForScaler(ctx context.Context, id int, metricNa return nil, err } - return ns.GetMetrics(ctx, metricName, metricSelector) + return ns.GetMetrics(ctx, metricName) } func (c *ScalersCache) IsScaledObjectActive(ctx context.Context, scaledObject *kedav1alpha1.ScaledObject) (bool, bool, []external_metrics.ExternalMetricValue) { @@ -180,16 +180,16 @@ func (c *ScalersCache) IsScaledJobActive(ctx context.Context, scaledJob *kedav1a return isActive, ceilToInt64(queueLength), ceilToInt64(maxValue) } -func (c *ScalersCache) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (c *ScalersCache) GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error) { var metrics []external_metrics.ExternalMetricValue for i, s := range c.Scalers { - m, err := s.Scaler.GetMetrics(ctx, metricName, metricSelector) + m, err := s.Scaler.GetMetrics(ctx, metricName) if err != nil { ns, err := c.refreshScaler(ctx, i) if err != nil { return metrics, err } - m, err = ns.GetMetrics(ctx, metricName, metricSelector) + m, err = ns.GetMetrics(ctx, metricName) if err != nil { return metrics, err } @@ -282,7 +282,7 @@ func (c *ScalersCache) getScaledJobMetrics(ctx context.Context, scaledJob *kedav targetAverageValue = getTargetAverageValue(metricSpecs) - metrics, err := s.Scaler.GetMetrics(ctx, metricSpecs[0].External.Metric.Name, nil) + metrics, err := s.Scaler.GetMetrics(ctx, metricSpecs[0].External.Metric.Name) if err != nil { scalerLogger.V(1).Info("Error getting scaler metrics, but continue", "Error", err) c.Recorder.Event(scaledJob, corev1.EventTypeWarning, eventreason.KEDAScalerFailed, err.Error()) diff --git a/pkg/scaling/cache/scalers_cache_test.go b/pkg/scaling/cache/scalers_cache_test.go index 10d651f46ac..fd73a8a01ab 100644 --- a/pkg/scaling/cache/scalers_cache_test.go +++ b/pkg/scaling/cache/scalers_cache_test.go @@ -280,7 +280,7 @@ func createScaler(ctrl *gomock.Controller, queueLength int64, averageValue int64 } scaler.EXPECT().IsActive(gomock.Any()).Return(isActive, nil) scaler.EXPECT().GetMetricSpecForScaling(gomock.Any()).Return(metricsSpecs) - scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Any(), nil).Return(metrics, nil) + scaler.EXPECT().GetMetrics(gomock.Any(), gomock.Any()).Return(metrics, nil) scaler.EXPECT().Close(gomock.Any()) return scaler } diff --git a/pkg/scaling/scale_handler.go b/pkg/scaling/scale_handler.go index 4bde8291454..d065782d291 100644 --- a/pkg/scaling/scale_handler.go +++ b/pkg/scaling/scale_handler.go @@ -19,6 +19,7 @@ package scaling import ( "context" "fmt" + "strings" "sync" "time" @@ -28,11 +29,13 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/scale" "k8s.io/client-go/tools/record" + "k8s.io/metrics/pkg/apis/external_metrics" "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/log" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" "github.com/kedacore/keda/v2/pkg/eventreason" + "github.com/kedacore/keda/v2/pkg/fallback" "github.com/kedacore/keda/v2/pkg/scalers" "github.com/kedacore/keda/v2/pkg/scaling/cache" "github.com/kedacore/keda/v2/pkg/scaling/executor" @@ -46,6 +49,9 @@ type ScaleHandler interface { DeleteScalableObject(ctx context.Context, scalableObject interface{}) error GetScalersCache(ctx context.Context, scalableObject interface{}) (*cache.ScalersCache, error) ClearScalersCache(ctx context.Context, scalableObject interface{}) error + + GetScalersCacheForScaledObject(ctx context.Context, scaledObjectName, scaledObjectNamespace string) (*cache.ScalersCache, error) + GetExternalMetricsValuesList(ctx context.Context, cache *cache.ScalersCache, scaledObject *kedav1alpha1.ScaledObject, metricName string) (*external_metrics.ExternalMetricValueList, error) } type scaleHandler struct { @@ -163,6 +169,56 @@ func (h *scaleHandler) startScaleLoop(ctx context.Context, withTriggers *kedav1a } } +func (h *scaleHandler) GetScalersCacheForScaledObject(ctx context.Context, scaledObjectName, scaledObjectNamespace string) (*cache.ScalersCache, error) { + key := kedav1alpha1.GenerateIdenitifier("ScaledObject", scaledObjectName, scaledObjectNamespace) + + h.lock.RLock() + if cache, ok := h.scalerCaches[key]; ok { + h.lock.RUnlock() + return cache, nil + } + h.lock.RUnlock() + + h.lock.Lock() + defer h.lock.Unlock() + if cache, ok := h.scalerCaches[key]; ok { + return cache, nil + } + + scaledObject := &kedav1alpha1.ScaledObject{} + err := h.client.Get(ctx, types.NamespacedName{Name: scaledObjectName, Namespace: scaledObjectNamespace}, scaledObject) + if err != nil { + h.logger.Error(err, "failed to get ScaledObject", "name", scaledObjectName, "namespace", scaledObjectNamespace) + return nil, err + } + + podTemplateSpec, containerName, err := resolver.ResolveScaleTargetPodSpec(ctx, h.client, h.logger, scaledObject) + if err != nil { + return nil, err + } + + withTriggers, err := asDuckWithTriggers(scaledObject) + if err != nil { + return nil, err + } + + scalers, err := h.buildScalers(ctx, withTriggers, podTemplateSpec, containerName) + if err != nil { + return nil, err + } + + h.scalerCaches[key] = &cache.ScalersCache{ + ScaledObject: *scaledObject, + Generation: withTriggers.Generation, + Scalers: scalers, + Logger: h.logger, + Recorder: h.recorder, + } + + return h.scalerCaches[key], nil +} + +// TODO refactor this together with GetScalersCacheForScaledObject() func (h *scaleHandler) GetScalersCache(ctx context.Context, scalableObject interface{}) (*cache.ScalersCache, error) { withTriggers, err := asDuckWithTriggers(scalableObject) if err != nil { @@ -196,12 +252,19 @@ func (h *scaleHandler) GetScalersCache(ctx context.Context, scalableObject inter return nil, err } - h.scalerCaches[key] = &cache.ScalersCache{ + newCache := &cache.ScalersCache{ Generation: withTriggers.Generation, Scalers: scalers, Logger: h.logger, Recorder: h.recorder, } + switch obj := scalableObject.(type) { + case *kedav1alpha1.ScaledObject: + newCache.ScaledObject = *obj + default: + } + + h.scalerCaches[key] = newCache return h.scalerCaches[key], nil } @@ -288,6 +351,65 @@ func (h *scaleHandler) checkScalers(ctx context.Context, scalableObject interfac } } +func (h *scaleHandler) GetExternalMetricsValuesList(ctx context.Context, cache *cache.ScalersCache, scaledObject *kedav1alpha1.ScaledObject, metricName string) (*external_metrics.ExternalMetricValueList, error) { + var matchingMetrics []external_metrics.ExternalMetricValue + + // let's check metrics for all scalers in a ScaledObject + scalerError := false + scalers, scalerConfigs := cache.GetScalers() + for scalerIndex := 0; scalerIndex < len(scalers); scalerIndex++ { + metricSpecs := scalers[scalerIndex].GetMetricSpecForScaling(ctx) + scalerName := strings.Replace(fmt.Sprintf("%T", scalers[scalerIndex]), "*scalers.", "", 1) + if scalerConfigs[scalerIndex].TriggerName != "" { + scalerName = scalerConfigs[scalerIndex].TriggerName + } + + for _, metricSpec := range metricSpecs { + // skip cpu/memory resource scaler + if metricSpec.External == nil { + continue + } + + // Filter only the desired metric + if strings.EqualFold(metricSpec.External.Metric.Name, metricName) { + metrics, err := cache.GetMetricsForScaler(ctx, scalerIndex, metricName) + metrics, err = fallback.GetMetricsWithFallback(ctx, h.client, h.logger, metrics, err, metricName, scaledObject, metricSpec) + if err != nil { + scalerError = true + h.logger.Error(err, "error getting metric for scaler", "scaledObject.Namespace", scaledObject.Namespace, "scaledObject.Name", scaledObject.Name, "scaler", scalerName) + } else { + // TODO fix Prom metrics recorder + // for _, metric := range metrics { + // metricValue := metric.Value.AsApproximateFloat64() + // metricsServer.RecordHPAScalerMetric(scaledObject.Namespace, scaledObject.Name, scalerName, scalerIndex, metric.MetricName, metricValue) + // } + matchingMetrics = append(matchingMetrics, metrics...) + } + // TODO fix Prom metrics recorder + // metricsServer.RecordHPAScalerError(scaledObject.Namespace, scaledObject.Name, scalerName, scalerIndex, metricName, err) + } + } + } + + // invalidate the cache for the ScaledObject, if we hit an error in any scaler + // in this case we try to build all scalers (and resolve all secrets/creds) again in the next call + if scalerError { + err := h.ClearScalersCache(ctx, scaledObject) + if err != nil { + h.logger.Error(err, "error clearing scalers cache") + } + h.logger.V(1).Info("scaler error encountered, clearing scaler cache") + } + + if len(matchingMetrics) == 0 { + return nil, fmt.Errorf("no matching metrics found for " + metricName) + } + + return &external_metrics.ExternalMetricValueList{ + Items: matchingMetrics, + }, nil +} + // buildScalers returns list of Scalers for the specified triggers func (h *scaleHandler) buildScalers(ctx context.Context, withTriggers *kedav1alpha1.WithTriggers, podTemplateSpec *corev1.PodTemplateSpec, containerName string) ([]cache.ScalerBuilder, error) { logger := h.logger.WithValues("type", withTriggers.Kind, "namespace", withTriggers.Namespace, "name", withTriggers.Name)