mirror of
https://github.com/zalando-incubator/kube-metrics-adapter.git
synced 2026-03-14 12:07:36 +00:00
Compare commits
38 Commits
update-jwt
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 55bb290076 | |||
| 70641827ce | |||
| 99ca95588e | |||
| cc9952d66e | |||
| 58c6a56cbf | |||
| 9e3a1760f1 | |||
| 0e52e076c1 | |||
| 18faf9c076 | |||
| 170faf8809 | |||
| 419f75cf18 | |||
| 0fe764be7c | |||
| 6a245b7e1e | |||
| 7a4d08cd77 | |||
| 1a9eaeedcb | |||
| 0227a3fa07 | |||
| 430b2382f6 | |||
| f64cfab5c9 | |||
| 19b1706f6c | |||
| 335dc1ff56 | |||
| 23f65af774 | |||
| a0263ae7f9 | |||
| 90a0e28490 | |||
| 724a613dda | |||
| 33db2b700c | |||
| 4bde6c3b98 | |||
| f295dfa4b6 | |||
| b9a1cf9a26 | |||
| adba88129b | |||
| 0a6f40369b | |||
| e263f964e9 | |||
| 88d8843e96 | |||
| ef298ca774 | |||
| bfd050e5b6 | |||
| e0240911c6 | |||
| 32bda8016a | |||
| 42abde30f9 | |||
| 5124f33c5d | |||
| 1e042c124c |
@@ -10,8 +10,8 @@ jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/checkout@v6.0.2
|
||||
- uses: actions/setup-go@v6.2.0
|
||||
with:
|
||||
go-version: '^1.25'
|
||||
- run: go version
|
||||
|
||||
@@ -38,16 +38,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6.2.0
|
||||
with:
|
||||
go-version: '1.22'
|
||||
go-version: '1.25'
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
uses: github/codeql-action/autobuild@v4
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@@ -74,4 +74,4 @@ jobs:
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v4
|
||||
|
||||
@@ -25,15 +25,15 @@ jobs:
|
||||
packages: write # to push packages
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
|
||||
uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
|
||||
|
||||
- uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753
|
||||
- uses: actions/setup-go@a5f9b05d2d216f63e13859e0d847461041025775
|
||||
with:
|
||||
# https://www.npmjs.com/package/semver#caret-ranges-123-025-004
|
||||
go-version: '^1.25'
|
||||
|
||||
- name: Login to Github Container Registry
|
||||
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -47,21 +47,21 @@ jobs:
|
||||
make build.linux.amd64 build.linux.arm64
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Docker meta
|
||||
uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
|
||||
id: meta
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
type=semver,pattern=v{{major}}.{{minor}}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
||||
with:
|
||||
context: .
|
||||
build-args: BASE_IMAGE=gcr.io/distroless/static-debian12
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
|
||||
# Build and push latest tag
|
||||
- name: Build and push latest
|
||||
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
||||
with:
|
||||
context: .
|
||||
build-args: BASE_IMAGE=gcr.io/distroless/static-debian12
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Run chart-releaser
|
||||
uses: helm/chart-releaser-action@v1.4.0
|
||||
uses: helm/chart-releaser-action@v1.7.0
|
||||
with:
|
||||
charts_dir: docs
|
||||
env:
|
||||
|
||||
@@ -34,12 +34,12 @@ $(GENERATED): go.mod $(CRD_TYPE_SOURCE) $(OPENAPI)
|
||||
./hack/update-codegen.sh
|
||||
|
||||
$(GENERATED_CRDS): $(GENERATED) $(CRD_SOURCES)
|
||||
go run sigs.k8s.io/controller-tools/cmd/controller-gen crd:crdVersions=v1 paths=./pkg/apis/... output:crd:dir=docs
|
||||
go tool controller-gen crd:crdVersions=v1 paths=./pkg/apis/... output:crd:dir=docs
|
||||
mv docs/zalando.org_clusterscalingschedules.yaml docs/cluster_scaling_schedules_crd.yaml
|
||||
mv docs/zalando.org_scalingschedules.yaml docs/scaling_schedules_crd.yaml
|
||||
|
||||
$(OPENAPI): go.mod
|
||||
go run k8s.io/kube-openapi/cmd/openapi-gen \
|
||||
go tool openapi-gen \
|
||||
--go-header-file hack/boilerplate.go.txt \
|
||||
--logtostderr \
|
||||
--output-dir pkg/api/generated/openapi \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: kube-metrics-adapter
|
||||
version: 0.2.3
|
||||
version: 0.2.6
|
||||
description: kube-metrics-adapter helm chart
|
||||
home: https://github.com/zalando-incubator/kube-metrics-adapter
|
||||
maintainers:
|
||||
|
||||
@@ -3,6 +3,13 @@ apiVersion: apiregistration.k8s.io/v1
|
||||
kind: APIService
|
||||
metadata:
|
||||
name: v1beta1.custom.metrics.k8s.io
|
||||
{{- with .Values.customMetricsApi.annotations }}
|
||||
annotations:
|
||||
{{- range $k, $v := . }}
|
||||
{{- $value := $v | quote }}
|
||||
{{- printf "%s: %s" (tpl $k $) (tpl $value $) | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
service:
|
||||
name: kube-metrics-adapter
|
||||
@@ -13,3 +20,4 @@ spec:
|
||||
groupPriorityMinimum: 100
|
||||
versionPriority: 100
|
||||
{{- end}}
|
||||
""
|
||||
|
||||
@@ -3,6 +3,13 @@ apiVersion: apiregistration.k8s.io/v1
|
||||
kind: APIService
|
||||
metadata:
|
||||
name: v1beta1.external.metrics.k8s.io
|
||||
{{- with .Values.externalMetricsApi.annotations }}
|
||||
annotations:
|
||||
{{- range $k, $v := . }}
|
||||
{{- $value := $v | quote }}
|
||||
{{- printf "%s: %s" (tpl $k $) (tpl $value $) | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
service:
|
||||
name: kube-metrics-adapter
|
||||
|
||||
+13
-1
@@ -4,7 +4,7 @@ replicas: 1
|
||||
|
||||
registry:
|
||||
image: ghcr.io/zalando-incubator/kube-metrics-adapter
|
||||
imageTag: v0.2.3
|
||||
imageTag: v0.2.6
|
||||
imagePullPolicy: IfNotPresent
|
||||
|
||||
service:
|
||||
@@ -15,7 +15,19 @@ addDirectoryHeader:
|
||||
contentionProfiling:
|
||||
profiling:
|
||||
enableCustomMetricsApi: true
|
||||
|
||||
# -- add annotations to the custom metrics apiservice resource, e.g.
|
||||
# cert-manager.io/inject-ca-from: {{.Release.Namespace}}/kube-metrics-adapter to inject the CA certificate form a cert-manager-issued cert used for the deployment
|
||||
customMetricsApi:
|
||||
annotations: {}
|
||||
|
||||
enableExternalMetricsApi: true
|
||||
|
||||
# -- add annotations to the custom metrics apiservice resource, e.g.
|
||||
# cert-manager.io/inject-ca-from: {{.Release.Namespace}}/kube-metrics-adapter to inject the CA certificate form a cert-manager-issued cert used for the deployment
|
||||
externalMetricsApi:
|
||||
annotations: {}
|
||||
|
||||
credentialsDirectory:
|
||||
disregardIncompatibleHPAs:
|
||||
http2MaxStreamsPerConnection:
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
module github.com/zalando-incubator/kube-metrics-adapter
|
||||
|
||||
require (
|
||||
github.com/argoproj/argo-rollouts v1.8.3
|
||||
github.com/aws/aws-sdk-go-v2 v1.38.3
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.6
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.42.3
|
||||
github.com/argoproj/argo-rollouts v1.8.4
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.7
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.42.21
|
||||
github.com/influxdata/influxdb-client-go v1.4.0
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/prometheus/common v0.66.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.10.1
|
||||
github.com/prometheus/common v0.67.5
|
||||
github.com/sirupsen/logrus v1.9.4
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spyzhov/ajson v0.9.6
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/szuecs/routegroup-client v0.28.2
|
||||
github.com/szuecs/routegroup-client v0.34.1
|
||||
github.com/zalando-incubator/cluster-lifecycle-manager v0.0.0-20250912104308-4489de744ee3
|
||||
golang.org/x/net v0.44.0
|
||||
golang.org/x/oauth2 v0.31.0
|
||||
golang.org/x/sync v0.17.0
|
||||
k8s.io/api v0.34.0
|
||||
k8s.io/apimachinery v0.34.0
|
||||
k8s.io/apiserver v0.34.0
|
||||
k8s.io/client-go v0.34.0
|
||||
k8s.io/code-generator v0.34.0
|
||||
k8s.io/component-base v0.34.0
|
||||
golang.org/x/oauth2 v0.35.0
|
||||
golang.org/x/sync v0.19.0
|
||||
k8s.io/api v0.34.4
|
||||
k8s.io/apimachinery v0.34.4
|
||||
k8s.io/apiserver v0.34.4
|
||||
k8s.io/client-go v0.34.4
|
||||
k8s.io/component-base v0.34.4
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
k8s.io/metrics v0.33.1
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
||||
sigs.k8s.io/controller-tools v0.19.0
|
||||
sigs.k8s.io/custom-metrics-apiserver v1.33.0
|
||||
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||
k8s.io/metrics v0.34.4
|
||||
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4
|
||||
sigs.k8s.io/custom-metrics-apiserver v1.34.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -42,23 +39,25 @@ require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.29.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.38.2 // indirect
|
||||
github.com/aws/smithy-go v1.23.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/bytedance/sonic v1.11.9 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
@@ -66,7 +65,7 @@ require (
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deepmap/oapi-codegen v1.16.3 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
@@ -170,23 +169,25 @@ require (
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.42.0 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.28.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/term v0.35.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/mod v0.30.0 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/term v0.38.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.37.0 // indirect
|
||||
golang.org/x/tools v0.39.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/grpc v1.72.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
@@ -194,14 +195,26 @@ require (
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.0 // indirect
|
||||
k8s.io/code-generator v0.34.4 // indirect
|
||||
k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kms v0.34.0 // indirect
|
||||
k8s.io/kms v0.34.4 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
|
||||
sigs.k8s.io/controller-tools v0.19.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
)
|
||||
|
||||
tool (
|
||||
k8s.io/code-generator
|
||||
k8s.io/code-generator/cmd/client-gen
|
||||
k8s.io/code-generator/cmd/deepcopy-gen
|
||||
k8s.io/code-generator/cmd/informer-gen
|
||||
k8s.io/code-generator/cmd/lister-gen
|
||||
k8s.io/kube-openapi/cmd/openapi-gen
|
||||
sigs.k8s.io/controller-tools/cmd/controller-gen
|
||||
)
|
||||
|
||||
go 1.24.2
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
// +build tools
|
||||
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// This package imports things required by build scripts, to force `go mod` to see them as dependencies
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "k8s.io/code-generator"
|
||||
_ "k8s.io/kube-openapi/cmd/openapi-gen"
|
||||
_ "sigs.k8s.io/controller-tools/cmd/controller-gen"
|
||||
)
|
||||
@@ -31,14 +31,14 @@ APIS_PKG="${GOPKG}/pkg/apis"
|
||||
GROUPS_WITH_VERSIONS="${CUSTOM_RESOURCE_NAME}:${CUSTOM_RESOURCE_VERSION}"
|
||||
|
||||
echo "Generating deepcopy funcs"
|
||||
go run k8s.io/code-generator/cmd/deepcopy-gen \
|
||||
go tool deepcopy-gen \
|
||||
--output-file zz_generated.deepcopy.go \
|
||||
--bounding-dirs "${APIS_PKG}" \
|
||||
--go-header-file "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
|
||||
"${APIS_PKG}/${CUSTOM_RESOURCE_NAME}/${CUSTOM_RESOURCE_VERSION}"
|
||||
|
||||
echo "Generating clientset for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}"
|
||||
go run k8s.io/code-generator/cmd/client-gen \
|
||||
go tool client-gen \
|
||||
--clientset-name versioned \
|
||||
--input-base "" \
|
||||
--input "${APIS_PKG}/${CUSTOM_RESOURCE_NAME}/${CUSTOM_RESOURCE_VERSION}" \
|
||||
@@ -47,14 +47,14 @@ go run k8s.io/code-generator/cmd/client-gen \
|
||||
--output-dir "${OUTPUT_DIR}/clientset"
|
||||
|
||||
echo "Generating listers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/listers"
|
||||
go run k8s.io/code-generator/cmd/lister-gen \
|
||||
go tool lister-gen \
|
||||
--output-pkg "${OUTPUT_PKG}/listers" \
|
||||
--go-header-file "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
|
||||
--output-dir "${OUTPUT_DIR}/listers" \
|
||||
"${APIS_PKG}/${CUSTOM_RESOURCE_NAME}/${CUSTOM_RESOURCE_VERSION}"
|
||||
|
||||
echo "Generating informers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/informers"
|
||||
go run k8s.io/code-generator/cmd/informer-gen \
|
||||
go tool informer-gen \
|
||||
--versioned-clientset-package "${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}/${CLIENTSET_NAME_VERSIONED:-versioned}" \
|
||||
--listers-package "${OUTPUT_PKG}/listers" \
|
||||
--output-pkg "${OUTPUT_PKG}/informers" \
|
||||
|
||||
@@ -268,7 +268,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||
"k8s.io/api/core/v1.WeightedPodAffinityTerm": schema_k8sio_api_core_v1_WeightedPodAffinityTerm(ref),
|
||||
"k8s.io/api/core/v1.WindowsSecurityContextOptions": schema_k8sio_api_core_v1_WindowsSecurityContextOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/api/resource.Quantity": schema_apimachinery_pkg_api_resource_Quantity(ref),
|
||||
"k8s.io/apimachinery/pkg/api/resource.int64Amount": schema_apimachinery_pkg_api_resource_int64Amount(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup": schema_pkg_apis_meta_v1_APIGroup(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIGroupList": schema_pkg_apis_meta_v1_APIGroupList(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIResource": schema_pkg_apis_meta_v1_APIResource(ref),
|
||||
@@ -15167,15 +15166,12 @@ func schema_pkg_apis_meta_v1_InternalEvent(ref common.ReferenceCallback) common.
|
||||
"Object": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Object is:\n * If Type is Added or Modified: the new state of the object.\n * If Type is Deleted: the state of the object immediately before deletion.\n * If Type is Bookmark: the object (instance of a type being watched) where\n only ResourceVersion field is set. On successful restart of watch from a\n bookmark resourceVersion, client is guaranteed to not get repeat event\n nor miss any events.\n * If Type is Error: *api.Status is recommended; other types may make sense\n depending on context.",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/runtime.Object"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"Type", "Object"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/apimachinery/pkg/runtime.Object"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package collector
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -182,6 +183,25 @@ type MetricTypeName struct {
|
||||
Metric autoscalingv2.MetricIdentifier
|
||||
}
|
||||
|
||||
func (m MetricTypeName) String() string {
|
||||
str := fmt.Sprintf("%s/%s", m.Type, m.Metric.Name)
|
||||
if m.Metric.Selector != nil && len(m.Metric.Selector.MatchLabels) > 0 {
|
||||
str += " " + mapToString(m.Metric.Selector.MatchLabels)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func mapToString(m map[string]string) string {
|
||||
str := "{"
|
||||
keyVals := make([]string, 0, len(m))
|
||||
for k, v := range m {
|
||||
keyVals = append(keyVals, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
str += strings.Join(keyVals, ",")
|
||||
str += "}"
|
||||
return str
|
||||
}
|
||||
|
||||
type CollectedMetric struct {
|
||||
Type autoscalingv2.MetricSourceType
|
||||
Namespace string
|
||||
|
||||
@@ -30,6 +30,88 @@ func (c *mockCollector) Interval() time.Duration {
|
||||
return 0
|
||||
}
|
||||
|
||||
func TestMetricTypeName_String(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
metricType autoscalingv2.MetricSourceType
|
||||
metricName string
|
||||
selector *metav1.LabelSelector
|
||||
expectedStr string
|
||||
shouldContain []string
|
||||
}{
|
||||
{
|
||||
name: "nil selector with PodsMetricSourceType",
|
||||
metricType: autoscalingv2.PodsMetricSourceType,
|
||||
metricName: "metric-name",
|
||||
selector: nil,
|
||||
expectedStr: "Pods/metric-name",
|
||||
},
|
||||
{
|
||||
name: "nil selector with ObjectMetricSourceType",
|
||||
metricType: autoscalingv2.ObjectMetricSourceType,
|
||||
metricName: "metric-name",
|
||||
selector: nil,
|
||||
expectedStr: "Object/metric-name",
|
||||
},
|
||||
{
|
||||
name: "nil selector with ExternalMetricSourceType",
|
||||
metricType: autoscalingv2.ExternalMetricSourceType,
|
||||
metricName: "metric-name",
|
||||
selector: nil,
|
||||
expectedStr: "External/metric-name",
|
||||
},
|
||||
{
|
||||
name: "empty selector (non-nil but empty MatchLabels)",
|
||||
metricType: autoscalingv2.ExternalMetricSourceType,
|
||||
metricName: "metric-name",
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{},
|
||||
},
|
||||
expectedStr: "External/metric-name",
|
||||
},
|
||||
{
|
||||
name: "selector with single MatchLabel",
|
||||
metricType: autoscalingv2.ExternalMetricSourceType,
|
||||
metricName: "metric-name",
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"key": "value"},
|
||||
},
|
||||
shouldContain: []string{"External/metric-name", "key=value"},
|
||||
},
|
||||
{
|
||||
name: "selector with multiple MatchLabels",
|
||||
metricType: autoscalingv2.ExternalMetricSourceType,
|
||||
metricName: "metric-name",
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"key1": "val1", "key2": "val2"},
|
||||
},
|
||||
shouldContain: []string{"External/metric-name", "key1=val1", "key2=val2"},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mtn := MetricTypeName{
|
||||
Type: tc.metricType,
|
||||
Metric: autoscalingv2.MetricIdentifier{
|
||||
Name: tc.metricName,
|
||||
Selector: tc.selector,
|
||||
},
|
||||
}
|
||||
|
||||
result := mtn.String()
|
||||
|
||||
if tc.expectedStr != "" {
|
||||
require.Equal(t, tc.expectedStr, result)
|
||||
}
|
||||
|
||||
if len(tc.shouldContain) > 0 {
|
||||
for _, substring := range tc.shouldContain {
|
||||
require.Contains(t, result, substring, "result should contain %q", substring)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCollector(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
msg string
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/metrics/pkg/apis/custom_metrics"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/zalando-incubator/kube-metrics-adapter/pkg/zmon"
|
||||
"golang.org/x/net/context"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package scheduledscaling
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package scheduledscaling
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -10,7 +11,6 @@ import (
|
||||
v1 "github.com/zalando-incubator/kube-metrics-adapter/pkg/apis/zalando.org/v1"
|
||||
zalandov1 "github.com/zalando-incubator/kube-metrics-adapter/pkg/client/clientset/versioned/typed/zalando.org/v1"
|
||||
"github.com/zalando-incubator/kube-metrics-adapter/pkg/recorder"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/sync/errgroup"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -57,7 +57,7 @@ var (
|
||||
type now func() time.Time
|
||||
|
||||
type scalingScheduleStore interface {
|
||||
List() []interface{}
|
||||
List() []any
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
@@ -325,7 +325,7 @@ func highestActiveSchedule(hpa *autoscalingv2.HorizontalPodAutoscaler, activeSch
|
||||
continue
|
||||
}
|
||||
|
||||
target := int64(metric.Object.Target.AverageValue.MilliValue() / 1000)
|
||||
target := float64(metric.Object.Target.AverageValue.MilliValue()) / 1000.0
|
||||
if target == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -338,10 +338,10 @@ func highestActiveSchedule(hpa *autoscalingv2.HorizontalPodAutoscaler, activeSch
|
||||
value = activeSchedules[scheduleName]
|
||||
}
|
||||
|
||||
expected := int64(math.Ceil(float64(value) / float64(target)))
|
||||
expected := int64(math.Ceil(float64(value) / target))
|
||||
if expected > highestExpected {
|
||||
highestExpected = expected
|
||||
usageRatio = float64(value) / (float64(target) * float64(currentReplicas))
|
||||
usageRatio = float64(value) / (target * float64(currentReplicas))
|
||||
highestObject = metric.Object.DescribedObject
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,35 +336,42 @@ func TestAdjustScaling(t *testing.T) {
|
||||
msg string
|
||||
currentReplicas int32
|
||||
desiredReplicas int32
|
||||
targetValue int64
|
||||
targetValue string
|
||||
scheduleTarget int64
|
||||
}{
|
||||
{
|
||||
msg: "current less than 10%% below desired (target 10000)",
|
||||
currentReplicas: 28, // 7.1% increase to desired
|
||||
desiredReplicas: 31,
|
||||
targetValue: 333, // 10000/333 ~= 31
|
||||
targetValue: "333", // 10000/333 ~= 31
|
||||
scheduleTarget: 10000,
|
||||
},
|
||||
{
|
||||
msg: "current less than 10%% below desired",
|
||||
currentReplicas: 95, // 5.3% increase to desired
|
||||
desiredReplicas: 100,
|
||||
targetValue: 10, // 1000/10 = 100
|
||||
targetValue: "10", // 1000/10 = 100
|
||||
scheduleTarget: 1000,
|
||||
},
|
||||
{
|
||||
msg: "current more than 10%% below desired, no adjustment",
|
||||
currentReplicas: 90, // 11% increase to desired
|
||||
desiredReplicas: 90,
|
||||
targetValue: 10, // 1000/10 = 100
|
||||
targetValue: "10", // 1000/10 = 100
|
||||
scheduleTarget: 1000,
|
||||
},
|
||||
{
|
||||
msg: "invalid HPA should not do any adjustment",
|
||||
currentReplicas: 95,
|
||||
desiredReplicas: 95,
|
||||
targetValue: 0, // this is treated as invalid in the test, thus the HPA is ingored and no adjustment happens.
|
||||
targetValue: "", // this is treated as invalid in the test, thus the HPA is ingored and no adjustment happens.
|
||||
scheduleTarget: 1000,
|
||||
},
|
||||
{
|
||||
msg: "handle milivalue as targetValue",
|
||||
currentReplicas: 90, // 5.8% increase to desired
|
||||
desiredReplicas: 96,
|
||||
targetValue: "10500m", // 1000/10.5 ~= 96
|
||||
scheduleTarget: 1000,
|
||||
},
|
||||
} {
|
||||
@@ -444,8 +451,11 @@ func TestAdjustScaling(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
if tc.targetValue != 0 {
|
||||
hpa.Spec.Metrics[0].Object.Target.AverageValue = resource.NewQuantity(tc.targetValue, resource.DecimalSI)
|
||||
if tc.targetValue != "" {
|
||||
quantity, err := resource.ParseQuantity(tc.targetValue)
|
||||
require.NoError(t, err)
|
||||
|
||||
hpa.Spec.Metrics[0].Object.Target.AverageValue = &quantity
|
||||
}
|
||||
|
||||
hpa, err = kubeClient.AutoscalingV2().HorizontalPodAutoscalers("default").Create(context.Background(), hpa, metav1.CreateOptions{})
|
||||
|
||||
+92
-28
@@ -8,6 +8,10 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v5"
|
||||
)
|
||||
|
||||
// Nakadi defines an interface for talking to the Nakadi API.
|
||||
@@ -95,26 +99,40 @@ func (c *Client) subscriptions(ctx context.Context, filter *SubscriptionFilter,
|
||||
endpoint.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[nakadi subscriptions] failed to create request: %w", err)
|
||||
op := func() ([]byte, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[nakadi subscriptions] failed to create request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[nakadi subscriptions] failed to make request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkResponseStatus(resp, b); err != nil {
|
||||
return nil, fmt.Errorf("[nakadi subscriptions] %w", err)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[nakadi subscriptions] failed to make request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
d, err := io.ReadAll(resp.Body)
|
||||
d, err := backoff.Retry(
|
||||
ctx,
|
||||
op,
|
||||
backoff.WithBackOff(exponentialBackoff()),
|
||||
backoff.WithMaxTries(3),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("[nakadi subscriptions] unexpected response code: %d (%s)", resp.StatusCode, string(d))
|
||||
}
|
||||
|
||||
var subscriptionsResp struct {
|
||||
Items []struct {
|
||||
ID string `json:"id"`
|
||||
@@ -194,26 +212,40 @@ func (c *Client) stats(ctx context.Context, filter *SubscriptionFilter) ([]stats
|
||||
q.Set("show_time_lag", "true")
|
||||
endpoint.RawQuery = q.Encode()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[nakadi stats] failed to create request: %w", err)
|
||||
op := func() ([]byte, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[nakadi stats] failed to create request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[nakadi stats] failed to make request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkResponseStatus(resp, b); err != nil {
|
||||
return nil, fmt.Errorf("[nakadi stats] %w", err)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[nakadi stats] failed to make request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
d, err := io.ReadAll(resp.Body)
|
||||
d, err := backoff.Retry(
|
||||
ctx,
|
||||
op,
|
||||
backoff.WithBackOff(exponentialBackoff()),
|
||||
backoff.WithMaxTries(3),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("[nakadi stats] unexpected response code: %d (%s)", resp.StatusCode, string(d))
|
||||
}
|
||||
|
||||
var result statsResp
|
||||
err = json.Unmarshal(d, &result)
|
||||
if err != nil {
|
||||
@@ -229,3 +261,35 @@ func (c *Client) stats(ctx context.Context, filter *SubscriptionFilter) ([]stats
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func checkResponseStatus(resp *http.Response, b []byte) error {
|
||||
if resp.StatusCode == http.StatusTooManyRequests {
|
||||
h := resp.Header.Get("Retry-After")
|
||||
if h == "" {
|
||||
return fmt.Errorf("unexpected response code: %d (%s)", resp.StatusCode, string(b))
|
||||
|
||||
}
|
||||
sec, err := strconv.ParseInt(h, 10, 32)
|
||||
if err != nil {
|
||||
return backoff.Permanent(err)
|
||||
}
|
||||
return backoff.RetryAfter(int(sec))
|
||||
}
|
||||
if resp.StatusCode >= http.StatusBadRequest &&
|
||||
resp.StatusCode < http.StatusInternalServerError {
|
||||
return backoff.Permanent(
|
||||
fmt.Errorf("non-retryable response code: %d (%s)", resp.StatusCode, string(b)),
|
||||
)
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("unexpected response code: %d (%s)", resp.StatusCode, string(b))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func exponentialBackoff() backoff.BackOff {
|
||||
b := backoff.NewExponentialBackOff()
|
||||
b.MaxInterval = time.Second * 30
|
||||
b.InitialInterval = time.Millisecond * 100
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cenkalti/backoff/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -210,11 +212,70 @@ func TestQuery(tt *testing.T) {
|
||||
|
||||
nakadiClient := NewNakadiClient(ts.URL, client)
|
||||
consumerLagSeconds, err := nakadiClient.ConsumerLagSeconds(context.Background(), ti.subscriptionFilter)
|
||||
assert.Equal(t, ti.err, err)
|
||||
assertErrorMessage(t, ti.err, err)
|
||||
assert.Equal(t, ti.consumerLagSeconds, consumerLagSeconds)
|
||||
unconsumedEvents, err := nakadiClient.UnconsumedEvents(context.Background(), ti.subscriptionFilter)
|
||||
assert.Equal(t, ti.err, err)
|
||||
assertErrorMessage(t, ti.err, err)
|
||||
assert.Equal(t, ti.unconsumedEvents, unconsumedEvents)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_checkResponseStatus(tt *testing.T) {
|
||||
for _, ti := range []struct {
|
||||
msg string
|
||||
resp *http.Response
|
||||
errCheck func(error) bool
|
||||
}{
|
||||
{
|
||||
msg: "nil when 200",
|
||||
resp: &http.Response{StatusCode: http.StatusOK},
|
||||
},
|
||||
{
|
||||
msg: "backoff.Permanent when 4xx",
|
||||
resp: &http.Response{StatusCode: http.StatusBadRequest},
|
||||
errCheck: func(err error) bool {
|
||||
var permanentErr *backoff.PermanentError
|
||||
return errors.As(err, &permanentErr)
|
||||
},
|
||||
},
|
||||
{
|
||||
msg: "unexpected error when 422 without Retry-After header",
|
||||
resp: &http.Response{StatusCode: http.StatusTooManyRequests},
|
||||
errCheck: func(err error) bool {
|
||||
return strings.Contains(err.Error(), "unexpected response code")
|
||||
},
|
||||
},
|
||||
{
|
||||
msg: "backoff.RetryAfter when 422 with Retry-After header",
|
||||
resp: &http.Response{
|
||||
StatusCode: http.StatusTooManyRequests,
|
||||
Header: http.Header{
|
||||
"Retry-After": []string{"120"},
|
||||
},
|
||||
},
|
||||
errCheck: func(err error) bool {
|
||||
var retryAfterErr *backoff.RetryAfterError
|
||||
return errors.As(err, &retryAfterErr)
|
||||
},
|
||||
},
|
||||
} {
|
||||
tt.Run(ti.msg, func(t *testing.T) {
|
||||
err := checkResponseStatus(ti.resp, nil)
|
||||
if ti.errCheck == nil {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.True(t, ti.errCheck(err))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertErrorMessage(t *testing.T, expected, actual error) {
|
||||
t.Helper()
|
||||
if expected != nil {
|
||||
assert.EqualError(t, actual, expected.Error())
|
||||
} else {
|
||||
assert.NoError(t, actual)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -3,6 +3,7 @@ package provider
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -345,7 +346,7 @@ type CollectorScheduler struct {
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// NewCollectorScheudler initializes a new CollectorScheduler.
|
||||
// NewCollectorScheduler initializes a new CollectorScheduler.
|
||||
func NewCollectorScheduler(ctx context.Context, metricsc chan<- metricCollection) *CollectorScheduler {
|
||||
return &CollectorScheduler{
|
||||
ctx: ctx,
|
||||
@@ -375,14 +376,17 @@ func (t *CollectorScheduler) Add(resourceRef resourceReference, typeName collect
|
||||
collectors[typeName] = cancel
|
||||
|
||||
// start runner for new collector
|
||||
go collectorRunner(ctx, metricCollector, t.metricSink)
|
||||
go collectorRunner(ctx, typeName, metricCollector, t.metricSink)
|
||||
}
|
||||
|
||||
// collectorRunner runs a collector at the desirec interval. If the passed
|
||||
// context is canceled the collection will be stopped.
|
||||
func collectorRunner(ctx context.Context, collector collector.Collector, metricsc chan<- metricCollection) {
|
||||
func collectorRunner(ctx context.Context, typeName collector.MetricTypeName, collector collector.Collector, metricsc chan<- metricCollection) {
|
||||
for {
|
||||
values, err := collector.GetMetrics(ctx)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("getting metrics for %s failed: %w", typeName, err)
|
||||
}
|
||||
|
||||
metricsc <- metricCollection{
|
||||
Values: values,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/zalando-incubator/kube-metrics-adapter/pkg/collector"
|
||||
"golang.org/x/net/context"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
@@ -70,6 +70,8 @@ func NewCommandStartAdapterServer(stopCh <-chan struct{}) *cobra.Command {
|
||||
NakadiTokenName: "nakadi",
|
||||
CredentialsDir: "/meta/credentials",
|
||||
ExternalRPSMetricName: "skipper_serve_host_duration_seconds_count",
|
||||
KubeClientQPS: 0.0, // 0.0 will use the 5.0 default in client-go
|
||||
KubeClientBurst: 0, // 0 will use the 10 default in client-go
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -153,6 +155,10 @@ func NewCommandStartAdapterServer(stopCh <-chan struct{}) *cobra.Command {
|
||||
"The name of the metric that should be used to query prometheus for RPS per hostname.")
|
||||
flags.BoolVar(&o.ExternalRPSMetrics, "external-rps-metrics", o.ExternalRPSMetrics, ""+
|
||||
"whether to enable external RPS metric collector or not")
|
||||
flags.Float64Var(&o.KubeClientQPS, "kube-client-qps", o.KubeClientQPS, ""+
|
||||
"maximum queries per second (QPS) to the Kubernetes API server (increase for large clusters), defaults to 5")
|
||||
flags.IntVar(&o.KubeClientBurst, "kube-client-burst", o.KubeClientBurst, ""+
|
||||
"maximum burst for throttle to the Kubernetes API server (increase for large clusters, defaults to 10)")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -199,6 +205,8 @@ func (o AdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-chan struct
|
||||
}()
|
||||
|
||||
clientConfig.Timeout = defaultClientGOTimeout
|
||||
clientConfig.QPS = float32(o.KubeClientQPS)
|
||||
clientConfig.Burst = o.KubeClientBurst
|
||||
|
||||
client, err := kubernetes.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
@@ -546,4 +554,8 @@ type AdapterServerOptions struct {
|
||||
ExternalRPSMetrics bool
|
||||
// Name of the Prometheus metric that stores RPS by hostname for external RPS metrics.
|
||||
ExternalRPSMetricName string
|
||||
// KubeClientQPS configures the maximum QPS to the Kubernetes API server
|
||||
KubeClientQPS float64
|
||||
// KubeClientBurst configures the maximum burst for throttle to the Kubernetes API server
|
||||
KubeClientBurst int
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user