From be371fc77f13902aefe0f8ef9fa2ef9b4c9a9d14 Mon Sep 17 00:00:00 2001 From: Andrey Anastasov <98102124+andrerun@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:23:42 +0200 Subject: [PATCH 1/8] Apply review comments. Add debug support --- Dockerfile | 6 +- Makefile | 27 +++- README.md | 22 +--- VERSION | 2 +- example/custom-metrics-deployment.yaml | 19 ++- example/custom-metrics-service.yaml | 7 +- example/rbac.yaml | 2 +- go.mod | 13 +- hack/gardener-util/tools.mk | 2 +- pkg/app/cli_options.go | 2 +- pkg/ha/ha_service.go | 13 +- pkg/ha/ha_service_test.go | 3 + pkg/input/controller/pod/predicate.go | 4 +- pkg/input/controller/secret/actuator.go | 2 +- pkg/input/controller/secret/predicate.go | 2 +- pkg/input/controller/secret/predicate_test.go | 6 +- pkg/input/input_data_service_test.go | 5 + pkg/input/metrics_scraper/pacemaker.go | 2 +- pkg/input/metrics_scraper/pacemaker_test.go | 13 ++ .../metrics_scraper/scrape_queue_test.go | 23 ++++ pkg/input/metrics_scraper/scraper_test.go | 22 ++++ pkg/metrics_provider/metrics_provider.go | 2 +- .../metrics_provider_service_test.go | 1 + pkg/metrics_provider/metrics_provider_test.go | 5 + pkg/util/gardener/options_test.go | 3 + pkg/util/gardener/util.go | 4 +- pkg/util/gardener/util_test.go | 10 +- skaffold.yaml | 115 ++++++++++++++++++ 28 files changed, 270 insertions(+), 67 deletions(-) create mode 100644 skaffold.yaml diff --git a/Dockerfile b/Dockerfile index c598f4c6..5aea163e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,6 @@ FROM golang:1.19.9 AS builder WORKDIR /go/src/github.com/gardener/gardener-custom-metrics COPY . . RUN make install -# RUN CGO_ENABLED=0 GO111MODULE=on GOFLAGS=-mod=vendor go build -a -o gardener-custom-metrics.exe cmd/main.go ############# base image # TODO: Andrey: P1: Move to distroless FROM alpine:3.18.0 AS base @@ -13,6 +12,5 @@ FROM alpine:3.18.0 AS base FROM base AS gardener-custom-metrics WORKDIR / -COPY --from=builder /go/bin/gardener-custom-metrics /gardener-custom-metrics.exe -# COPY --from=builder /go/src/github.com/gardener/gardener-custom-metrics/gardener-custom-metrics.exe . -ENTRYPOINT ["/gardener-custom-metrics.exe"] +COPY --from=builder /go/bin/gardener-custom-metrics /gardener-custom-metrics +ENTRYPOINT ["/gardener-custom-metrics"] diff --git a/Makefile b/Makefile index 91830331..cb156418 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +BUILD_DATE := $(shell date '+%Y-%m-%dT%H:%M:%S%z' | sed 's/\([0-9][0-9]\)$$/:\1/g') NAME := gardener-custom-metrics -# IMAGE_REGISTRY_URI := eu.gcr.io/gardener-project/gardener/$(NAME) -IMAGE_REGISTRY_URI := eu.gcr.io/sap-se-gcp-scp-k8s/$(NAME) +IMAGE_REGISTRY_URI := eu.gcr.io/gardener-project/gardener +# IMAGE_REGISTRY_URI := eu.gcr.io/sap-se-gcp-scp-k8s/$(NAME) REPO_ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) VERSION := $(shell cat "$(REPO_ROOT)/VERSION") EFFECTIVE_VERSION := $(VERSION)-$(shell git rev-parse HEAD) @@ -30,6 +31,7 @@ ifneq ($(strip $(shell git status --porcelain 2>/dev/null)),) EFFECTIVE_VERSION := $(EFFECTIVE_VERSION)-dirty endif +LD_FLAGS_DEBUG := "$(shell EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) $(REPO_ROOT)/hack/gardener-util/get-build-ld-flags.sh k8s.io/component-base $(REPO_ROOT)/VERSION $(EXTENSION_PREFIX)-$(NAME))" LD_FLAGS := "-w $(shell EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) $(REPO_ROOT)/hack/gardener-util/get-build-ld-flags.sh k8s.io/component-base $(REPO_ROOT)/VERSION $(EXTENSION_PREFIX)-$(NAME))" TOOLS_DIR := $(REPO_ROOT)/hack/gardener-util/tools @@ -136,3 +138,24 @@ verify: check check-docforge format test .PHONY: verify-extended verify-extended: check-generate check check-docforge format test test-cov test-clean + +# skaffold dev and debug clean up deployed modules by default, disable this +debug: export SKAFFOLD_CLEANUP = false +# Artifacts might be already built when you decide to start debugging. +# However, these artifacts do not include the gcflags which `skaffold debug` sets automatically, so delve would not work. +# Disabling the skaffold cache for debugging ensures that you run artifacts with gcflags required for debugging. +debug: export SKAFFOLD_CACHE_ARTIFACTS = false + +debug: export SOURCE_DATE_EPOCH = $(shell date -d $(BUILD_DATE) +%s) + +.PHONY: debug +debug: $(SKAFFOLD) + @echo "LD_FLAGS: $(LD_FLAGS_DEBUG)" + @LD_FLAGS=$(LD_FLAGS) $(SKAFFOLD) debug + # TODO: Andrey: P1: code cleanup + # export SKAFFOLD_DEFAULT_REPO = localhost:5001 + # export SKAFFOLD_PUSH = true + + # skaffold dev triggers new builds and deployments immediately on file changes by default, + # this is too heavy in a large project like gardener, so trigger new builds and deployments manually instead. + # gardener%dev gardenlet%dev operator-dev: export SKAFFOLD_TRIGGER = manual diff --git a/README.md b/README.md index f57ab13e..8fdafd8e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,6 @@ -pkg directory: -``` -├── input - Takes care of source data: tracks seed's k8s contents, scrapes ShootKapis -│ ├── controller -│ │ ├── ... -│ │ ├── pod -│ │ │ └── ... -│ │ └── secret -│ │ └── ... -│ ├── input_data_registry - Repository for the metrics source data -│ │ └── input_data_registry.go -│ └── input_data_service.go - Primary responsible for providing input data -└── metrics_provider_service - Serves k8s metrics via HTTP - ├── metrics_provider.go - Implements the provider interface required by the metrics server library - └── metrics_provider_service.go - Primary responsible for serving K8s metrics -``` \ No newline at end of file +# gardener-custom-metrics +[![reuse compliant](https://reuse.software/badge/reuse-compliant.svg)](https://reuse.software/) +## Overview +The `gardener-custom-metrics` component operates as a K8s API service, adding functionality to the seed kube-apiserver. +It periodically scrapes the metrics endpoints of all shoot kube-apiserver pods on the seed. It implements the K8s custom +metrics API and provides K8s metrics specific to Gardener, based on custom calculations. diff --git a/VERSION b/VERSION index 0a90cf07..2787740c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.10.7-dev \ No newline at end of file +v0.10.11-dev \ No newline at end of file diff --git a/example/custom-metrics-deployment.yaml b/example/custom-metrics-deployment.yaml index de158b5c..ee7edc56 100644 --- a/example/custom-metrics-deployment.yaml +++ b/example/custom-metrics-deployment.yaml @@ -1,7 +1,9 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: gardener-custom-metrics + labels: + app: gardener-custom-metrics + name: gardener-custom-metrics-debug namespace: garden spec: replicas: 1 @@ -9,23 +11,21 @@ spec: matchLabels: app: gardener-custom-metrics gardener.cloud/role: gardener-custom-metrics - resources.gardener.cloud/managed-by-xxx: gardener + resources.gardener.cloud/managed-by: gardener template: metadata: labels: app: gardener-custom-metrics gardener.cloud/role: gardener-custom-metrics - resources.gardener.cloud/managed-by-xxx: gardener + resources.gardener.cloud/managed-by: gardener networking.gardener.cloud/from-seed: allowed networking.gardener.cloud/to-dns: allowed - networking.gardener.cloud/to-seed-apiserver: allowed + networking.gardener.cloud/to-runtime-apiserver: allowed networking.resources.gardener.cloud/to-all-shoots-kube-apiserver-tcp-443: allowed networking.gardener.cloud/to-apiserver: allowed - spec: containers: - - command: - - ./gardener-custom-metrics.exe + - args: - --secure-port=6443 - --tls-cert-file=/var/run/secrets/gardener.cloud/tls/tls.crt - --tls-private-key-file=/var/run/secrets/gardener.cloud/tls/tls.key @@ -44,7 +44,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - image: eu.gcr.io/sap-se-gcp-scp-k8s/gardener-custom-metrics/gardener-custom-metrics:v0.10.4-dev + image: eu.gcr.io/gardener-project/gardener/gardener-custom-metrics:v0.10.9-dev imagePullPolicy: IfNotPresent name: gardener-custom-metrics ports: @@ -72,13 +72,12 @@ spec: securityContext: seccompProfile: type: RuntimeDefault - serviceAccount: gardener-custom-metrics serviceAccountName: gardener-custom-metrics terminationGracePeriodSeconds: 30 volumes: - name: gardener-custom-metrics-tls secret: - secretName: gardener-custom-metrics-tls + secretName: gardener-custom-metrics-tls-121d8b86 # TODO: Andrey: P1: This is dynamic - name: kube-api-access-gardener projected: defaultMode: 420 diff --git a/example/custom-metrics-service.yaml b/example/custom-metrics-service.yaml index 52e62965..270f00e8 100644 --- a/example/custom-metrics-service.yaml +++ b/example/custom-metrics-service.yaml @@ -13,11 +13,10 @@ spec: protocol: TCP targetPort: 6443 publishNotReadyAddresses: true - selector: - app: gardener-custom-metrics - gardener.cloud/role: gardener-custom-metrics - resources.gardener.cloud/managed-by-xxx: gardener sessionAffinity: None type: ClusterIP + # This service intentionally does not contain a pod selector. As a result, KCM does not perform any endpoint management. + # Endpoint management is instead done by the gardener-custom-metrics leader instance, which ensures a single endpoint, + # directing all traffic to the leader. status: loadBalancer: {} \ No newline at end of file diff --git a/example/rbac.yaml b/example/rbac.yaml index b571a43e..e080bd6e 100644 --- a/example/rbac.yaml +++ b/example/rbac.yaml @@ -93,7 +93,7 @@ rules: - "" resources: - secrets - # resourceNames: [ "ca", "shoot-access-prometheus" ] # TODO: Andrey: P1: How to write code so we can use name-based restriction? + # resourceNames: [ "ca", "shoot-access-gardener-custom-metrics" ] # TODO: Andrey: P1: How to write code so we can use name-based restriction? verbs: - get - list diff --git a/go.mod b/go.mod index f438f0a7..2b535378 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,17 @@ module github.com/gardener/gardener-custom-metrics -go 1.19 +go 1.21 require ( github.com/go-logr/logr v1.2.4 - github.com/spf13/cobra v1.6.1 + github.com/onsi/ginkgo/v2 v2.11.0 + github.com/onsi/gomega v1.27.8 + github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 go.uber.org/zap v1.21.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/time v0.3.0 + golang.org/x/tools v0.9.3 k8s.io/api v0.23.17 // v0.24.0 // v0.24.4 k8s.io/apimachinery v0.23.17 // v0.24.0 // v0.24.4 k8s.io/apiserver v0.23.17 // v0.24.4 @@ -22,12 +25,6 @@ require ( sigs.k8s.io/metrics-server v0.6.4 ) -require ( - github.com/onsi/ginkgo/v2 v2.11.0 - github.com/onsi/gomega v1.27.8 - golang.org/x/tools v0.9.3 -) - require ( github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/PuerkitoBio/purell v1.2.0 // indirect diff --git a/hack/gardener-util/tools.mk b/hack/gardener-util/tools.mk index a90a90cc..76572d15 100755 --- a/hack/gardener-util/tools.mk +++ b/hack/gardener-util/tools.mk @@ -61,7 +61,7 @@ HELM_VERSION ?= v3.11.2 KIND_VERSION ?= v0.18.0 KUBECTL_VERSION ?= v1.24.11 PROTOC_VERSION ?= 23.4 -SKAFFOLD_VERSION ?= v2.2.0 +SKAFFOLD_VERSION ?= v2.9.0 YQ_VERSION ?= v4.31.2 export TOOLS_BIN_DIR := $(TOOLS_BIN_DIR) diff --git a/pkg/app/cli_options.go b/pkg/app/cli_options.go index f6ed278a..db25a2af 100644 --- a/pkg/app/cli_options.go +++ b/pkg/app/cli_options.go @@ -139,7 +139,7 @@ func (c *CLIConfig) ManagerOptions() manager.Options { // TODO: Andrey: P2: Enable after switching from prometheus' secret (which does not have 'name' label), to ours. // It will prevent retrieving and caching unnecessary secrets. // - //nameRequirement, _ := labels.NewRequirement("name", selection.In, []string{"ca", "shoot-access-prometheus"}) + //nameRequirement, _ := labels.NewRequirement("name", selection.In, []string{"ca", "shoot-access-gardener-custom-metrics"}) //selector := labels.NewSelector().Add(*nameRequirement) //opts.NewCache = cache.BuilderWithOptions(cache.Options{ // SelectorsByObject: cache.SelectorsByObject{ diff --git a/pkg/ha/ha_service.go b/pkg/ha/ha_service.go index da190924..bab4e163 100644 --- a/pkg/ha/ha_service.go +++ b/pkg/ha/ha_service.go @@ -8,6 +8,7 @@ import ( "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client" ctlmgr "sigs.k8s.io/controller-runtime/pkg/manager" @@ -16,7 +17,8 @@ import ( ) // HAService is the main type of the package. It takes care of concerns related to running the application in high -// availability mode. +// availability mode. When running in active/passive replication mode, HAService ensures that all requests go to the +// active replica. // HAService implements [ctlmgr.Runnable]. // For information about individual fields, see NewHAService(). type HAService struct { @@ -61,10 +63,15 @@ func (ha *HAService) setEndpoints(ctx context.Context) error { endpoints := corev1.Endpoints{} err := ha.manager.GetClient().Get(ctx, client.ObjectKey{Namespace: ha.namespace, Name: app.Name}, &endpoints) if err != nil { - return fmt.Errorf("updating the service endpoint to point to the new leader: retrieving endpoints: %w", err) + if !errors.IsNotFound(err) { + return fmt.Errorf("updating the service endpoint to point to the new leader: retrieving endpoints: %w", err) + } + + endpoints.ObjectMeta.Namespace = ha.namespace + endpoints.ObjectMeta.Name = app.Name } - endpoints.ObjectMeta.Labels = map[string]string{"app": app.Name} + endpoints.ObjectMeta.Labels = map[string]string{"app": app.Name, "resources.gardener.cloud/managed-by": "gardener"} endpoints.Subsets = []corev1.EndpointSubset{{ Addresses: []corev1.EndpointAddress{{IP: ha.servingIPAddress}}, Ports: []corev1.EndpointPort{{Port: int32(ha.servingPort), Protocol: "TCP"}}, diff --git a/pkg/ha/ha_service_test.go b/pkg/ha/ha_service_test.go index 47b522f1..6290313c 100644 --- a/pkg/ha/ha_service_test.go +++ b/pkg/ha/ha_service_test.go @@ -52,6 +52,7 @@ var _ = Describe("HAService", func() { Expect(actual.Subsets[0].Ports).To(HaveLen(1)) Expect(actual.Subsets[0].Ports[0].Port).To(Equal(int32(testPort))) }) + It("should wait and retry with exponential backoff, if the service endpoints are missing, and succeed "+ "once they appear", func() { @@ -98,6 +99,7 @@ var _ = Describe("HAService", func() { Expect(actual.Subsets[0].Addresses).To(HaveLen(1)) Expect(actual.Subsets[0].Addresses[0].IP).To(Equal(testIPAddress)) }) + It("should immediately abort retrying, if the context gets canceled", func() { // Arrange manager := testutil.NewFakeManager() @@ -129,6 +131,7 @@ var _ = Describe("HAService", func() { err = manager.GetClient().Get(context.Background(), kclient.ObjectKey{Namespace: testNs, Name: app.Name}, &actual) Expect(err).To(HaveOccurred()) }) + It("should use exponential backoff", func() { // Arrange diff --git a/pkg/input/controller/pod/predicate.go b/pkg/input/controller/pod/predicate.go index 3b59607a..ef90b2ce 100644 --- a/pkg/input/controller/pod/predicate.go +++ b/pkg/input/controller/pod/predicate.go @@ -44,7 +44,7 @@ func isPodLabeledAsShootKapi(pod client.Object) bool { } func isKapiPod(pod *corev1.Pod) bool { - return gutil.IsShootCPNamespace(pod.Namespace) && isPodLabeledAsShootKapi(pod) + return gutil.IsShootNamespace(pod.Namespace) && isPodLabeledAsShootKapi(pod) } // Is the object a shoot CP pod, containing one of shoot's kube-apiserver instances @@ -74,7 +74,7 @@ func (p *podPredicate) Update(e event.UpdateEvent) (result bool) { p.log.Error(nil, "Update event has no new object") return false } - if !gutil.IsShootCPNamespace(e.ObjectNew.GetNamespace()) { + if !gutil.IsShootNamespace(e.ObjectNew.GetNamespace()) { return false } diff --git a/pkg/input/controller/secret/actuator.go b/pkg/input/controller/secret/actuator.go index e634d210..9773abcb 100644 --- a/pkg/input/controller/secret/actuator.go +++ b/pkg/input/controller/secret/actuator.go @@ -30,7 +30,7 @@ import ( const ( secretNameCA = "ca" - secretNameAccessToken = "shoot-access-prometheus" + secretNameAccessToken = "shoot-access-gardener-custom-metrics" ) // The secret actuator acts upon shoot secrets, maintaining the information necessary to scrape diff --git a/pkg/input/controller/secret/predicate.go b/pkg/input/controller/secret/predicate.go index 75cf142b..2a79cea3 100644 --- a/pkg/input/controller/secret/predicate.go +++ b/pkg/input/controller/secret/predicate.go @@ -49,7 +49,7 @@ func (p *secretPredicate) isRelevantSecret(obj client.Object) bool { return false } - return gutil.IsShootCPNamespace(secret.Namespace) && + return gutil.IsShootNamespace(secret.Namespace) && (secret.Name == secretNameCA || secret.Name == secretNameAccessToken) } diff --git a/pkg/input/controller/secret/predicate_test.go b/pkg/input/controller/secret/predicate_test.go index b5877896..99c594c7 100644 --- a/pkg/input/controller/secret/predicate_test.go +++ b/pkg/input/controller/secret/predicate_test.go @@ -29,7 +29,7 @@ var _ = Describe("input.controler.secret.predicate", func() { It("should return true if the event target is a shoot control plane secret, containing the shoot's "+ "kube-apiserver CA certificate or metrics scraping access token", func() { - for _, name := range []string{"ca", "shoot-access-prometheus"} { + for _, name := range []string{"ca", "shoot-access-gardener-custom-metrics"} { // Arrange predicate := NewPredicate(logr.Discard()) oldSecret := newTestSecret(name) @@ -47,7 +47,7 @@ var _ = Describe("input.controler.secret.predicate", func() { } }) It("should return false if the event target is not in a shoot namespace", func() { - for _, name := range []string{"ca", "shoot-access-prometheus"} { + for _, name := range []string{"ca", "shoot-access-gardener-custom-metrics"} { // Arrange predicate := NewPredicate(logr.Discard()) oldSecret := newTestSecret(name) @@ -66,7 +66,7 @@ var _ = Describe("input.controler.secret.predicate", func() { } }) It("should return true if the event target is not a secret", func() { - for _, name := range []string{"ca", "shoot-access-prometheus"} { + for _, name := range []string{"ca", "shoot-access-gardener-custom-metrics"} { // Arrange predicate := NewPredicate(logr.Discard()) oldSecret := newTestSecret(name) diff --git a/pkg/input/input_data_service_test.go b/pkg/input/input_data_service_test.go index 27815ce5..10498811 100644 --- a/pkg/input/input_data_service_test.go +++ b/pkg/input/input_data_service_test.go @@ -54,6 +54,7 @@ var _ = Describe("input.inputDataService", func() { Expect(ids.inputDataRegistry.(*input_data_registry.FakeInputDataRegistry).MinSampleGap).To(Equal(testMinSampleGap)) }) }) + Describe("DataSource", func() { It("should point to the same registry at the one supplied to the scraper", func() { // Arrange @@ -69,6 +70,7 @@ var _ = Describe("input.inputDataService", func() { Expect(kapis[0].PodName()).To(Equal("pod")) }) }) + Describe("AddToManager", func() { It("should add the scraper, pod controller, and secret controller to the manager", func() { // Arrange @@ -83,6 +85,7 @@ var _ = Describe("input.inputDataService", func() { Expect(testutil.GetRunnables[*metrics_scraper.Scraper](fm)).To(HaveLen(1)) Expect(testutil.GetRunnables[controller.Controller](fm)).To(HaveLen(2)) }) + It("should add apimachinery runtime types scheme to the manager", func() { // Arrange ids, _ := newInputDataService() @@ -100,6 +103,7 @@ var _ = Describe("input.inputDataService", func() { Expect(fm.Scheme.Recognizes(gvk)).To(BeTrue()) } }) + It("should create a new data registry and pass it to the scraper", func() { // Arrange ids, _ := newInputDataService() @@ -124,6 +128,7 @@ var _ = Describe("input.inputDataService", func() { Expect(registryPassedToScraperConstructor).NotTo(BeNil()) Expect(registryPassedToScraperConstructor == ids.inputDataRegistry).To(BeTrue()) }) + It("should configure the scraper with the specified scrape period and flow control period", func() { // Arrange ids, _ := newInputDataService() diff --git a/pkg/input/metrics_scraper/pacemaker.go b/pkg/input/metrics_scraper/pacemaker.go index dcda7609..a4248c32 100644 --- a/pkg/input/metrics_scraper/pacemaker.go +++ b/pkg/input/metrics_scraper/pacemaker.go @@ -53,7 +53,7 @@ type pacemakerImpl struct { // newPacemaker creates a rate limiter which maintains the rate of some repeating operation between a set minimum and // maximum. -// Withing the space between min and max, the exact rate is determined depending on whether the client is eager to +// Within the space between min and max, the exact rate is determined depending on whether the client is eager to // perform the operation. Eager requests are governed by "no more than max rate". Non-eager requests follow a // "no less than min rate" schedule. // diff --git a/pkg/input/metrics_scraper/pacemaker_test.go b/pkg/input/metrics_scraper/pacemaker_test.go index dfa965af..e35d42ed 100644 --- a/pkg/input/metrics_scraper/pacemaker_test.go +++ b/pkg/input/metrics_scraper/pacemaker_test.go @@ -51,6 +51,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { Expect(pm.config.RateDebtLimit).To(Equal(creationConfig.RateDebtLimit)) Expect(pm.config.RateSurplusLimit).To(Equal(creationConfig.RateSurplusLimit)) }) + It("should create a pacemaker with zero debt", func() { // Arrange creationConfig := &pacemakerConfig{ @@ -66,6 +67,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { // Assert Expect(pm.GetScrapePermission(false)).To(BeFalse()) }) + It("should create a pacemaker with zero surplus", func() { // Arrange creationConfig := &pacemakerConfig{ @@ -81,6 +83,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { Expect(pm.GetScrapePermission(true)).To(BeFalse()) }) }) + Describe("UpdateRate", func() { It("should write the specified MinRate value to the pacemaker's configuration", func() { // Arrange @@ -92,6 +95,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { // Assert Expect(pm.config.MinRate).To(Equal(float64(777))) }) + It("should write the specified RateDebtLimit value to the pacemaker's configuration", func() { // Arrange pm := newTestPacemakerWithTestWorthyConfiguration() @@ -103,6 +107,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { Expect(pm.config.RateDebtLimit).To(Equal(777)) }) }) + Describe("GetScrapePermission", func() { Context("if the scrape is eager", func() { Context("starting from a state of zero debt and surplus", func() { @@ -118,6 +123,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { Expect(pm.GetScrapePermission(true)).To(BeFalse()) }) }) + Context("starting from a state of exhausted surplus", func() { It("should grant permission to as many calls, as correspond to MaxRate, and deny the next one", func() { // Arrange @@ -145,6 +151,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { Expect(pm.GetScrapePermission(true)).To(BeFalse()) }) }) + Context("starting from a state of high debt", func() { It("should allow RateSurplusLimit immediate calls, then deny the next call", func() { @@ -168,6 +175,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { }) }) }) + Context("if the scrape is not eager", func() { Context("starting from a state of zero debt", func() { It("after a period of inactivity which does not exceed the debt limit, should allow as many "+ @@ -194,6 +202,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { } Expect(pm.GetScrapePermission(false)).To(BeFalse()) }) + It("after a period of inactivity which exceeds the debt limit, should allow RateDebtLimit "+ "immediate calls, and deny the next one", func() { @@ -218,6 +227,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { } Expect(pm.GetScrapePermission(false)).To(BeFalse()) }) + It("if time has not passed, should not allow any immediate calls", func() { // Arrange pm := newTestPacemaker(2, 4, 20, 10) @@ -230,6 +240,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { }) }) }) + Context("starting from a state of high debt", func() { It("should allow as many immediate calls, as the value of the initial debt, if they don't exceed "+ "MaxRate, and then deny the next call if it is not eager", func() { @@ -257,6 +268,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { Expect(pm.GetScrapePermission(false)).To(BeFalse()) } }) + It("should still be limited to MaxRate", func() { // Arrange secondsElapsed := 2 @@ -292,6 +304,7 @@ var _ = Describe("input.metrics_scraper.pacemakerImpl", func() { } }) }) + It("should perform as expected in one complex scenario", func() { // This one last test case does not follow the good practice of simplicity and testing just one thing. // It uses a complex scenario, in attempt to catch potential issues missed by the above simple cases. diff --git a/pkg/input/metrics_scraper/scrape_queue_test.go b/pkg/input/metrics_scraper/scrape_queue_test.go index 37145a23..ecace90d 100644 --- a/pkg/input/metrics_scraper/scrape_queue_test.go +++ b/pkg/input/metrics_scraper/scrape_queue_test.go @@ -126,6 +126,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { Expect(pm.RateDebtLimit.Load()).To(BeZero()) Expect(int(pm.RateSurplusLimit.Load())).To(Equal(surplusLimit)) }) + It("should subscribe the scrapeQueue for InputDataRegistry events, including events for objects already in the registry", func() { // Arrange @@ -138,6 +139,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { Expect(idr.ShouldWatcherNotifyOfPreexisting).To(BeTrue()) }) }) + Describe("onKapiUpdated", func() { Context("if the event is an add", func() { It("should update the pacemaker with MinRate = ScrapeTargetCount / ScrapePeriod, DebtLimit = 0", func() { @@ -159,6 +161,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { pacemaker.RateSurplusLimit.Load() == surplusLimit }).Should(BeTrue()) }) + It("should add the new target to the queue", func() { // Arrange sq, idr, _ := newTestScrapeQueue(1 * time.Minute) @@ -179,6 +182,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { }).Should(BeTrue()) }) }) + Context("if the event is a remove", func() { It("should update the pacemaker with MinRate = ScrapeTargetCount / ScrapePeriod, DebtLimit = 0", func() { // Arrange @@ -202,6 +206,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { pacemaker.RateSurplusLimit.Load() == surplusLimit }).Should(BeTrue()) }) + It("should remove the new target from the queue", func() { // Arrange sq, idr, _ := newTestScrapeQueue(1 * time.Minute) @@ -225,6 +230,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { return next != nil && next.PodName == podName+"2" }).Should(BeTrue()) }) + It("should have no effect if the target is missing", func() { // Arrange sq, idr, _ := newTestScrapeQueue(1 * time.Minute) @@ -244,6 +250,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { }).Should(BeTrue()) }) }) + Context("if the event is of unknown type", func() { It("should have no effect", func() { // Arrange @@ -268,6 +275,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { }) }) }) + Describe("GetNext", func() { It("should return nil if the queue contains only targets which are missing from the registry", func() { // Arrange @@ -282,6 +290,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(result).To(BeNil()) }) + It("on a queue with multiple targets and a newly added target, should immediately request an eager scrape for the new target", func() { // Arrange sq, idr, pm := newTestScrapeQueue(1 * time.Minute) @@ -300,6 +309,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(next.PodName).To(Equal(podName + "2")) }) + It("should request a scrape operation from the scrape client, if the pacemaker grants permission", func() { // Arrange sq, idr, _ := newTestScrapeQueue(1 * time.Minute) @@ -313,6 +323,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(next).To(Not(BeNil())) }) + It("should not request a scrape operation from the scrape client, if the pacemaker denies permission", func() { // Arrange sq, idr, pm := newTestScrapeQueue(1 * time.Minute) @@ -327,6 +338,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(next).To(BeNil()) }) + It("upon successful scrape, should record the scrape time in the data registry", func() { // Arrange sq, idr, _ := newTestScrapeQueue(1 * time.Minute) @@ -341,6 +353,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(idr.GetKapiData(nsName, podName).LastMetricsScrapeTime).To(Equal(testutil.NewTimeNowStub(2, 0, 0)())) }) + It("should not change the last scrape time for the Kapi, if the pacemaker denies permission", func() { // Arrange sq, idr, pm := newTestScrapeQueue(1 * time.Minute) @@ -357,6 +370,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(idr.GetKapiData(nsName, podName).LastMetricsScrapeTime).To(Equal(initialScrapeTime)) }) + It("should return targets in a strictly cyclic order", func() { // Arrange sq, idr, _ := newTestScrapeQueue(1 * time.Minute) @@ -384,6 +398,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { } } }) + It("should return nil if there are only ineligible targets at the time of the call", func() { // Arrange sq, idr, pm := newTestScrapeQueue(1 * time.Minute) @@ -402,6 +417,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(next).To(BeNil()) }) + It("should return nil, if the queue is empty", func() { // Arrange sq, _, _ := newTestScrapeQueue(1 * time.Minute) @@ -414,6 +430,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(next).To(BeNil()) }) + It("should request an eager/lazy scrape from the pacemaker, depending on whether one scrape period has "+ "elapsed since the time the next target was last scraped", func() { @@ -441,6 +458,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { Expect(sq.GetNext()).NotTo(BeNil()) // Eager again Expect(sq.GetNext()).To(BeNil()) // Not eager }) + It("should skip targets which are missing from the registry, and return the first target which is not missing", func() { // Arrange sq, idr, pm := newTestScrapeQueue(1 * time.Minute) @@ -462,6 +480,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { Expect(sq.GetNext()).To(BeNil()) // This should be back to the first target, thus not eager }) }) + Describe("DueCount", func() { It("on an empty queue should return zero", func() { // Arrange @@ -473,6 +492,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(due).To(BeZero()) }) + It("should return zero if the queue contains only targets which are missing from the registry", func() { // Arrange sq, idr, _ := newTestScrapeQueue(1 * time.Minute) @@ -487,6 +507,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(due).To(BeZero()) }) + It("should count targets exactly after one scraping period passes from their last scrape. It should count "+ "targets which have never been scraped, if, and only if the excludeUnscraped parameter is false", func() { @@ -519,6 +540,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { Expect(sq.DueCount(thirdScrapeTime, true)).To(Equal(20)) }) }) + Describe("Close", func() { It("should terminate the scrapeQueue's subscription to InputDataRegistry events", func() { // Arrange @@ -531,6 +553,7 @@ var _ = Describe("input.metrics_scraper.scrapeQueueImpl", func() { // Assert Expect(idr.Watcher).To(BeNil()) }) + It("should terminate the processing of InputDataRegistry events", func() { // Arrange sq, idr, _ := newTestScrapeQueue(1 * time.Minute) diff --git a/pkg/input/metrics_scraper/scraper_test.go b/pkg/input/metrics_scraper/scraper_test.go index 26bb6eb3..87f9aa85 100644 --- a/pkg/input/metrics_scraper/scraper_test.go +++ b/pkg/input/metrics_scraper/scraper_test.go @@ -122,6 +122,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Expect(scraper.queue.(*scrapeQueueImpl).scrapePeriod).To(Equal(scrapePeriod)) }) }) + Describe("Start", func() { It("should poll until context cancelled, and stop polling when the context is cancelled", func() { // Arrange @@ -160,6 +161,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Consistently(isRunning.Load).Should(BeFalse()) abortChan <- true }) + It("should not exit before all workers exit", func() { // Arrange scraper, idr, sq, _, ticker, _ := newTestScraper() @@ -187,6 +189,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { scraper.activeWorkerCount.Add(-1) Eventually(isRunning.Load).Should(BeFalse()) }) + It("should close scrape queue before exiting", func() { // Arrange scraper, idr, sq, _, _, _ := newTestScraper() @@ -206,6 +209,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Eventually(isRunning.Load).Should(BeFalse()) Expect(sq.IsClosed()).To(BeTrue()) }) + It("upon first invocation with multiple targets, should start 2 workers, then, if no scrapes are "+ "recorded, double upon each ticker tick, until it gets capped to the number of targets", func() { @@ -231,6 +235,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Consistently(metrics.WorkerProcCount.Load).Should(Equal(expected)) } }) + It("if last shift managed to scrape all of its targets, should attempt scraping with one less worker", func() { // Arrange scraper, idr, sq, _, ticker, metrics := newTestScraper() @@ -252,6 +257,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Eventually(metrics.WorkerProcCount.Load).Should(Equal(int32(9))) }) + It("if last shift failed to scrape all of its targets, should increase worker count proportionally to "+ "last shift's throughput and current due target count", func() { @@ -271,6 +277,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Eventually(metrics.WorkerProcCount.Load).Should(Equal(int32(6))) Consistently(metrics.WorkerProcCount.Load).Should(Equal(int32(6))) }) + It("should consider leftover targets from last shift, when calculating this shift's worker count", func() { // Arrange // Last shift scraped 1 out of 6 targets with 6 workers. This shift has 3 new targets and 5 leftover @@ -288,6 +295,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Eventually(metrics.WorkerProcCount.Load).Should(Equal(int32(8))) Consistently(metrics.WorkerProcCount.Load).Should(Equal(int32(8))) }) + It("should respect maxShiftWorkerCount", func() { // Arrange // Last shift scraped 1 out of 6 targets with 6 workers. This shift has 10 new targets and 5 leftover @@ -305,6 +313,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Eventually(metrics.WorkerProcCount.Load).Should(Equal(int32(10))) Consistently(metrics.WorkerProcCount.Load).Should(Equal(int32(10))) }) + It("should respect minShiftWorkerCount", func() { // Arrange scraper, idr, sq, _, ticker, metrics := newTestScraper() @@ -328,6 +337,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Eventually(metrics.WorkerProcCount.Load).Should(Equal(int32(1))) Consistently(metrics.WorkerProcCount.Load).Should(Equal(int32(1))) }) + It("if the queue is empty, should slowly reduce the number of workers to 1", func() { // Arrange scraper, idr, sq, _, ticker, metrics := newTestScraper() @@ -349,6 +359,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Eventually(scraper.activeWorkerCount.Load).Should(BeZero()) } }) + It("should respect maxActiveWorkerCount", func() { // Arrange scraper, idr, sq, _, ticker, metrics := newTestScraper() @@ -367,6 +378,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Eventually(metrics.WorkerProcCount.Load).Should(Equal(int32(9))) Consistently(metrics.WorkerProcCount.Load).Should(Equal(int32(9))) }) + It("should apply the specified scrapeFlowControlPeriod to the ticker it uses", func() { // Arrange schedulingPeriod := 100 * time.Millisecond @@ -386,6 +398,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { // Assert Eventually(fakeTicker.Period.Load).Should(Equal(int64(schedulingPeriod))) }) + It("should schedule scrape shifts when and only when the ticket ticks", func() { // Arrange scraper, idr, sq, _, ticker, metrics := newTestScraper() @@ -406,6 +419,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { } }) }) + Describe("workerProc", func() { It("polls the targets returned by GetNext(),until the context is cancelled", func() { // Arrange @@ -425,6 +439,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Consistently(client.WasScraped.Load).Should(BeFalse()) Expect(scraper.activeWorkerCount.Load()).To(BeZero()) }) + It("if context has not been cancelled, polls the queue until GetNext() returns nil", func() { // Arrange scraper, idr, sq, client, _, _ := newTestScraper() @@ -443,6 +458,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Consistently(client.WasScraped.Load).Should(BeFalse()) Expect(scraper.activeWorkerCount.Load()).To(BeZero()) }) + It("if context has been cancelled, exits before scraping the queue", func() { // Arrange scraper, _, client, _, _ := arrangeWorkerTest() @@ -456,6 +472,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Consistently(client.WasScraped.Load).Should(BeFalse()) Expect(scraper.activeWorkerCount.Load()).To(BeZero()) }) + It("should scrape each target returned by the queue", func() { // Arrange scraper, idr, sq, _, _, _ := newTestScraper() @@ -475,6 +492,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Expect(kapi.TotalRequestCountNew).To(Equal(fakeMetricsClientMetricsValue)) } }) + Context("when scraping a target", func() { It("should have no effect if the kapi is missing from the registry", func() { // Arrange @@ -492,6 +510,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Expect(client.WasScraped.Load()).To(BeFalse()) Expect(idr.GetKapiData(target.Namespace, target.PodName)).To(BeNil()) }) + It("should have no effect if the auth secret is missing from the registry", func() { // Arrange scraper, idr, client, testMetrics, target := arrangeWorkerTest() @@ -509,6 +528,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Expect(idr.GetKapiData(target.Namespace, target.PodName).TotalRequestCountNew).To(BeZero()) Expect(idr.GetKapiData(target.Namespace, target.PodName).MetricsTimeNew).To(BeZero()) }) + It("should have no effect if the CA certificate is missing from the registry", func() { // Arrange scraper, idr, client, testMetrics, target := arrangeWorkerTest() @@ -526,6 +546,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { Expect(idr.GetKapiData(target.Namespace, target.PodName).TotalRequestCountNew).To(BeZero()) Expect(idr.GetKapiData(target.Namespace, target.PodName).MetricsTimeNew).To(BeZero()) }) + It("should record the resulting metric value in the registry", func() { // Arrange scraper, idr, _, _, target := arrangeWorkerTest() @@ -540,6 +561,7 @@ var _ = Describe("input.metrics_scraper.Scraper", func() { return idr.GetKapiData(target.Namespace, target.PodName).TotalRequestCountNew }).Should(Equal(fakeMetricsClientMetricsValue)) }) + It("should use scrapePeriod / 2 as timeout for individual scrapes", func() { // Arrange scraper, _, client, _, _ := arrangeWorkerTest() diff --git a/pkg/metrics_provider/metrics_provider.go b/pkg/metrics_provider/metrics_provider.go index 92e5d5f7..ef21ee20 100644 --- a/pkg/metrics_provider/metrics_provider.go +++ b/pkg/metrics_provider/metrics_provider.go @@ -119,7 +119,7 @@ func (mp *MetricsProvider) getMetricByPredicate( metricInfo provider.CustomMetricInfo) (*custom_metrics.MetricValueList, error) { if metricInfo.Metric != metricName { - return nil, nil + return &custom_metrics.MetricValueList{}, nil } kapis := mp.dataSource.GetShootKapis(namespace) diff --git a/pkg/metrics_provider/metrics_provider_service_test.go b/pkg/metrics_provider/metrics_provider_service_test.go index d61318e9..737e81f0 100644 --- a/pkg/metrics_provider/metrics_provider_service_test.go +++ b/pkg/metrics_provider/metrics_provider_service_test.go @@ -30,6 +30,7 @@ var _ = Describe("MetricsService", func() { } }) }) + Describe("CompleteCLIConfiguration", func() { It("should create a MetricsProvider based on the specified configuration", func() { // Arrange diff --git a/pkg/metrics_provider/metrics_provider_test.go b/pkg/metrics_provider/metrics_provider_test.go index 13ce45e8..e17aa3bc 100644 --- a/pkg/metrics_provider/metrics_provider_test.go +++ b/pkg/metrics_provider/metrics_provider_test.go @@ -45,6 +45,7 @@ var _ = Describe("MetricsProvider", func() { Expect(err).To(Succeed()) Expect(metricValue).To(BeNil()) }) + It("should return metrics for the Kapi pod specified by the namespaced name", func() { // Arrange idr := input_data_registry.FakeInputDataRegistry{} @@ -72,6 +73,7 @@ var _ = Describe("MetricsProvider", func() { Expect(val.DescribedObject.APIVersion).To(Equal("v1")) Expect(val.DescribedObject.Kind).To(Equal("Pod")) }) + It("should respect maxSampleAge", func() { // Arrange idr := input_data_registry.FakeInputDataRegistry{} @@ -97,6 +99,7 @@ var _ = Describe("MetricsProvider", func() { Expect(valStillGood).NotTo(BeNil()) Expect(valStillGood.DescribedObject.Name).To(Equal(testPodName + "2")) }) + It("should respect maxSampleGap", func() { // Arrange idr := input_data_registry.FakeInputDataRegistry{} @@ -123,6 +126,7 @@ var _ = Describe("MetricsProvider", func() { Expect(valGood.DescribedObject.Name).To(Equal(testPodName)) }) }) + Describe("GetMetricBySelector", func() { It("should return nothing if there are no Kapis", func() { // Arrange @@ -138,6 +142,7 @@ var _ = Describe("MetricsProvider", func() { Expect(metricValue).NotTo(BeNil()) Expect(metricValue.Items).To(HaveLen(0)) }) + It("should return only metrics for Kapi pods which match the selector", func() { // Arrange idr := input_data_registry.FakeInputDataRegistry{} diff --git a/pkg/util/gardener/options_test.go b/pkg/util/gardener/options_test.go index 607bc3f5..8de441de 100644 --- a/pkg/util/gardener/options_test.go +++ b/pkg/util/gardener/options_test.go @@ -60,6 +60,7 @@ var _ = Describe("RESTOptions", func() { Expect(output.ForwardedKubeconfig).To(Equal(customKubeconfig)) Expect(output.ForwardedMasterUrl).To(Equal(kapiUrl)) }) + It("should use the specified master URL and fall back to kubeconfig from environment variable", func() { // Arrange options, output := newRestOptions() @@ -74,6 +75,7 @@ var _ = Describe("RESTOptions", func() { Expect(output.ForwardedKubeconfig).To(Equal(envKubeconfig)) Expect(output.ForwardedMasterUrl).To(Equal(kapiUrl)) }) + It("should fall back to in-cluster config", func() { // Arrange options, output := newRestOptions() @@ -91,6 +93,7 @@ var _ = Describe("RESTOptions", func() { Expect(output.ForwardedMasterUrl).To(Equal(inCluster)) Expect(output.ForwardedKubeconfig).To(Equal(inCluster)) }) + It("should fall back to default kubeconfig location", func() { // Arrange options, output := newRestOptions() diff --git a/pkg/util/gardener/util.go b/pkg/util/gardener/util.go index 833232a0..e8795e96 100644 --- a/pkg/util/gardener/util.go +++ b/pkg/util/gardener/util.go @@ -7,9 +7,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller" ) -// IsShootCPNamespace determines whether the format of specified name implies that it is a shoot namespace in a seed +// IsShootNamespace determines whether the format of specified name implies that it is a shoot namespace in a seed // cluster -func IsShootCPNamespace(namespace string) bool { +func IsShootNamespace(namespace string) bool { return strings.HasPrefix(namespace, "shoot--") } diff --git a/pkg/util/gardener/util_test.go b/pkg/util/gardener/util_test.go index d72e81d4..75420351 100644 --- a/pkg/util/gardener/util_test.go +++ b/pkg/util/gardener/util_test.go @@ -6,12 +6,12 @@ import ( ) var _ = Describe("uti/gardener", func() { - Describe("IsShootCPNamespace", func() { + Describe("IsShootNamespace", func() { It("should work expected on certain predefined values", func() { - Expect(IsShootCPNamespace("shoot--my-shoot")).To(BeTrue()) - Expect(IsShootCPNamespace("shoot-my-shoot")).To(BeFalse()) - Expect(IsShootCPNamespace("")).To(BeFalse()) - Expect(IsShootCPNamespace("shoot--my--shoot")).To(BeTrue()) + Expect(IsShootNamespace("shoot--my-shoot")).To(BeTrue()) + Expect(IsShootNamespace("shoot-my-shoot")).To(BeFalse()) + Expect(IsShootNamespace("")).To(BeFalse()) + Expect(IsShootNamespace("shoot--my--shoot")).To(BeTrue()) }) }) }) diff --git a/skaffold.yaml b/skaffold.yaml new file mode 100644 index 00000000..b8928fd6 --- /dev/null +++ b/skaffold.yaml @@ -0,0 +1,115 @@ +--- +apiVersion: skaffold/v4beta7 +kind: Config +metadata: + name: gcmx +build: + artifacts: + - image: eu.gcr.io/gardener-project/gardener/gardener-custom-metrics + ko: + dependencies: + paths: + - cmd/** + - example/** + - pkg/** + - vendor/** + - VERSION + ldflags: + - '{{.LD_FLAGS}}' + main: ./cmd/gardener-custom-metrics +profiles: + - name: debug + activation: + - command: debug + manifests: + rawYaml: + - example/custom-metrics-deployment.yaml +# kustomize: +# paths: +# - example/provider-local/seed-kind2/skaffold + deploy: + kubectl: {} + +# TODO: Andrey: P1: cleanup +# patches: +# - op: add +# path: /deploy/helm/releases/0/setValues +# value: +# replicaCount: 1 +# config.leaderElection.leaderElect: false +# config.server.healthProbes.enable: false +# - name: kind2 +# patches: +# - op: add +# path: /deploy/helm/releases/0/valuesFiles/- +# value: example/gardener-local/gardenlet/values-kind2.yaml +# - op: replace +# path: /deploy/helm/hooks/after/0/host/command +# value: +# - bash +# - -ec +# - KUBECONFIG=$GARDENER_LOCAL_KUBECONFIG hack/usage/wait-for.sh seed local2 GardenletReady SeedSystemComponentsHealthy ExtensionsReady BackupBucketsReady +# - name: extensions +# patches: +# - op: add +# path: /deploy/helm/releases/0/valuesFiles/- +# value: example/gardener-local/gardenlet/values-provider-extensions.yaml +# - op: add +# path: /deploy/helm/releases/0/valuesFiles/- +# value: example/provider-extensions/gardenlet/{{.SEED_VALUES}} +# - op: replace +# path: /deploy/helm/hooks/after/0/host/command +# value: +# - bash +# - -ec +# - KUBECONFIG=$GARDENER_LOCAL_KUBECONFIG hack/usage/wait-for.sh seed "$SEED_NAME" GardenletReady SeedSystemComponentsHealthy ExtensionsReady +# - name: ha-single-zone +# patches: +# - op: add +# path: /deploy/helm/releases/0/valuesFiles/- +# value: example/gardener-local/gardenlet/values-kind-ha-single-zone.yaml +# - op: replace +# path: /deploy/helm/hooks/after/0/host/command +# value: +# - bash +# - -ec +# - hack/usage/wait-for.sh seed local-ha-single-zone GardenletReady SeedSystemComponentsHealthy ExtensionsReady BackupBucketsReady +# - name: kind2-ha-single-zone +# patches: +# - op: add +# path: /deploy/helm/releases/0/valuesFiles/- +# value: example/gardener-local/gardenlet/values-kind2-ha-single-zone.yaml +# - op: replace +# path: /deploy/helm/hooks/after/0/host/command +# value: +# - bash +# - -ec +# - KUBECONFIG=$GARDENER_LOCAL_KUBECONFIG hack/usage/wait-for.sh seed local2-ha-single-zone GardenletReady SeedSystemComponentsHealthy ExtensionsReady BackupBucketsReady +# - name: ha-multi-zone +# patches: +# - op: add +# path: /deploy/helm/releases/0/valuesFiles/- +# value: example/gardener-local/gardenlet/values-kind-ha-multi-zone.yaml +# - op: replace +# path: /deploy/helm/hooks/after/0/host/command +# value: +# - bash +# - -ec +# - TIMEOUT=1200 hack/usage/wait-for.sh seed local-ha-multi-zone GardenletReady SeedSystemComponentsHealthy ExtensionsReady BackupBucketsReady +# - name: ipv6 +# activation: +# - env: IPFAMILY=ipv6 +# patches: +# - op: add +# path: /deploy/helm/releases/0/valuesFiles/- +# value: example/gardener-local/gardenlet/values-ipv6.yaml +# - name: debug +# activation: +# - command: debug +# patches: +# - op: add +# path: /deploy/helm/releases/0/setValues +# value: +# replicaCount: 1 +# config.leaderElection.leaderElect: false +# config.server.healthProbes.enable: false From 0f0ee1198d6cc31a241abcfb7ff7a50f9345d0aa Mon Sep 17 00:00:00 2001 From: Andrey Anastasov <98102124+andrerun@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:58:35 +0200 Subject: [PATCH 2/8] Apply review comments --- Dockerfile | 4 +- Makefile | 10 +-- README.md | 2 +- VERSION | 2 +- docs/development/README.md | 21 +++++++ example/custom-metrics-deployment.yaml | 2 - go.mod | 6 +- go.sum | 25 ++++++++ pkg/ha/ha_service.go | 2 +- pkg/util/gardener/util.go | 2 +- pkg/util/gardener/util_test.go | 7 ++- skaffold.yaml | 86 +------------------------- 12 files changed, 67 insertions(+), 102 deletions(-) create mode 100644 docs/development/README.md diff --git a/Dockerfile b/Dockerfile index 5aea163e..7ecf541e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,12 @@ ############# builder -FROM golang:1.19.9 AS builder +FROM golang:1.22.1 AS builder WORKDIR /go/src/github.com/gardener/gardener-custom-metrics COPY . . RUN make install ############# base image # TODO: Andrey: P1: Move to distroless -FROM alpine:3.18.0 AS base +FROM alpine:3.18.6 AS base ############# gardener-custom-metrics FROM base AS gardener-custom-metrics diff --git a/Makefile b/Makefile index cb156418..f60b0707 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,6 @@ BUILD_DATE := $(shell date '+%Y-%m-%dT%H:%M:%S%z' | sed 's/\([0-9][0-9]\)$$/:\1/g') NAME := gardener-custom-metrics IMAGE_REGISTRY_URI := eu.gcr.io/gardener-project/gardener -# IMAGE_REGISTRY_URI := eu.gcr.io/sap-se-gcp-scp-k8s/$(NAME) REPO_ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) VERSION := $(shell cat "$(REPO_ROOT)/VERSION") EFFECTIVE_VERSION := $(VERSION)-$(shell git rev-parse HEAD) @@ -31,8 +30,9 @@ ifneq ($(strip $(shell git status --porcelain 2>/dev/null)),) EFFECTIVE_VERSION := $(EFFECTIVE_VERSION)-dirty endif -LD_FLAGS_DEBUG := "$(shell EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) $(REPO_ROOT)/hack/gardener-util/get-build-ld-flags.sh k8s.io/component-base $(REPO_ROOT)/VERSION $(EXTENSION_PREFIX)-$(NAME))" +# In debug, do not use the -w flag. It strips useful debug information. LD_FLAGS := "-w $(shell EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) $(REPO_ROOT)/hack/gardener-util/get-build-ld-flags.sh k8s.io/component-base $(REPO_ROOT)/VERSION $(EXTENSION_PREFIX)-$(NAME))" +LD_FLAGS_DEBUG := "$(shell EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) $(REPO_ROOT)/hack/gardener-util/get-build-ld-flags.sh k8s.io/component-base $(REPO_ROOT)/VERSION $(EXTENSION_PREFIX)-$(NAME))" TOOLS_DIR := $(REPO_ROOT)/hack/gardener-util/tools include $(REPO_ROOT)/hack/gardener-util/tools.mk @@ -150,8 +150,10 @@ debug: export SOURCE_DATE_EPOCH = $(shell date -d $(BUILD_DATE) +%s) .PHONY: debug debug: $(SKAFFOLD) - @echo "LD_FLAGS: $(LD_FLAGS_DEBUG)" - @LD_FLAGS=$(LD_FLAGS) $(SKAFFOLD) debug + @LD_FLAGS=$(LD_FLAGS_DEBUG) $(SKAFFOLD) debug + + # TODO: Andrey: P1: Inject TLS secret name dynamically into deployment + # GCMX_TLS_SECRET_NAME=$(kubectl -n garden get secrets | grep '^gardener-custom-metrics' | head -n 1 | awk '{print $1}') \ # TODO: Andrey: P1: code cleanup # export SKAFFOLD_DEFAULT_REPO = localhost:5001 # export SKAFFOLD_PUSH = true diff --git a/README.md b/README.md index 8fdafd8e..95338b44 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # gardener-custom-metrics -[![reuse compliant](https://reuse.software/badge/reuse-compliant.svg)](https://reuse.software/) +[![REUSE status](https://api.reuse.software/badge/github.com/gardener/gardener-custom-metrics)](https://api.reuse.software/info/github.com/gardener/gardener-custom-metrics) ## Overview The `gardener-custom-metrics` component operates as a K8s API service, adding functionality to the seed kube-apiserver. It periodically scrapes the metrics endpoints of all shoot kube-apiserver pods on the seed. It implements the K8s custom diff --git a/VERSION b/VERSION index 2787740c..0a02a013 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.10.11-dev \ No newline at end of file +v0.1.0-dev \ No newline at end of file diff --git a/docs/development/README.md b/docs/development/README.md new file mode 100644 index 00000000..5ef08ccd --- /dev/null +++ b/docs/development/README.md @@ -0,0 +1,21 @@ +### To debug gardener-custom-metrics (GCMx): +- Prerequisite: [Gardener local dev setup] +- Open a terminal +- Set current directory to project root +- Point $KUBECONFIG to the K8s cluster from the [Gardener local dev setup] +- Run `make debug`: + - This is a blocking call + - It builds and deploys a debug-instrumented pod to the cluster + - It forwards the pod's log output to the console window + - It forwards localhost:56268 to the debugger port for the pod +- Attach debugger to localhost:56268. At this point, if you place a breakpoint somewhere, it should be hit. + +### To build and publish GCMx: +These instructions are a work in progress and may contain errors +- Open a terminal +- Set current directory to project root +- Run `make docker-build` +- Run `make docker-login` +- Run `make docker-push` + +[Gardener local dev setup]: https://gardener.cloud/docs/gardener/deployment/getting_started_locally \ No newline at end of file diff --git a/example/custom-metrics-deployment.yaml b/example/custom-metrics-deployment.yaml index ee7edc56..84f05359 100644 --- a/example/custom-metrics-deployment.yaml +++ b/example/custom-metrics-deployment.yaml @@ -11,13 +11,11 @@ spec: matchLabels: app: gardener-custom-metrics gardener.cloud/role: gardener-custom-metrics - resources.gardener.cloud/managed-by: gardener template: metadata: labels: app: gardener-custom-metrics gardener.cloud/role: gardener-custom-metrics - resources.gardener.cloud/managed-by: gardener networking.gardener.cloud/from-seed: allowed networking.gardener.cloud/to-dns: allowed networking.gardener.cloud/to-runtime-apiserver: allowed diff --git a/go.mod b/go.mod index 2b535378..57823249 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,14 @@ module github.com/gardener/gardener-custom-metrics -go 1.21 +go 1.22.0 require ( github.com/go-logr/logr v1.2.4 github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/gomega v1.27.8 - github.com/spf13/cobra v1.6.1 + github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 + go.uber.org/atomic v1.7.0 go.uber.org/zap v1.21.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/time v0.3.0 @@ -82,7 +83,6 @@ require ( go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect go.opentelemetry.io/otel/trace v0.20.0 // indirect go.opentelemetry.io/proto/otlp v0.7.0 // indirect - go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/mod v0.10.0 // indirect diff --git a/go.sum b/go.sum index e1c8d8a2..bf963668 100644 --- a/go.sum +++ b/go.sum @@ -21,7 +21,9 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/compute v1.13.0 h1:AYrLkB8NPdDRslNp4Jxmzrhdr03fUAIDbiGFjLWowoU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -36,6 +38,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= @@ -81,6 +84,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.16.0+incompatible h1:rgqiKNjTnFQA6kkhFe16D8epTksy9HQ1MyrbDXSdYhM= github.com/emicklei/go-restful v2.16.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= @@ -98,6 +102,7 @@ github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= @@ -168,6 +173,7 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -205,7 +211,9 @@ github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9 github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= @@ -221,6 +229,7 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -268,8 +277,10 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -309,9 +320,12 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.9.4 h1:Sd43wM1IWz/s1aVXdOBkjJvuP8UdyqioeE4AmM0QsBs= +github.com/spf13/afero v1.9.4/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -326,24 +340,32 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= go.etcd.io/etcd/pkg/v3 v3.5.0 h1:ntrg6vvKRW26JRmHTE0iNlDgYK6JX3hg/4cD62X0ixk= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= go.etcd.io/etcd/raft/v3 v3.5.0 h1:kw2TmO3yFTgE+F0mdKkG7xMxkit2duBDa2Hu6D/HMlw= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= go.etcd.io/etcd/server/v3 v3.5.0 h1:jk8D/lwGEDlQU9kZXUFMSANkE22Sg5+mW27ip8xcF9E= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -378,6 +400,7 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= @@ -695,6 +718,7 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -720,6 +744,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 k8s.io/api v0.23.17 h1:gC11V5AIsNXUUa/xd5RQo7djukvl5O1ZDQKwEYu0H7g= k8s.io/api v0.23.17/go.mod h1:upM9VIzXUjEyLTmGGi0KnH8kdlPnvgv+fEJ3tggDHfE= k8s.io/apiextensions-apiserver v0.23.5 h1:5SKzdXyvIJKu+zbfPc3kCbWpbxi+O+zdmAJBm26UJqI= +k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ= k8s.io/apimachinery v0.23.17 h1:ipJ0SrpI6EzH8zVw0WhCBldgJhzIamiYIumSGTdFExY= k8s.io/apimachinery v0.23.17/go.mod h1:87v5Wl9qpHbnapX1PSNgln4oO3dlyjAU3NSIwNhT4Lo= k8s.io/apiserver v0.23.17 h1:0br6oJhknp1mT0epMS84ibj+XcpmthPd60B5bPdbko8= diff --git a/pkg/ha/ha_service.go b/pkg/ha/ha_service.go index bab4e163..808d4e97 100644 --- a/pkg/ha/ha_service.go +++ b/pkg/ha/ha_service.go @@ -71,7 +71,7 @@ func (ha *HAService) setEndpoints(ctx context.Context) error { endpoints.ObjectMeta.Name = app.Name } - endpoints.ObjectMeta.Labels = map[string]string{"app": app.Name, "resources.gardener.cloud/managed-by": "gardener"} + endpoints.ObjectMeta.Labels = map[string]string{"app": app.Name} endpoints.Subsets = []corev1.EndpointSubset{{ Addresses: []corev1.EndpointAddress{{IP: ha.servingIPAddress}}, Ports: []corev1.EndpointPort{{Port: int32(ha.servingPort), Protocol: "TCP"}}, diff --git a/pkg/util/gardener/util.go b/pkg/util/gardener/util.go index e8795e96..ae873cc6 100644 --- a/pkg/util/gardener/util.go +++ b/pkg/util/gardener/util.go @@ -10,7 +10,7 @@ import ( // IsShootNamespace determines whether the format of specified name implies that it is a shoot namespace in a seed // cluster func IsShootNamespace(namespace string) bool { - return strings.HasPrefix(namespace, "shoot--") + return strings.HasPrefix(namespace, "shoot-") } // WatchBuilder holds various functions which add watch controls to the passed Controller. diff --git a/pkg/util/gardener/util_test.go b/pkg/util/gardener/util_test.go index 75420351..ae88b31e 100644 --- a/pkg/util/gardener/util_test.go +++ b/pkg/util/gardener/util_test.go @@ -7,9 +7,12 @@ import ( var _ = Describe("uti/gardener", func() { Describe("IsShootNamespace", func() { - It("should work expected on certain predefined values", func() { + It("should work as expected on certain predefined values", func() { + // Not a valid format from the Gardener perspective, but one we expect the less rigorous check in + // IsShootNamespace() to accept Expect(IsShootNamespace("shoot--my-shoot")).To(BeTrue()) - Expect(IsShootNamespace("shoot-my-shoot")).To(BeFalse()) + // Legacy format - some clusters may still use it + Expect(IsShootNamespace("shoot-my-shoot")).To(BeTrue()) Expect(IsShootNamespace("")).To(BeFalse()) Expect(IsShootNamespace("shoot--my--shoot")).To(BeTrue()) }) diff --git a/skaffold.yaml b/skaffold.yaml index b8928fd6..b3e00b11 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -2,7 +2,7 @@ apiVersion: skaffold/v4beta7 kind: Config metadata: - name: gcmx + name: gardener-custom-metrics build: artifacts: - image: eu.gcr.io/gardener-project/gardener/gardener-custom-metrics @@ -29,87 +29,3 @@ profiles: # - example/provider-local/seed-kind2/skaffold deploy: kubectl: {} - -# TODO: Andrey: P1: cleanup -# patches: -# - op: add -# path: /deploy/helm/releases/0/setValues -# value: -# replicaCount: 1 -# config.leaderElection.leaderElect: false -# config.server.healthProbes.enable: false -# - name: kind2 -# patches: -# - op: add -# path: /deploy/helm/releases/0/valuesFiles/- -# value: example/gardener-local/gardenlet/values-kind2.yaml -# - op: replace -# path: /deploy/helm/hooks/after/0/host/command -# value: -# - bash -# - -ec -# - KUBECONFIG=$GARDENER_LOCAL_KUBECONFIG hack/usage/wait-for.sh seed local2 GardenletReady SeedSystemComponentsHealthy ExtensionsReady BackupBucketsReady -# - name: extensions -# patches: -# - op: add -# path: /deploy/helm/releases/0/valuesFiles/- -# value: example/gardener-local/gardenlet/values-provider-extensions.yaml -# - op: add -# path: /deploy/helm/releases/0/valuesFiles/- -# value: example/provider-extensions/gardenlet/{{.SEED_VALUES}} -# - op: replace -# path: /deploy/helm/hooks/after/0/host/command -# value: -# - bash -# - -ec -# - KUBECONFIG=$GARDENER_LOCAL_KUBECONFIG hack/usage/wait-for.sh seed "$SEED_NAME" GardenletReady SeedSystemComponentsHealthy ExtensionsReady -# - name: ha-single-zone -# patches: -# - op: add -# path: /deploy/helm/releases/0/valuesFiles/- -# value: example/gardener-local/gardenlet/values-kind-ha-single-zone.yaml -# - op: replace -# path: /deploy/helm/hooks/after/0/host/command -# value: -# - bash -# - -ec -# - hack/usage/wait-for.sh seed local-ha-single-zone GardenletReady SeedSystemComponentsHealthy ExtensionsReady BackupBucketsReady -# - name: kind2-ha-single-zone -# patches: -# - op: add -# path: /deploy/helm/releases/0/valuesFiles/- -# value: example/gardener-local/gardenlet/values-kind2-ha-single-zone.yaml -# - op: replace -# path: /deploy/helm/hooks/after/0/host/command -# value: -# - bash -# - -ec -# - KUBECONFIG=$GARDENER_LOCAL_KUBECONFIG hack/usage/wait-for.sh seed local2-ha-single-zone GardenletReady SeedSystemComponentsHealthy ExtensionsReady BackupBucketsReady -# - name: ha-multi-zone -# patches: -# - op: add -# path: /deploy/helm/releases/0/valuesFiles/- -# value: example/gardener-local/gardenlet/values-kind-ha-multi-zone.yaml -# - op: replace -# path: /deploy/helm/hooks/after/0/host/command -# value: -# - bash -# - -ec -# - TIMEOUT=1200 hack/usage/wait-for.sh seed local-ha-multi-zone GardenletReady SeedSystemComponentsHealthy ExtensionsReady BackupBucketsReady -# - name: ipv6 -# activation: -# - env: IPFAMILY=ipv6 -# patches: -# - op: add -# path: /deploy/helm/releases/0/valuesFiles/- -# value: example/gardener-local/gardenlet/values-ipv6.yaml -# - name: debug -# activation: -# - command: debug -# patches: -# - op: add -# path: /deploy/helm/releases/0/setValues -# value: -# replicaCount: 1 -# config.leaderElection.leaderElect: false -# config.server.healthProbes.enable: false From 6d713a65e8a6c7557dd3d1b6479a0fc8c023c0ff Mon Sep 17 00:00:00 2001 From: Andrey Anastasov <98102124+andrerun@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:59:40 +0200 Subject: [PATCH 3/8] Metrics client: cap input stream length --- pkg/input/metrics_scraper/metrics_client.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/input/metrics_scraper/metrics_client.go b/pkg/input/metrics_scraper/metrics_client.go index 6a522a7c..8224a897 100644 --- a/pkg/input/metrics_scraper/metrics_client.go +++ b/pkg/input/metrics_scraper/metrics_client.go @@ -93,7 +93,7 @@ func (mc *metricsClientImpl) GetKapiInstanceMetrics( }(response.Body) if response.StatusCode < 200 || response.StatusCode >= 300 { - return 0, fmt.Errorf("metrics client: responce reported HTTP status %d", response.StatusCode) + return 0, fmt.Errorf("metrics client: response reported HTTP status %d", response.StatusCode) } // If the server returned compressed response, use decompressing reader @@ -117,7 +117,9 @@ func (mc *metricsClientImpl) GetKapiInstanceMetrics( // - an optional error // // Exactly one of the int64 value and the error is non-zero. -func getTotalRequestCount(metricsStream io.ReadCloser) (int64, error) { +func getTotalRequestCount(metricsStream io.Reader) (int64, error) { + // Limit the metrics response as a general precaution. It should be < 5MB, so if we're getting >20MB something's wrong + metricsStream = &io.LimitedReader{R: metricsStream, N: 20 * 1024 * 1024} reader := bufio.NewReader(metricsStream) totalRequestCount := int64(0) From a322ae23d8bd8252dac4144c15a6295741f560dd Mon Sep 17 00:00:00 2001 From: Andrey Anastasov <98102124+andrerun@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:09:03 +0200 Subject: [PATCH 4/8] Development README cosmetics Co-authored-by: Ismail Alidzhikov --- docs/development/README.md | 48 +++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/docs/development/README.md b/docs/development/README.md index 5ef08ccd..398d79ad 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -1,21 +1,27 @@ -### To debug gardener-custom-metrics (GCMx): -- Prerequisite: [Gardener local dev setup] -- Open a terminal -- Set current directory to project root -- Point $KUBECONFIG to the K8s cluster from the [Gardener local dev setup] -- Run `make debug`: - - This is a blocking call - - It builds and deploys a debug-instrumented pod to the cluster - - It forwards the pod's log output to the console window - - It forwards localhost:56268 to the debugger port for the pod -- Attach debugger to localhost:56268. At this point, if you place a breakpoint somewhere, it should be hit. - -### To build and publish GCMx: -These instructions are a work in progress and may contain errors -- Open a terminal -- Set current directory to project root -- Run `make docker-build` -- Run `make docker-login` -- Run `make docker-push` - -[Gardener local dev setup]: https://gardener.cloud/docs/gardener/deployment/getting_started_locally \ No newline at end of file +> 🚧 Note: This is a WIP document. + +### Debugging gardener-custom-metrics + +1. Make sure that you have a running local Gardener setup. The steps to complete this can be found in the [Deploying Gardener Locally guide](https://github.com/gardener/gardener/blob/master/docs/deployment/getting_started_locally.md). + +1. In a new terminal, navigate to the gardener-custom-metrics project root. + +1. Make sure that your `KUBECONFIG` environment variable is targeting the local Gardener cluster. + +1. Run `make debug`. + + This is a blocking call. It builds and deploys a debug-instrumented pod to the cluster. It forwards the pod's log output to the console window. It forwards `localhost:56268` to the debugger port for the pod. + +1. Attach debugger to `localhost:56268`. + + At this point, if you place a breakpoint somewhere, it should be hit. + +### Building and publishing gardener-custom-metrics container image: + +1. In a new terminal, navigate to the gardener-custom-metrics project root. + +1. Run `make docker-build` to build container image. + +1. Run `make docker-login` to authenticate against Artifact Registry before pushing the image. + +1. Run `make docker-push` to push the container image. From c5908edb6191e73e2eca7502cf49558839f7614c Mon Sep 17 00:00:00 2001 From: Andrey Anastasov <98102124+andrerun@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:10:40 +0200 Subject: [PATCH 5/8] README cosmetics Co-authored-by: Ismail Alidzhikov --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 95338b44..06a39eec 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # gardener-custom-metrics + [![REUSE status](https://api.reuse.software/badge/github.com/gardener/gardener-custom-metrics)](https://api.reuse.software/info/github.com/gardener/gardener-custom-metrics) + ## Overview -The `gardener-custom-metrics` component operates as a K8s API service, adding functionality to the seed kube-apiserver. -It periodically scrapes the metrics endpoints of all shoot kube-apiserver pods on the seed. It implements the K8s custom -metrics API and provides K8s metrics specific to Gardener, based on custom calculations. + +The `gardener-custom-metrics` component operates as a K8s API service, adding functionality to the seed kube-apiserver. It periodically scrapes the metrics endpoints of all shoot kube-apiserver pods on the seed. It implements the K8s custom metrics API and provides K8s metrics specific to Gardener, based on custom calculations. + From 3e4add3868cab1665e957f9e96f8e902e8808937 Mon Sep 17 00:00:00 2001 From: Andrey Anastasov <98102124+andrerun@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:26:37 +0200 Subject: [PATCH 6/8] Makefile - remove TODO --- Makefile | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Makefile b/Makefile index f60b0707..6501a8d8 100644 --- a/Makefile +++ b/Makefile @@ -154,10 +154,3 @@ debug: $(SKAFFOLD) # TODO: Andrey: P1: Inject TLS secret name dynamically into deployment # GCMX_TLS_SECRET_NAME=$(kubectl -n garden get secrets | grep '^gardener-custom-metrics' | head -n 1 | awk '{print $1}') \ - # TODO: Andrey: P1: code cleanup - # export SKAFFOLD_DEFAULT_REPO = localhost:5001 - # export SKAFFOLD_PUSH = true - - # skaffold dev triggers new builds and deployments immediately on file changes by default, - # this is too heavy in a large project like gardener, so trigger new builds and deployments manually instead. - # gardener%dev gardenlet%dev operator-dev: export SKAFFOLD_TRIGGER = manual From 8e9248a468562a742d3f142153efe0e65449e2b1 Mon Sep 17 00:00:00 2001 From: Andrey Anastasov <98102124+andrerun@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:53:22 +0200 Subject: [PATCH 7/8] Bump pipeline_definitions to golang:1.22.1 --- .ci/pipeline_definitions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/pipeline_definitions b/.ci/pipeline_definitions index b3d220d6..e68679dd 100644 --- a/.ci/pipeline_definitions +++ b/.ci/pipeline_definitions @@ -36,7 +36,7 @@ gardener-custom-metrics: release: steps: verify: - image: 'golang:1.19.9' + image: 'golang:1.22.1' traits: version: preprocess: 'finalize' From b80af7c7058f50da2a576e42343cdfeed0831a02 Mon Sep 17 00:00:00 2001 From: Andrey Anastasov <98102124+andrerun@users.noreply.github.com> Date: Thu, 21 Mar 2024 17:09:38 +0200 Subject: [PATCH 8/8] Drop inactive configuration from skaffold.yaml --- skaffold.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/skaffold.yaml b/skaffold.yaml index b3e00b11..90baa450 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -24,8 +24,5 @@ profiles: manifests: rawYaml: - example/custom-metrics-deployment.yaml -# kustomize: -# paths: -# - example/provider-local/seed-kind2/skaffold deploy: kubectl: {}