Compare commits

...

122 Commits

Author SHA1 Message Date
Kubernetes Prow Robot bc45a49c9b
Merge pull request #2719 from Rishab87/reason-label
feat: include reason label to `kube_deployment_status_condition`
2025-08-14 08:27:09 -07:00
Rishab87 012b46d220 adding empty string in reasons 2025-08-14 18:32:48 +05:30
Kubernetes Prow Robot 1556ac589f
Merge pull request #2723 from ydFu/patch-1
docs: Update metrics-store-performance-optimization.md
2025-08-13 10:53:09 -07:00
Rishab87 547afad282 adding reasons from deployment_utils.go 2025-08-13 22:35:44 +05:30
Kubernetes Prow Robot 997272f779
Merge pull request #2731 from kubernetes/dependabot/github_actions/actions/checkout-5.0.0
build(deps): Bump actions/checkout from 4.2.2 to 5.0.0
2025-08-11 12:55:07 -07:00
dependabot[bot] bd174abd54
build(deps): Bump actions/checkout from 4.2.2 to 5.0.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11bd71901b...08c6903cd8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 19:45:26 +00:00
Rishab87 b5820387c0 adding empty reason in allowedList 2025-08-11 20:50:42 +05:30
Rishab87 bc1e7f8965 fixing empty reasons and adding tests 2025-08-11 20:16:08 +05:30
Rishab87 b30335fa54 changing empty reasons to unkown 2025-08-08 21:46:48 +05:30
Ader Fu 9222ba465f
Update metrics-store-performance-optimization.md 2025-08-08 16:54:27 +08:00
Kubernetes Prow Robot 95b29ac8a9
Merge pull request #2714 from Rishab87/fix-md-format
fix: Fixed the format of Markdown files
2025-08-07 06:05:43 -07:00
Rishab87 f8f39bc9fc disabling md041 in PR template 2025-08-07 17:40:54 +05:30
Kubernetes Prow Robot 3a0eec4626
Merge pull request #2720 from mrueg/k8s-1.33
chore: Build with k8s 1.33
2025-08-07 01:07:41 -07:00
Kubernetes Prow Robot d680e8c991
Merge pull request #2705 from rashmichandrashekar/rashmi/ksm-config-override
fix: Config file overrides apply to some fields but not other
2025-08-06 01:09:26 -07:00
Rashmi Chandrashekar 921147623e support overrides 2025-08-05 19:30:00 -07:00
Rishab87 5de7a63748 addressing reviews 2025-08-05 17:23:48 +05:30
Rishab87 0a50cabaf9 added reason label 2025-08-05 16:35:42 +05:30
Manuel Rüger 72ed667151 chore: Build with k8s 1.33 2025-08-04 23:16:39 +02:00
Kubernetes Prow Robot 9add5df58e
Merge pull request #2716 from taraspos/patch-1
fix(customresourcestate): fix index out of range
2025-08-04 11:51:39 -07:00
Kubernetes Prow Robot 61cb551bb5
Merge pull request #2717 from kubernetes/dependabot/go_modules/github.com/prometheus/client_golang-1.23.0
build(deps): Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0
2025-08-04 07:33:40 -07:00
Rishab87 fc6ab5bf65 addressing reviews & fixing CI errors 2025-08-04 19:58:37 +05:30
Rishab Kumar Jha c309d3a00f
Update README.md
Co-authored-by: Manuel Rüger <manuel@rueg.eu>
2025-08-04 19:53:32 +05:30
dependabot[bot] cb6bdd2046
build(deps): Bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.22.0 to 1.23.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 13:29:57 +00:00
Taras dc54dc6580
customresourcestate: fix panic 2025-08-04 14:07:41 +01:00
Rishab87 63a0298d5a fixed md024, md036, md040, md041, md033 rules 2025-08-02 23:42:45 +05:30
Kubernetes Prow Robot 61be81fa1f
Merge pull request #2712 from kubernetes/dependabot/go_modules/sigs.k8s.io/yaml-1.6.0
build(deps): Bump sigs.k8s.io/yaml from 1.5.0 to 1.6.0
2025-07-27 16:14:27 -07:00
dependabot[bot] c106a38fab
build(deps): Bump sigs.k8s.io/yaml from 1.5.0 to 1.6.0
Bumps [sigs.k8s.io/yaml](https://github.com/kubernetes-sigs/yaml) from 1.5.0 to 1.6.0.
- [Release notes](https://github.com/kubernetes-sigs/yaml/releases)
- [Changelog](https://github.com/kubernetes-sigs/yaml/blob/master/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/yaml/compare/v1.5.0...v1.6.0)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/yaml
  dependency-version: 1.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-27 23:06:40 +00:00
Kubernetes Prow Robot 104c83fb9f
Merge pull request #2710 from CatherineF-dev/master
chore: Add CatherineF-dev into SECURITY_CONTACTS
2025-07-24 10:00:27 -07:00
CatherineF-dev 9f6f1cd762
Add CatherineF-dev into SECURITY_CONTACTS 2025-07-21 15:25:25 -04:00
Kubernetes Prow Robot f421b9a69a
Merge pull request #2707 from kubernetes/dependabot/go_modules/github.com/KimMachineGun/automemlimit-0.7.4
build(deps): Bump github.com/KimMachineGun/automemlimit from 0.7.3 to 0.7.4
2025-07-14 05:22:23 -07:00
dependabot[bot] dd2ca7b09b
build(deps): Bump github.com/KimMachineGun/automemlimit
Bumps [github.com/KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit) from 0.7.3 to 0.7.4.
- [Release notes](https://github.com/KimMachineGun/automemlimit/releases)
- [Commits](https://github.com/KimMachineGun/automemlimit/compare/v0.7.3...v0.7.4)

---
updated-dependencies:
- dependency-name: github.com/KimMachineGun/automemlimit
  dependency-version: 0.7.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 11:37:51 +00:00
Kubernetes Prow Robot 6942640a45
Merge pull request #2699 from yshngg/feature/pod-metrics/unscheduled-time
feat(pod): Add new metric for pod unscheduled time tracking
2025-07-11 17:09:31 -07:00
yshngg a483701408 feat(pod): add new metric for pod unscheduled time tracking
The changes introduce a new metric generator `kube_pod_status_unscheduled_time` to record the Unix timestamp when pods transition to unscheduled status. This enhances monitoring capabilities for scheduling issues by capturing exact transition times during `PodScheduled` condition changes.
2025-07-01 16:06:28 +08:00
Kubernetes Prow Robot 56d3b561e6
Merge pull request #2696 from kubernetes/dependabot/go_modules/github.com/oklog/run-1.2.0
build(deps): Bump github.com/oklog/run from 1.1.0 to 1.2.0
2025-06-30 05:14:32 -07:00
Kubernetes Prow Robot dff9a1e8f5
Merge pull request #2697 from kubernetes/release-2.16
chore: Merge v2.16 back into `main`
2025-06-30 05:12:32 -07:00
dependabot[bot] a0889d56c8
build(deps): Bump github.com/oklog/run from 1.1.0 to 1.2.0
Bumps [github.com/oklog/run](https://github.com/oklog/run) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/oklog/run/releases)
- [Commits](https://github.com/oklog/run/compare/v1.1.0...v1.2.0)

---
updated-dependencies:
- dependency-name: github.com/oklog/run
  dependency-version: 1.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 11:32:37 +00:00
Kubernetes Prow Robot edc9db4649
Merge pull request #2694 from kubernetes/dependabot/go_modules/sigs.k8s.io/yaml-1.5.0
build(deps): Bump sigs.k8s.io/yaml from 1.4.0 to 1.5.0
2025-06-30 04:32:32 -07:00
dependabot[bot] 0a8f32ff12
build(deps): Bump sigs.k8s.io/yaml from 1.4.0 to 1.5.0
Bumps [sigs.k8s.io/yaml](https://github.com/kubernetes-sigs/yaml) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/kubernetes-sigs/yaml/releases)
- [Changelog](https://github.com/kubernetes-sigs/yaml/blob/master/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/yaml/compare/v1.4.0...v1.5.0)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/yaml
  dependency-version: 1.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 11:16:25 +00:00
Kubernetes Prow Robot 291a962840
Merge pull request #2692 from rexagod/prep-216
chore: Prep `v2.16` release
2025-06-25 05:52:30 -07:00
Pranshu Srivastava c6ae6f53f7
chore: Prep `v2.16` release
Signed-off-by: Pranshu Srivastava <rexagod@gmail.com>
2025-06-24 17:04:39 +05:30
Kubernetes Prow Robot 9576360078
Merge pull request #2693 from rexagod/make-examples-fix
fix: Fix `examples` target
2025-06-23 09:19:56 -07:00
Pranshu Srivastava 8b2aa61c70
fix: Fix `examples` target
Signed-off-by: Pranshu Srivastava <rexagod@gmail.com>
2025-06-23 19:27:58 +05:30
Kubernetes Prow Robot d59fe58df9
Merge pull request #2686 from mrueg/authfilter
feat: Add AuthFilter
2025-06-23 06:18:54 -07:00
Manuel Rüger 5e8e4fffa6
Update tests/e2e/auth-filter_test.go
Co-authored-by: Pranshu Srivastava <prasriva@redhat.com>
2025-06-23 14:18:44 +02:00
Manuel Rüger 301240eccc
Update tests/e2e/auth-filter_test.go
Co-authored-by: Pranshu Srivastava <prasriva@redhat.com>
2025-06-23 14:18:35 +02:00
Manuel Rüger a5789613f1 feat: Add AuthFilter
This adds an Authentication/Authorization filter through Kubernetes'
TokenReview / SubjectAccessReview resources.

The client config for kube-state-metrics needs a clusterrole for

* apiGroups: authentication.k8s.io, resources: tokenreviews, verbs: create
* apiGroups: authorization.k8s.io, resources: subjectaccessreviews, verbs: create

The Prometheus client needs a clusterrole for

* nonResourceURLs: "/metrics", verbs: get
2025-06-23 14:17:52 +02:00
Kubernetes Prow Robot 15e6171c37
Merge pull request #2691 from kubernetes/dependabot/go_modules/github.com/prometheus/common-0.65.0
build(deps): Bump github.com/prometheus/common from 0.64.0 to 0.65.0
2025-06-23 04:50:54 -07:00
dependabot[bot] 873c140040
build(deps): Bump github.com/prometheus/common from 0.64.0 to 0.65.0
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.64.0 to 0.65.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.64.0...v0.65.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-version: 0.65.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 10:30:43 +00:00
Kubernetes Prow Robot 5c130dadad
Merge pull request #2689 from mrueg/k8s-1.32.6
chore: Bump to k8s 1.32.6
2025-06-23 02:26:59 -07:00
Manuel Rüger 2258ba71e8 chore: Bump to k8s 1.32.6 2025-06-19 21:04:03 +02:00
Kubernetes Prow Robot 55d2a7cfac
Merge pull request #2672 from rexagod/sync-caches
fix: Clean up CR reflectors after parent CRD deletion
2025-06-19 09:26:54 -07:00
Kubernetes Prow Robot 97bfa326ab
Merge pull request #2687 from mrueg/makefile-fix-typo
fix: Fix typo in Makefile
2025-06-19 00:48:52 -07:00
Pranshu Srivastava ea6b123caf
fix: close reflectors once their corresponding CRDs are dropped
Signed-off-by: Pranshu Srivastava <rexagod@gmail.com>
2025-06-19 03:07:45 +05:30
Manuel Rüger b9068888d0 Makefile: Fix typo 2025-06-18 22:22:55 +02:00
Kubernetes Prow Robot dbf6e9b4e2
Merge pull request #2677 from mrueg/bump-kind
chore: Bump kind
2025-06-17 06:30:59 -07:00
Kubernetes Prow Robot d84b10a125
Merge pull request #2626 from mrueg/limit-list
feat: Introduce object limits
2025-06-17 06:29:00 -07:00
Kubernetes Prow Robot 775e4586ad
Merge pull request #2683 from kubernetes/dependabot/go_modules/github.com/KimMachineGun/automemlimit-0.7.3
build(deps): Bump github.com/KimMachineGun/automemlimit from 0.7.2 to 0.7.3
2025-06-15 11:52:57 -07:00
dependabot[bot] bea09e59f0
build(deps): Bump github.com/KimMachineGun/automemlimit
Bumps [github.com/KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit) from 0.7.2 to 0.7.3.
- [Release notes](https://github.com/KimMachineGun/automemlimit/releases)
- [Commits](https://github.com/KimMachineGun/automemlimit/compare/v0.7.2...v0.7.3)

---
updated-dependencies:
- dependency-name: github.com/KimMachineGun/automemlimit
  dependency-version: 0.7.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-15 18:44:43 +00:00
Manuel Rüger 4519b2848b feat: Introduce object limits
This change allows user-controlled limits on how many objects KSM will
list from the API. This is helpful to prevent resource exhaustion on
KSM, in case the API creates too many resources.

The object limit it set globally and applied per resource watched.
2025-05-31 23:29:41 +02:00
Manuel Rüger 99224f2c29 chore: Bump kind 2025-05-31 22:16:44 +02:00
Kubernetes Prow Robot 84e2d8fe69
Merge pull request #2670 from rexagod/add-pathtype-to-ingress-path
feat: add `pathType` to `ingress_path`
2025-05-31 11:44:12 -07:00
Kubernetes Prow Robot 6beab20acd
Merge pull request #2676 from kubernetes/dependabot/go_modules/github.com/go-logr/logr-1.4.3
build(deps): Bump github.com/go-logr/logr from 1.4.2 to 1.4.3
2025-05-31 11:34:11 -07:00
dependabot[bot] bb2ad9d2ea
build(deps): Bump github.com/go-logr/logr from 1.4.2 to 1.4.3
Bumps [github.com/go-logr/logr](https://github.com/go-logr/logr) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/go-logr/logr/releases)
- [Changelog](https://github.com/go-logr/logr/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-logr/logr/compare/v1.4.2...v1.4.3)

---
updated-dependencies:
- dependency-name: github.com/go-logr/logr
  dependency-version: 1.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-31 18:24:54 +00:00
Kubernetes Prow Robot 28bf0e817d
Merge pull request #2644 from carlosmorenokm1/fix-pod-status-reason
fix: report correct reason in kube_pod_status_reason metric
2025-05-25 21:02:36 -07:00
Kubernetes Prow Robot 1018969872
Merge pull request #2673 from kubernetes/dependabot/go_modules/github.com/prometheus/common-0.64.0
build(deps): Bump github.com/prometheus/common from 0.63.0 to 0.64.0
2025-05-18 14:15:14 -07:00
dependabot[bot] 043b59ab08
build(deps): Bump github.com/prometheus/common from 0.63.0 to 0.64.0
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.63.0 to 0.64.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.63.0...v0.64.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-version: 0.64.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-18 21:06:57 +00:00
Kubernetes Prow Robot 8ec1fb3c15
Merge pull request #2669 from kubernetes/dependabot/github_actions/actions/setup-go-5.5.0
build(deps): Bump actions/setup-go from 5.4.0 to 5.5.0
2025-05-12 03:27:15 -07:00
Pranshu Srivastava e178d8e582
enhancement: add `pathType` to `ingress_path`
This avoids duplicate metrics (and thus, `PrometheusDuplicateTimestamps`) for schemas such as:
```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - backend:
          service:
            name: cart
            port:
              number: 3000
        path: /nvc/cart
        pathType: Prefix
      - backend:
          service:
            name: cart
            port:
              number: 3000
        path: /nvc/cart
        pathType: Exact
```

Signed-off-by: Pranshu Srivastava <rexagod@gmail.com>
2025-05-12 15:34:00 +05:30
dependabot[bot] 20af6bac6d
build(deps): Bump actions/setup-go from 5.4.0 to 5.5.0
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](0aaccfd150...d35c59abb0)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 5.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-12 09:41:04 +00:00
Kubernetes Prow Robot 9ea1495953
Merge pull request #2656 from mrueg/port-away-gopkg.yamlv3
chore: Port away from gopkg.in/yaml.v3
2025-05-07 09:21:24 -07:00
Kubernetes Prow Robot 090535fcd2
Merge pull request #2667 from kubernetes/dependabot/go_modules/github.com/KimMachineGun/automemlimit-0.7.2
build(deps): Bump github.com/KimMachineGun/automemlimit from 0.7.1 to 0.7.2
2025-05-05 02:43:58 -07:00
dependabot[bot] d45250dec2
build(deps): Bump github.com/KimMachineGun/automemlimit
Bumps [github.com/KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit) from 0.7.1 to 0.7.2.
- [Release notes](https://github.com/KimMachineGun/automemlimit/releases)
- [Commits](https://github.com/KimMachineGun/automemlimit/compare/v0.7.1...v0.7.2)

---
updated-dependencies:
- dependency-name: github.com/KimMachineGun/automemlimit
  dependency-version: 0.7.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 09:36:26 +00:00
Manuel Rüger 3b21633bee chore: Port away from gopkg.in/yaml.v3
This is deprecated by upstream and we can use sigs.k8s.io/yaml now.

Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2025-04-22 10:58:08 +02:00
Kubernetes Prow Robot 0b01e3abce
Merge pull request #2654 from kubernetes/dependabot/github_actions/kubernetes-sigs/release-actions-0.3.1
build(deps): Bump kubernetes-sigs/release-actions from 0.3.0 to 0.3.1
2025-04-21 03:29:00 -07:00
dependabot[bot] 012b785665
build(deps): Bump kubernetes-sigs/release-actions from 0.3.0 to 0.3.1
Bumps [kubernetes-sigs/release-actions](https://github.com/kubernetes-sigs/release-actions) from 0.3.0 to 0.3.1.
- [Release notes](https://github.com/kubernetes-sigs/release-actions/releases)
- [Changelog](https://github.com/kubernetes-sigs/release-actions/blob/main/RELEASE.md)
- [Commits](a69972745f...a30d93cf2a)

---
updated-dependencies:
- dependency-name: kubernetes-sigs/release-actions
  dependency-version: 0.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-21 10:08:57 +00:00
Kubernetes Prow Robot 209f3ab5fa
Merge pull request #2652 from kubernetes/dependabot/go_modules/github.com/prometheus/client_model-0.6.2
build(deps): Bump github.com/prometheus/client_model from 0.6.1 to 0.6.2
2025-04-12 16:54:41 -07:00
Kubernetes Prow Robot d060e4f32c
Merge pull request #2639 from kubernetes/dependabot/go_modules/github.com/spf13/viper-1.20.1
build(deps): Bump github.com/spf13/viper from 1.20.0 to 1.20.1
2025-04-12 16:52:41 -07:00
dependabot[bot] aab32a9e1a
build(deps): Bump github.com/spf13/viper from 1.20.0 to 1.20.1
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.20.0 to 1.20.1.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.20.0...v1.20.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-12 23:44:47 +00:00
dependabot[bot] e204ab31cb
build(deps): Bump github.com/prometheus/client_model from 0.6.1 to 0.6.2
Bumps [github.com/prometheus/client_model](https://github.com/prometheus/client_model) from 0.6.1 to 0.6.2.
- [Release notes](https://github.com/prometheus/client_model/releases)
- [Commits](https://github.com/prometheus/client_model/compare/v0.6.1...v0.6.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_model
  dependency-version: 0.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-12 23:44:02 +00:00
Kubernetes Prow Robot 38e2fa6e53
Merge pull request #2650 from dgrisonnet/catherine-approver
chore: add CatherineF-dev as an approver
2025-04-10 11:24:51 -07:00
Damien Grisonnet f6e2b5fbda chore: add CatherineF-dev as an approver
Signed-off-by: Damien Grisonnet <dgrisonn@redhat.com>
2025-04-10 19:04:43 +02:00
Kubernetes Prow Robot 3aee5ff2bb
Merge pull request #2648 from kubernetes/dependabot/go_modules/github.com/prometheus/client_golang-1.22.0
build(deps): Bump github.com/prometheus/client_golang from 1.21.1 to 1.22.0
2025-04-09 04:34:39 -07:00
dependabot[bot] 55e124f509
build(deps): Bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.1 to 1.22.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.21.1...v1.22.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-08 08:19:21 +00:00
Kubernetes Prow Robot f0f9898fa1
Merge pull request #2643 from mrueg/golangci-v2
chore: Migrate to golangci-lint v2
2025-04-07 22:18:39 -07:00
Kubernetes Prow Robot a0d9835e78
Merge pull request #2647 from kubernetes/dependabot/go_modules/github.com/fsnotify/fsnotify-1.9.0
build(deps): Bump github.com/fsnotify/fsnotify from 1.8.0 to 1.9.0
2025-04-07 05:40:38 -07:00
dependabot[bot] a09d690396
build(deps): Bump github.com/fsnotify/fsnotify from 1.8.0 to 1.9.0
Bumps [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify) from 1.8.0 to 1.9.0.
- [Release notes](https://github.com/fsnotify/fsnotify/releases)
- [Changelog](https://github.com/fsnotify/fsnotify/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fsnotify/fsnotify/compare/v1.8.0...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/fsnotify/fsnotify
  dependency-version: 1.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 10:22:23 +00:00
Carlos Moreno 05187b47e2 fix: report correct values in kube_pod_status_reason metric (added tests) 2025-04-01 18:32:26 -05:00
Carlos Moreno 518db3d3cd fix: report correct values in kube_pod_status_reason metric 2025-03-31 23:01:45 -05:00
Manuel Rüger 0c029b690e chore: Migrate to golangci-lint v2 2025-03-31 14:52:47 +02:00
Kubernetes Prow Robot ffd8f41131
Merge pull request #2641 from ricardbejarano/main
fix: bump golang.org/x/net to v0.38.0 (fixes CVE-2025-22870 & CVE-2025-22872)
2025-03-31 04:22:40 -07:00
Ricard Bejarano 4f62f0fde4
go mod tidy
Signed-off-by: Ricard Bejarano <ricard@bejarano.io>
2025-03-31 11:38:34 +02:00
Ricard Bejarano 1c923dc83b
fix: bump golang.org/x/net to v0.38.0 (fixes CVE-2025-22872) 2025-03-30 11:49:41 +02:00
Ricard Bejarano a6ff8ae41c
fix: bump golang.org/x/net to v0.36.0 (fixes CVE-2025-22870) 2025-03-29 10:17:12 +01:00
Kubernetes Prow Robot b528c28f7e
Merge pull request #2634 from kubernetes/dependabot/github_actions/actions/setup-go-5.4.0
build(deps): Bump actions/setup-go from 5.3.0 to 5.4.0
2025-03-24 03:00:34 -07:00
dependabot[bot] bc2a57140c
build(deps): Bump actions/setup-go from 5.3.0 to 5.4.0
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.3.0 to 5.4.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](f111f3307d...0aaccfd150)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 09:52:08 +00:00
Kubernetes Prow Robot 5f116914f1
Merge pull request #2616 from rexagod/2594
feat: Use `dlclark/regexp2` over standard library's package
2025-03-19 01:10:31 -07:00
Pranshu Srivastava 8b631bbff4
feat: Use `dlclark/regexp2` over standard library's package
Signed-off-by: Pranshu Srivastava <rexagod@gmail.com>
2025-03-18 18:57:25 +05:30
Kubernetes Prow Robot bc60722ddd
Merge pull request #2630 from kubernetes/dependabot/go_modules/github.com/prometheus/common-0.63.0
build(deps): Bump github.com/prometheus/common from 0.62.0 to 0.63.0
2025-03-17 18:07:49 -07:00
Kubernetes Prow Robot 456ac8f2e8
Merge pull request #2629 from kubernetes/dependabot/go_modules/github.com/spf13/viper-1.20.0
build(deps): Bump github.com/spf13/viper from 1.19.0 to 1.20.0
2025-03-17 18:05:49 -07:00
dependabot[bot] aa6e88c2d5
build(deps): Bump github.com/spf13/viper from 1.19.0 to 1.20.0
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.19.0 to 1.20.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.19.0...v1.20.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 00:51:07 +00:00
dependabot[bot] b3d26f7a9f
build(deps): Bump github.com/prometheus/common from 0.62.0 to 0.63.0
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.62.0 to 0.63.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.62.0...v0.63.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 00:51:05 +00:00
Kubernetes Prow Robot 40602cb3e3
Merge pull request #2611 from mrueg/go-1.24
chore: Bump to go-1.24, use go tools
2025-03-17 17:49:49 -07:00
Manuel Rüger a3972f90ab chore: Bump to go-1.24, use go tools 2025-03-16 21:41:32 +01:00
Kubernetes Prow Robot dab65d7cb4
Merge pull request #2628 from kubernetes/dependabot/go_modules/k8s-dependencies-8005f85eb9
build(deps): Bump the k8s-dependencies group with 5 updates
2025-03-12 02:01:46 -07:00
dependabot[bot] 05e45869ff
build(deps): Bump the k8s-dependencies group with 5 updates
Bumps the k8s-dependencies group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.32.2` | `0.32.3` |
| [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.32.2` | `0.32.3` |
| [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.32.2` | `0.32.3` |
| [k8s.io/component-base](https://github.com/kubernetes/component-base) | `0.32.2` | `0.32.3` |
| [k8s.io/sample-controller](https://github.com/kubernetes/sample-controller) | `0.32.2` | `0.32.3` |


Updates `k8s.io/api` from 0.32.2 to 0.32.3
- [Commits](https://github.com/kubernetes/api/compare/v0.32.2...v0.32.3)

Updates `k8s.io/apimachinery` from 0.32.2 to 0.32.3
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.32.2...v0.32.3)

Updates `k8s.io/client-go` from 0.32.2 to 0.32.3
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.32.2...v0.32.3)

Updates `k8s.io/component-base` from 0.32.2 to 0.32.3
- [Commits](https://github.com/kubernetes/component-base/compare/v0.32.2...v0.32.3)

Updates `k8s.io/sample-controller` from 0.32.2 to 0.32.3
- [Commits](https://github.com/kubernetes/sample-controller/compare/v0.32.2...v0.32.3)

---
updated-dependencies:
- dependency-name: k8s.io/api
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/component-base
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/sample-controller
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-12 08:40:29 +00:00
Kubernetes Prow Robot 3d73ddbd09
Merge pull request #2624 from kubernetes/dependabot/go_modules/github.com/prometheus/client_golang-1.21.1
build(deps): Bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1
2025-03-06 14:19:44 -08:00
dependabot[bot] 5906b6dc9e
build(deps): Bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.0 to 1.21.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.21.0...v1.21.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-06 22:10:30 +00:00
Kubernetes Prow Robot c853e41fee
Merge pull request #2618 from kubernetes/dependabot/go_modules/github.com/google/go-cmp-0.7.0
build(deps): Bump github.com/google/go-cmp from 0.6.0 to 0.7.0
2025-02-24 01:08:29 -08:00
Kubernetes Prow Robot 2c423907a3
Merge pull request #2617 from kubernetes/dependabot/go_modules/github.com/KimMachineGun/automemlimit-0.7.1
build(deps): Bump github.com/KimMachineGun/automemlimit from 0.7.0 to 0.7.1
2025-02-24 01:06:29 -08:00
dependabot[bot] 0129759430
build(deps): Bump github.com/google/go-cmp from 0.6.0 to 0.7.0
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: github.com/google/go-cmp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 08:57:49 +00:00
dependabot[bot] c405dcf1f3
build(deps): Bump github.com/KimMachineGun/automemlimit
Bumps [github.com/KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit) from 0.7.0 to 0.7.1.
- [Release notes](https://github.com/KimMachineGun/automemlimit/releases)
- [Commits](https://github.com/KimMachineGun/automemlimit/compare/v0.7.0...v0.7.1)

---
updated-dependencies:
- dependency-name: github.com/KimMachineGun/automemlimit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 08:57:44 +00:00
Kubernetes Prow Robot 7f9b0d1189
Merge pull request #2615 from SuperQ/superq/reclaim
feat: Add PersistentVolume Reclaim Policy into info metric
2025-02-22 13:56:26 -08:00
SuperQ a775fe3458
feat: Add PersistentVolume Reclaim Policy metric
In order to monitor for PVs with different reclaim policies add a
`reclaim_policy` label to the `kube_persistentvolume_info` metric.

Signed-off-by: SuperQ <superq@gmail.com>
2025-02-20 10:37:13 +01:00
Kubernetes Prow Robot 3527ceb4d5
Merge pull request #2613 from kubernetes/dependabot/go_modules/github.com/prometheus/client_golang-1.21.0
build(deps): Bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0
2025-02-19 03:42:26 -08:00
dependabot[bot] 9ce7e6b771
build(deps): Bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.5 to 1.21.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/v1.21.0/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.5...v1.21.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-19 11:13:44 +00:00
Kubernetes Prow Robot cd49aeac35
Merge pull request #2610 from kubernetes/dependabot/go_modules/github.com/spf13/cobra-1.9.1
build(deps): Bump github.com/spf13/cobra from 1.8.1 to 1.9.1
2025-02-17 04:40:22 -08:00
dependabot[bot] 16db8b7368
build(deps): Bump github.com/spf13/cobra from 1.8.1 to 1.9.1
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.1 to 1.9.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.1...v1.9.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 09:34:11 +00:00
Kubernetes Prow Robot 350a7c472e
Merge pull request #2609 from kubernetes/dependabot/go_modules/k8s-dependencies-648f52ad64
build(deps): Bump the k8s-dependencies group with 5 updates
2025-02-15 00:32:20 -08:00
dependabot[bot] 919ce06ec7
build(deps): Bump the k8s-dependencies group with 5 updates
Bumps the k8s-dependencies group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [k8s.io/api](https://github.com/kubernetes/api) | `0.32.1` | `0.32.2` |
| [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.32.1` | `0.32.2` |
| [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.32.1` | `0.32.2` |
| [k8s.io/component-base](https://github.com/kubernetes/component-base) | `0.32.1` | `0.32.2` |
| [k8s.io/sample-controller](https://github.com/kubernetes/sample-controller) | `0.32.1` | `0.32.2` |


Updates `k8s.io/api` from 0.32.1 to 0.32.2
- [Commits](https://github.com/kubernetes/api/compare/v0.32.1...v0.32.2)

Updates `k8s.io/apimachinery` from 0.32.1 to 0.32.2
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.32.1...v0.32.2)

Updates `k8s.io/client-go` from 0.32.1 to 0.32.2
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.32.1...v0.32.2)

Updates `k8s.io/component-base` from 0.32.1 to 0.32.2
- [Commits](https://github.com/kubernetes/component-base/compare/v0.32.1...v0.32.2)

Updates `k8s.io/sample-controller` from 0.32.1 to 0.32.2
- [Commits](https://github.com/kubernetes/sample-controller/compare/v0.32.1...v0.32.2)

---
updated-dependencies:
- dependency-name: k8s.io/api
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/component-base
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/sample-controller
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-15 08:17:23 +00:00
Kubernetes Prow Robot 2a95d4649b
Merge pull request #2606 from kubernetes/dependabot/go_modules/github.com/prometheus/exporter-toolkit-0.14.0
build(deps): Bump github.com/prometheus/exporter-toolkit from 0.13.2 to 0.14.0
2025-02-06 12:17:56 -08:00
dependabot[bot] dc60c09548
build(deps): Bump github.com/prometheus/exporter-toolkit
Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.2 to 0.14.0.
- [Release notes](https://github.com/prometheus/exporter-toolkit/releases)
- [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.2...v0.14.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/exporter-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-06 20:09:02 +00:00
Kubernetes Prow Robot 4fa35209c1
Merge pull request #2600 from kubernetes/release-2.15
chore: Merge release 2.15 back to main
2025-02-03 22:14:58 -08:00
104 changed files with 2410 additions and 2293 deletions

View File

@ -9,10 +9,10 @@ assignees: ''
<!-- Please only use this template for submitting feature requests -->
**What would you like to be added**:
**What would you like to be added:**
**Why is this needed**:
**Why is this needed:**
**Describe the solution you'd like**
**Describe the solution you'd like:**
**Additional context**
**Additional context:**

View File

@ -5,9 +5,10 @@
4. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->
**What this PR does / why we need it**:
<!-- markdownlint-disable-next-line MD041 -->
**What this PR does / why we need it:**
**How does this change affect the cardinality of KSM**: *(increases, decreases or does not change cardinality)*
**How does this change affect the cardinality of KSM:** *(increases, decreases or does not change cardinality)*
**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
**Which issue(s) this PR fixes:** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*
Fixes #

View File

@ -8,10 +8,6 @@ updates:
- "k8s.io*"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "tools"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:

View File

@ -20,8 +20,8 @@ env:
E2E_SETUP_KIND: yes
E2E_SETUP_KUBECTL: yes
SUDO: sudo
GO_VERSION: "^1.23"
GOLANGCI_LINT_VERSION: "v1.61.0"
GO_VERSION: "^1.24"
GOLANGCI_LINT_VERSION: "v2.0.2"
jobs:
ci-go-lint:
@ -29,18 +29,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
id: go
- name: Setup environment
run: |
make install-tools
- name: Lint
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${{ env.GOLANGCI_LINT_VERSION }}
@ -51,18 +47,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
id: go
- name: Setup environment
run: |
make install-tools
- name: Validate generated manifests
run: |
make validate-manifests
@ -72,18 +64,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
id: go
- name: Setup environment
run: |
make install-tools
- name: Validate go modules
run: |
make validate-modules
@ -93,18 +81,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
id: go
- name: Setup environment
run: |
make install-tools
- name: Check that all metrics are documented and templates have no delta
run: |
make doccheck
@ -114,18 +98,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
id: go
- name: Setup environment
run: |
make install-tools
- name: Unit tests
run: |
make test-unit
@ -135,7 +115,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup promtool
run: |
@ -150,18 +130,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
id: go
- name: Setup environment
run: |
make install-tools
- name: Benchmark tests
run: |
BENCHSTAT_OUTPUT_FILE=result.txt make test-benchmark-compare
@ -181,18 +157,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
id: go
- name: Setup environment
run: |
make install-tools
- name: Build
run: |
make build
@ -202,18 +174,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
id: go
- name: Setup environment
run: |
make install-tools
- name: End-to-end tests
run: |
make e2e

View File

@ -6,7 +6,7 @@ on:
- cron: '0 0 * * 1'
env:
GO_VERSION: "^1.23"
GO_VERSION: "^1.24"
permissions:
contents: read
@ -15,10 +15,10 @@ jobs:
ci-security-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
name: Checkout code
- name: Set up Go 1.x
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Install govulncheck binary

View File

@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set environment variables
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV

View File

@ -21,10 +21,10 @@ jobs:
steps:
- name: Fetch source code into GITHUB_WORKSPACE
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install Kubernetes BOM
uses: kubernetes-sigs/release-actions/setup-bom@a69972745f85aab4ba5d6c681e2a0e7f73eaff2b # v0.3.0
uses: kubernetes-sigs/release-actions/setup-bom@a30d93cf2aa029e1e4c8a6c79f766aebf429fddb # v0.3.1
- name: Generate SBOM
run: |

View File

@ -1,15 +1,10 @@
run:
timeout: 10m
version: "2"
linters:
disable-all: true
default: none
enable:
- gocritic
- gocyclo
- gofmt
- goimports
- gosec
- gosimple
- govet
- ineffassign
- misspell
@ -18,22 +13,48 @@ linters:
- staticcheck
- unconvert
- unused
exclusions:
generated: lax
rules:
- linters:
- promlinter
path: _test\.go
- linters:
- gosec
text: 'G104:'
- linters:
- revive
text: 'package-comments:|var-naming:'
# This needs to stay as long as we support exposing v1.endpoints metrics
- linters:
- staticcheck
text: 'SA1019: v1.Endpoint'
path: 'internal/store/endpoint.*.go|internal/store/builder.go'
# TODO: Use functions with context https://github.com/kubernetes/kube-state-metrics/issues/2721
- linters:
- staticcheck
text: 'SA1019: .*List|Watch'
path: 'pkg/sharding/listwatch.go|pkg/watch/watch.go'
linters-settings:
goimports:
local-prefixes: k8s.io/kube-state-metrics,k8s.io/kube-state-metrics/v2
paths:
- third_party$
- builtin$
- examples$
issues:
exclude-use-default: false
exclude-rules:
# We don't check metrics naming in the tests.
- path: _test\.go
linters:
- promlinter
# TODO(mrueg) Improve error handling
- text: "G104:"
linters:
- gosec
- text: "package-comments:"
linters:
- revive
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofmt
- goimports
settings:
goimports:
local-prefixes:
- k8s.io/kube-state-metrics
- k8s.io/kube-state-metrics/v2
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View File

@ -8,10 +8,12 @@
"style": "asterisk"
},
"MD013": false, // https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md#md013---line-length
"MD024": false, // https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md#md024---multiple-headers-with-the-same-content
"MD033": false, // https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md#md033---inline-html
"MD036": false, // https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md#md036---emphasis-used-instead-of-a-header
"MD040": false, // https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md#md040---fenced-code-blocks-should-have-a-language-specified
"MD041": false // https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md#md041---first-line-in-file-should-be-a-top-level-header
"MD033": {
"allowed_elements": [
"details",
"summary",
"br"
]
}
}
}

View File

@ -9,7 +9,7 @@ To add new statements to publish data about a vulnerability,
download [vexctl](https://github.com/openvex/vexctl)
and append new statements using `vexctl add`. For example:
```
```bash
vexctl add --in-place main.openvex.json pkg:oci/test CVE-2014-1234567 fixed
```

View File

@ -1,6 +1,23 @@
# Changelog
## v2.16.0 / 2025-06-23
**Note:**
* This release builds with Golang `v1.24.4`
* This release builds with `k8s.io/client-go`: `v0.32.6`
* [FEATURE] Add a `reclaim_policy` label to the `kube_persistentvolume_info` metric by @SuperQ in <https://github.com/kubernetes/kube-state-metrics/pull/2615>
* [FEATURE] Use dlclark/regexp2 over standard library's package to support lookarounds by @rexagod in <https://github.com/kubernetes/kube-state-metrics/pull/2616>
* [BUGFIX] Report correct values in `kube_pod_status_reason` metric by @carlosmorenokm1 in <https://github.com/kubernetes/kube-state-metrics/pull/2644>
* [FEATURE] Add add `pathType` to `kube_ingress_path` by @rexagod in <https://github.com/kubernetes/kube-state-metrics/pull/2670>
* [FEATURE] Introduce object limits by @mrueg in <https://github.com/kubernetes/kube-state-metrics/pull/2626>
* [BUGFIX] Close reflectors once their corresponding CRDs are dropped by @rexagod in <https://github.com/kubernetes/kube-state-metrics/pull/2672>
* [FEATURE] Incorporate `WithAuthenticationAndAuthorization` to support endpoint authn/z by @mrueg in <https://github.com/kubernetes/kube-state-metrics/pull/2686>
## v2.15.0 / 2025-02-03
## Note
**Note:**
* This release builds with Golang `v1.23.5`
* This release builds with `k8s.io/client-go`: `v0.32.1`
@ -16,7 +33,7 @@
## v2.14.0 / 2024-11-08
### Note
**Note:**
* This release builds with Golang `v1.23.3`
* This release builds with `k8s.io/client-go`: `v0.31.2`
@ -39,7 +56,7 @@
## v2.13.0 / 2024-07-18
### Note
**Note:**
* This release builds with Golang `v1.22.5`.
* This release builds with `k8s.io/client-go`: `v0.30.3`.
@ -54,7 +71,7 @@
## v2.12.0 / 2024-04-02
### Note
**Note:**
* This release addresses a critical issue where scraping the exposition data for certain types caused metrics-backends to crash: <https://github.com/kubernetes/kube-state-metrics/issues/2248>.
* This release builds with `k8s.io/client-go`: `v0.29.3`.
@ -65,7 +82,7 @@
## v2.11.0 / 2024-03-04
### Note
**Note:**
This release builds with Golang `v1.21.8`.
@ -82,7 +99,7 @@ This release builds with Golang `v1.21.8`.
## v2.10.1 / 2023-10-09
### Note
**Note:**
* This release addresses a regression introduced in [#2105](https://github.com/kubernetes/kube-state-metrics/pull/2105).
@ -91,7 +108,7 @@ This release builds with Golang `v1.21.8`.
## v2.10.0 / 2023-08-31
### Note
**Note:**
* Label and annotation metrics aren't exposed by default anymore to reduce the memory usage of the default configuration of kube-state-metrics. Before this change, they used to only include the name and namespace of the objects which is not relevant to users not opting in these metrics.
@ -124,7 +141,7 @@ This release does not incorporate any user-facing changes. Re-running release pr
The changes mentioned below are only the user-facing ones. For a list of the complete set of changes, refer the changelog associated with the release tag.
### Note
**Note:**
* The deprecated experimental VerticalPodAutoscaler metrics are no longer supported, and have been removed. We recommend to use CustomResourceState metrics to gather metrics from custom resources like the Vertical Pod Autoscaler.
* #2004 regulated label names to adhere with [OTel-Prometheus standards](https://github.com/open-telemetry/opentelemetry-specification/blob/8946dfc6a2302f78b0224fcc3f4dfb816a7bb1f4/specification/compatibility/prometheus_and_openmetrics.md?plain=1#L224-L229), so existing label names that do not follow the same may be replaced by the ones that do. Please refer to the PR for more details.

View File

@ -1,4 +1,4 @@
ARG GOVERSION=1.23
ARG GOVERSION=1.24
ARG GOARCH
FROM golang:${GOVERSION} AS builder
ARG GOARCH
@ -6,7 +6,7 @@ ENV GOARCH=${GOARCH}
WORKDIR /go/src/k8s.io/kube-state-metrics/
COPY . /go/src/k8s.io/kube-state-metrics/
RUN make install-tools && make build-local
RUN make build-local
FROM gcr.io/distroless/static-debian12:latest-${GOARCH}
COPY --from=builder /go/src/k8s.io/kube-state-metrics/kube-state-metrics /

View File

@ -2,7 +2,7 @@
kube-state-metrics is welcoming contributions from the community. If you are interested in intensifying your contributions and becoming a maintainer, this doc describes the necessary steps.
As part of the Kubernetes project, we use the community membership process as described [here](https://github.com/kubernetes/community/blob/master/community-membership.md). We do not adhere strictly to the numbers of contributions and reviews. Still as becoming a maintainer is a trust-based process and we desire positive outcomes for the project, we look for a long-term interest and engagement.
As part of the Kubernetes project, we rely on the [community membership process](https://github.com/kubernetes/community/blob/master/community-membership.md). We do not adhere strictly to the numbers of contributions and reviews. Still as becoming a maintainer is a trust-based process and we desire positive outcomes for the project, we look for a long-term interest and engagement.
## Adding a new reviewer

View File

@ -6,8 +6,6 @@ VERSION = $(shell grep '^version:' data.yaml | grep -oE "[0-9]+.[0-9]+.[0-9]+")
TAG ?= $(TAG_PREFIX)$(VERSION)
LATEST_RELEASE_BRANCH := release-$(shell echo $(VERSION) | grep -ohE "[0-9]+.[0-9]+")
BRANCH = $(strip $(shell git rev-parse --abbrev-ref HEAD))
DOCKER_CLI ?= docker
PROMTOOL_CLI ?= promtool
PKGS = $(shell go list ./... | grep -v /vendor/ | grep -v /tests/e2e)
ARCH ?= $(shell go env GOARCH)
BUILD_DATE = $(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
@ -15,14 +13,21 @@ GIT_COMMIT ?= $(shell git rev-parse --short HEAD)
OS ?= $(shell uname -s | tr A-Z a-z)
ALL_ARCH = amd64 arm arm64 ppc64le s390x
PKG = github.com/prometheus/common
PROMETHEUS_VERSION = 2.55.1
GO_VERSION = 1.23.5
PROMETHEUS_VERSION = 3.4.1
GO_VERSION = 1.24.4
IMAGE = $(REGISTRY)/kube-state-metrics
MULTI_ARCH_IMG = $(IMAGE)-$(ARCH)
USER ?= $(shell id -u -n)
HOST ?= $(shell hostname)
MARKDOWNLINT_CLI2_VERSION = 0.17.2
MARKDOWNLINT_CLI2_VERSION = 0.18.1
DOCKER_CLI ?= docker
PROMTOOL_CLI ?= promtool
GOMPLATE_CLI ?= go tool github.com/hairyhenderson/gomplate/v4/cmd/gomplate
GOJSONTOYAML_CLI ?= go tool github.com/brancz/gojsontoyaml
EMBEDMD_CLI ?= go tool github.com/campoy/embedmd
JSONNET_CLI ?= go tool github.com/google/go-jsonnet/cmd/jsonnet
JB_CLI ?= go tool github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb
export DOCKER_CLI_EXPERIMENTAL=enabled
@ -88,7 +93,7 @@ fix-markdown-format:
${DOCKER_CLI} run -v "${PWD}:/workdir" davidanson/markdownlint-cli2:v${MARKDOWNLINT_CLI2_VERSION} --fix --config .markdownlint-cli2.jsonc
generate-template:
gomplate -d config=./data.yaml --file README.md.tpl > README.md
${GOMPLATE_CLI} -d config=./data.yaml --file README.md.tpl > README.md
validate-template: generate-template
git diff --no-ext-diff --quiet --exit-code README.md
@ -138,7 +143,7 @@ e2e:
generate: build-local generate-template
@echo ">> generating docs"
@./scripts/generate-help-text.sh
embedmd -w `find . -path ./vendor -prune -o -name "*.md" -print`
${EMBEDMD_CLI} -w `find . -path ./vendor -prune -o -name "*.md" -print`
validate-manifests: examples
@git diff --exit-code
@ -147,31 +152,27 @@ mixin: examples/prometheus-alerting-rules/alerts.yaml
examples/prometheus-alerting-rules/alerts.yaml: jsonnet $(shell find jsonnet | grep ".libsonnet") scripts/mixin.jsonnet scripts/vendor
mkdir -p examples/prometheus-alerting-rules
jsonnet -J scripts/vendor scripts/mixin.jsonnet | gojsontoyaml > examples/prometheus-alerting-rules/alerts.yaml
${JSONNET_CLI} -J scripts/vendor scripts/mixin.jsonnet | ${GOJSONTOYAML_CLI} > examples/prometheus-alerting-rules/alerts.yaml
examples: examples/standard examples/autosharding examples/daemonsetsharding mixin
examples/standard: jsonnet $(shell find jsonnet | grep ".libsonnet") scripts/standard.jsonnet scripts/vendor
mkdir -p examples/standard
jsonnet -J scripts/vendor -m examples/standard --ext-str version="$(VERSION)" scripts/standard.jsonnet | xargs -I{} sh -c 'cat {} | gojsontoyaml > `echo {} | sed "s/\(.\)\([A-Z]\)/\1-\2/g" | tr "[:upper:]" "[:lower:]"`.yaml' -- {}
${JSONNET_CLI} -J scripts/vendor -m examples/standard --ext-str version="$(VERSION)" scripts/standard.jsonnet | xargs -I{} sh -c 'cat {} | ${GOJSONTOYAML_CLI} > `echo {} | sed "s/\(.\)\([A-Z]\)/\1-\2/g" | tr "[:upper:]" "[:lower:]"`.yaml' -- {}
find examples -type f ! -name '*.yaml' -delete
examples/autosharding: jsonnet $(shell find jsonnet | grep ".libsonnet") scripts/autosharding.jsonnet scripts/vendor
mkdir -p examples/autosharding
jsonnet -J scripts/vendor -m examples/autosharding --ext-str version="$(VERSION)" scripts/autosharding.jsonnet | xargs -I{} sh -c 'cat {} | gojsontoyaml > `echo {} | sed "s/\(.\)\([A-Z]\)/\1-\2/g" | tr "[:upper:]" "[:lower:]"`.yaml' -- {}
${JSONNET_CLI} -J scripts/vendor -m examples/autosharding --ext-str version="$(VERSION)" scripts/autosharding.jsonnet | xargs -I{} sh -c 'cat {} | ${GOJSONTOYAML_CLI} > `echo {} | sed "s/\(.\)\([A-Z]\)/\1-\2/g" | tr "[:upper:]" "[:lower:]"`.yaml' -- {}
find examples -type f ! -name '*.yaml' -delete
examples/daemonsetsharding: jsonnet $(shell find jsonnet | grep ".libsonnet") scripts/daemonsetsharding.jsonnet scripts/vendor
mkdir -p examples/daemonsetsharding
jsonnet -J scripts/vendor -m examples/daemonsetsharding --ext-str version="$(VERSION)" scripts/daemonsetsharding.jsonnet | xargs -I{} sh -c 'cat {} | gojsontoyaml > `echo {} | sed "s/\(.\)\([A-Z]\)/\1-\2/g" | tr "[:upper:]" "[:lower:]"`.yaml' -- {}
${JSONNET_CLI} -J scripts/vendor -m examples/daemonsetsharding --ext-str version="$(VERSION)" scripts/daemonsetsharding.jsonnet | xargs -I{} sh -c 'cat {} | ${GOJSONTOYAML_CLI} > `echo {} | sed "s/\(.\)\([A-Z]\)/\1-\2/g" | tr "[:upper:]" "[:lower:]"`.yaml' -- {}
find examples -type f ! -name '*.yaml' -delete
scripts/vendor: scripts/jsonnetfile.json scripts/jsonnetfile.lock.json
cd scripts && jb install
install-tools:
@echo Installing tools from tools.go
grep '^\s*_' tools/tools.go | awk '{print $$2}' | xargs -tI % go install -mod=readonly -modfile=tools/go.mod %
cd scripts && ${JB_CLI} install
install-promtool:
@echo Installing promtool

1
OWNERS
View File

@ -5,6 +5,7 @@ reviewers:
- mrueg
- rexagod
approvers:
- CatherineF-dev
- dgrisonnet
- mrueg
- rexagod

View File

@ -41,6 +41,7 @@ are deleted they are no longer visible on the `/metrics` endpoint.
* [Resource group version compatibility](#resource-group-version-compatibility)
* [Container Image](#container-image)
* [Metrics Documentation](#metrics-documentation)
* [ECMAScript regular expression support for allow and deny lists](#ecmascript-regular-expression-support-for-allow-and-deny-lists)
* [Conflict resolution in label names](#conflict-resolution-in-label-names)
* [Kube-state-metrics self metrics](#kube-state-metrics-self-metrics)
* [Resource recommendation](#resource-recommendation)
@ -67,9 +68,8 @@ are deleted they are no longer visible on the `/metrics` endpoint.
#### Kubernetes Version
kube-state-metrics uses [`client-go`](https://github.com/kubernetes/client-go) to talk with
Kubernetes clusters. The supported Kubernetes cluster version is determined by `client-go`.
The compatibility matrix for client-go and Kubernetes cluster can be found
[here](https://github.com/kubernetes/client-go#compatibility-matrix).
Kubernetes clusters. The supported Kubernetes cluster version is determined by
[`client-go`](https://github.com/kubernetes/client-go#compatibility-matrix).
All additional compatibility is only best effort, or happens to still/already be supported.
#### Compatibility matrix
@ -79,12 +79,12 @@ Generally, it is recommended to use the latest release of kube-state-metrics. If
| kube-state-metrics | Kubernetes client-go Version |
|--------------------|:----------------------------:|
| **v2.11.0** | v1.28 |
| **v2.12.0** | v1.29 |
| **v2.13.0** | v1.30 |
| **v2.14.0** | v1.31 |
| **v2.15.0** | v1.32 |
| **main** | v1.32 |
| **v2.16.0** | v1.32 |
| **main** | v1.33 |
#### Resource group version compatibility
@ -96,8 +96,8 @@ release.
The latest container image can be found at:
* `registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.15.0` (arch: `amd64`, `arm`, `arm64`, `ppc64le` and `s390x`)
* View all multi-architecture images at [here](https://explore.ggcr.dev/?image=registry.k8s.io%2Fkube-state-metrics%2Fkube-state-metrics:v2.15.0)
* `registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.16.0` (arch: `amd64`, `arm`, `arm64`, `ppc64le` and `s390x`)
* [Multi-architecture images](https://explore.ggcr.dev/?image=registry.k8s.io%2Fkube-state-metrics%2Fkube-state-metrics:v2.16.0)
### Metrics Documentation
@ -129,6 +129,10 @@ e.g. by standardizing Kubernetes labels using an
[Admission Webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)
that ensures that there are no possible conflicts.
#### ECMAScript regular expression support for allow and deny lists
Starting from [#2616](https://github.com/kubernetes/kube-state-metrics/pull/2616/files), kube-state-metrics supports ECMAScript's `regexp` for allow and deny lists. This was incorporated as a workaround for the limitations of the `regexp` package in Go, which does not support lookarounds due to their non-linear time complexity. Please note that while lookarounds are now supported for allow and deny lists, regular expressions' evaluation time is capped at a minute to prevent performance issues.
### Kube-state-metrics self metrics
kube-state-metrics exposes its own general process metrics under `--telemetry-host` and `--telemetry-port` (default 8081).
@ -139,7 +143,7 @@ at the logs of kube-state-metrics.
Example of the above mentioned metrics:
```
```prometheus
kube_state_metrics_list_total{resource="*v1.Node",result="success"} 1
kube_state_metrics_list_total{resource="*v1.Node",result="error"} 52
kube_state_metrics_watch_total{resource="*v1beta1.Ingress",result="success"} 1
@ -147,7 +151,7 @@ kube_state_metrics_watch_total{resource="*v1beta1.Ingress",result="success"} 1
kube-state-metrics also exposes some http request metrics, examples of those are:
```
```prometheus
http_request_duration_seconds_bucket{handler="metrics",method="get",le="2.5"} 30
http_request_duration_seconds_bucket{handler="metrics",method="get",le="5"} 30
http_request_duration_seconds_bucket{handler="metrics",method="get",le="10"} 30
@ -158,20 +162,20 @@ http_request_duration_seconds_count{handler="metrics",method="get"} 30
kube-state-metrics also exposes build and configuration metrics:
```
```prometheus
kube_state_metrics_build_info{branch="main",goversion="go1.15.3",revision="6c9d775d",version="v2.0.0-beta"} 1
kube_state_metrics_shard_ordinal{shard_ordinal="0"} 0
kube_state_metrics_total_shards 1
```
`kube_state_metrics_build_info` is used to expose version and other build information. For more usage about the info pattern,
please check the blog post [here](https://www.robustperception.io/exposing-the-software-version-to-prometheus).
please check this [blog post](https://www.robustperception.io/exposing-the-software-version-to-prometheus).
Sharding metrics expose `--shard` and `--total-shards` flags and can be used to validate
run-time configuration, see [`/examples/prometheus-alerting-rules`](./examples/prometheus-alerting-rules).
kube-state-metrics also exposes metrics about it config file and the Custom Resource State config file:
```
```prometheus
kube_state_metrics_config_hash{filename="crs.yml",type="customresourceconfig"} 2.38272279311849e+14
kube_state_metrics_config_hash{filename="config.yml",type="config"} 2.65285922340846e+14
kube_state_metrics_last_config_reload_success_timestamp_seconds{filename="crs.yml",type="customresourceconfig"} 1.6704882592037103e+09
@ -198,7 +202,7 @@ Note that if CPU limits are set too low, kube-state-metrics' internal queues wil
In a 100 node cluster scaling test the latency numbers were as follows:
```
```text
"Perc50": 259615384 ns,
"Perc90": 475000000 ns,
"Perc99": 906666666 ns.
@ -262,7 +266,7 @@ Each kube-state-metrics pod uses FieldSelector (spec.nodeName) to watch/list pod
A daemonset kube-state-metrics example:
```
```yaml
apiVersion: apps/v1
kind: DaemonSet
spec:
@ -284,7 +288,7 @@ spec:
To track metrics for unassigned pods, you need to add an additional deployment and set `--track-unscheduled-pods`, as shown in the following example:
```
```yaml
apiVersion: apps/v1
kind: Deployment
spec:
@ -304,8 +308,8 @@ Other metrics can be sharded via [Horizontal sharding](#horizontal-sharding).
Install this project to your `$GOPATH` using `go get`:
```
go get k8s.io/kube-state-metrics
```bash
go get k8s.io/kube-state-metrics/v2
```
#### Building the Docker container
@ -313,7 +317,7 @@ go get k8s.io/kube-state-metrics
Simply run the following command in this root folder, which will create a
self-contained, statically-linked binary and build a Docker image:
```
```bash
make container
```
@ -336,7 +340,7 @@ To have Prometheus discover kube-state-metrics instances it is advised to create
**Note:** Google Kubernetes Engine (GKE) Users - GKE has strict role permissions that will prevent the kube-state-metrics roles and role bindings from being created. To work around this, you can give your GCP identity the cluster-admin role by running the following one-liner:
```
```bash
kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud info --format='value(config.account)')
```
@ -411,14 +415,14 @@ When developing, test a metric dump against your local Kubernetes cluster by run
> Users can override the apiserver address in KUBE-CONFIG file with `--apiserver` command line.
```
```bash
go install
kube-state-metrics --port=8080 --telemetry-port=8081 --kubeconfig=<KUBE-CONFIG> --apiserver=<APISERVER>
```
Then curl the metrics endpoint
```
```bash
curl localhost:8080/metrics
```

View File

@ -41,6 +41,7 @@ are deleted they are no longer visible on the `/metrics` endpoint.
* [Resource group version compatibility](#resource-group-version-compatibility)
* [Container Image](#container-image)
* [Metrics Documentation](#metrics-documentation)
* [ECMAScript regular expression support for allow and deny lists](#ecmascript-regular-expression-support-for-allow-and-deny-lists)
* [Conflict resolution in label names](#conflict-resolution-in-label-names)
* [Kube-state-metrics self metrics](#kube-state-metrics-self-metrics)
* [Resource recommendation](#resource-recommendation)
@ -67,9 +68,8 @@ are deleted they are no longer visible on the `/metrics` endpoint.
#### Kubernetes Version
kube-state-metrics uses [`client-go`](https://github.com/kubernetes/client-go) to talk with
Kubernetes clusters. The supported Kubernetes cluster version is determined by `client-go`.
The compatibility matrix for client-go and Kubernetes cluster can be found
[here](https://github.com/kubernetes/client-go#compatibility-matrix).
Kubernetes clusters. The supported Kubernetes cluster version is determined by
[`client-go`](https://github.com/kubernetes/client-go#compatibility-matrix).
All additional compatibility is only best effort, or happens to still/already be supported.
#### Compatibility matrix
@ -98,7 +98,7 @@ The latest container image can be found at:
{{ (index . (math.Sub (len .) 2)).version -}}
{{ end }}
* `registry.k8s.io/kube-state-metrics/kube-state-metrics:{{ template "get-latest-release" (datasource "config").compat }}` (arch: `amd64`, `arm`, `arm64`, `ppc64le` and `s390x`)
* View all multi-architecture images at [here](https://explore.ggcr.dev/?image=registry.k8s.io%2Fkube-state-metrics%2Fkube-state-metrics:{{ template "get-latest-release" (datasource "config").compat -}})
* [Multi-architecture images](https://explore.ggcr.dev/?image=registry.k8s.io%2Fkube-state-metrics%2Fkube-state-metrics:{{ template "get-latest-release" (datasource "config").compat -}})
### Metrics Documentation
@ -130,6 +130,10 @@ e.g. by standardizing Kubernetes labels using an
[Admission Webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)
that ensures that there are no possible conflicts.
#### ECMAScript regular expression support for allow and deny lists
Starting from [#2616](https://github.com/kubernetes/kube-state-metrics/pull/2616/files), kube-state-metrics supports ECMAScript's `regexp` for allow and deny lists. This was incorporated as a workaround for the limitations of the `regexp` package in Go, which does not support lookarounds due to their non-linear time complexity. Please note that while lookarounds are now supported for allow and deny lists, regular expressions' evaluation time is capped at a minute to prevent performance issues.
### Kube-state-metrics self metrics
kube-state-metrics exposes its own general process metrics under `--telemetry-host` and `--telemetry-port` (default 8081).
@ -140,7 +144,7 @@ at the logs of kube-state-metrics.
Example of the above mentioned metrics:
```
```prometheus
kube_state_metrics_list_total{resource="*v1.Node",result="success"} 1
kube_state_metrics_list_total{resource="*v1.Node",result="error"} 52
kube_state_metrics_watch_total{resource="*v1beta1.Ingress",result="success"} 1
@ -148,7 +152,7 @@ kube_state_metrics_watch_total{resource="*v1beta1.Ingress",result="success"} 1
kube-state-metrics also exposes some http request metrics, examples of those are:
```
```prometheus
http_request_duration_seconds_bucket{handler="metrics",method="get",le="2.5"} 30
http_request_duration_seconds_bucket{handler="metrics",method="get",le="5"} 30
http_request_duration_seconds_bucket{handler="metrics",method="get",le="10"} 30
@ -159,20 +163,20 @@ http_request_duration_seconds_count{handler="metrics",method="get"} 30
kube-state-metrics also exposes build and configuration metrics:
```
```prometheus
kube_state_metrics_build_info{branch="main",goversion="go1.15.3",revision="6c9d775d",version="v2.0.0-beta"} 1
kube_state_metrics_shard_ordinal{shard_ordinal="0"} 0
kube_state_metrics_total_shards 1
```
`kube_state_metrics_build_info` is used to expose version and other build information. For more usage about the info pattern,
please check the blog post [here](https://www.robustperception.io/exposing-the-software-version-to-prometheus).
please check this [blog post](https://www.robustperception.io/exposing-the-software-version-to-prometheus).
Sharding metrics expose `--shard` and `--total-shards` flags and can be used to validate
run-time configuration, see [`/examples/prometheus-alerting-rules`](./examples/prometheus-alerting-rules).
kube-state-metrics also exposes metrics about it config file and the Custom Resource State config file:
```
```prometheus
kube_state_metrics_config_hash{filename="crs.yml",type="customresourceconfig"} 2.38272279311849e+14
kube_state_metrics_config_hash{filename="config.yml",type="config"} 2.65285922340846e+14
kube_state_metrics_last_config_reload_success_timestamp_seconds{filename="crs.yml",type="customresourceconfig"} 1.6704882592037103e+09
@ -199,7 +203,7 @@ Note that if CPU limits are set too low, kube-state-metrics' internal queues wil
In a 100 node cluster scaling test the latency numbers were as follows:
```
```text
"Perc50": 259615384 ns,
"Perc90": 475000000 ns,
"Perc99": 906666666 ns.
@ -263,7 +267,7 @@ Each kube-state-metrics pod uses FieldSelector (spec.nodeName) to watch/list pod
A daemonset kube-state-metrics example:
```
```yaml
apiVersion: apps/v1
kind: DaemonSet
spec:
@ -285,7 +289,7 @@ spec:
To track metrics for unassigned pods, you need to add an additional deployment and set `--track-unscheduled-pods`, as shown in the following example:
```
```yaml
apiVersion: apps/v1
kind: Deployment
spec:
@ -305,8 +309,8 @@ Other metrics can be sharded via [Horizontal sharding](#horizontal-sharding).
Install this project to your `$GOPATH` using `go get`:
```
go get k8s.io/kube-state-metrics
```bash
go get k8s.io/kube-state-metrics/v2
```
#### Building the Docker container
@ -314,7 +318,7 @@ go get k8s.io/kube-state-metrics
Simply run the following command in this root folder, which will create a
self-contained, statically-linked binary and build a Docker image:
```
```bash
make container
```
@ -337,7 +341,7 @@ To have Prometheus discover kube-state-metrics instances it is advised to create
**Note:** Google Kubernetes Engine (GKE) Users - GKE has strict role permissions that will prevent the kube-state-metrics roles and role bindings from being created. To work around this, you can give your GCP identity the cluster-admin role by running the following one-liner:
```
```bash
kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud info --format='value(config.account)')
```
@ -412,14 +416,14 @@ When developing, test a metric dump against your local Kubernetes cluster by run
> Users can override the apiserver address in KUBE-CONFIG file with `--apiserver` command line.
```
```bash
go install
kube-state-metrics --port=8080 --telemetry-port=8081 --kubeconfig=<KUBE-CONFIG> --apiserver=<APISERVER>
```
Then curl the metrics endpoint
```
```bash
curl localhost:8080/metrics
```

View File

@ -24,7 +24,7 @@ Maintaining the release branches for older minor releases happens on a best effo
* Only include user relevant changes
* Entries in the [`CHANGELOG.md`](CHANGELOG.md) are meant to be in this order:
```
```text
[CHANGE]
[FEATURE]
[ENHANCEMENT]

View File

@ -13,3 +13,4 @@
dgrisonnet
mrueg
rexagod
CatherineF-dev

View File

@ -1,12 +1,10 @@
# The purpose of this config is to keep all versions in a single file and make them machine accessible
# Marks the latest release
version: "2.15.0"
version: "2.16.0"
# List at max 5 releases here + the main branch
compat:
- version: "v2.11.0"
kubernetes: "1.28"
- version: "v2.12.0"
kubernetes: "1.29"
- version: "v2.13.0"
@ -15,5 +13,7 @@ compat:
kubernetes: "1.31"
- version: "v2.15.0"
kubernetes: "1.32"
- version: "main"
- version: "v2.16.0"
kubernetes: "1.32"
- version: "main"
kubernetes: "1.33"

View File

@ -79,13 +79,13 @@ can be used to extend single metrics output.
This example adds `label_release` to the set of default labels of the `kube_pod_status_ready` metric
and allows you select or group the metrics by Helm release label:
```
```promql
kube_pod_status_ready * on (namespace, pod) group_left(label_release) kube_pod_labels
```
Another useful example would be to query the memory usage of pods by its `phase`, such as `Running`:
```
```promql
sum(kube_pod_container_resource_requests{resource="memory"}) by (namespace, pod, node)
* on (namespace, pod) group_left() (sum(kube_pod_status_phase{phase="Running"}) by (pod, namespace) == 1)
```
@ -97,3 +97,49 @@ See [Custom Resource State Metrics](metrics/extend/customresourcestate-metrics.m
## CLI Arguments
Additionally, options for `kube-state-metrics` can be passed when executing as a CLI, or in a kubernetes / openshift environment. More information can be found here: [CLI Arguments](developer/cli-arguments.md)
## Protecting /metrics endpoints
Kube-State-Metrics' metrics can contain sensitive information about the state of the cluster, which you as an operator might want to additionally protect from unauthorized access.
In order to achieve this, you need to enable the `--auth-filter` flag on kube-state-metrics.
With this, kube-state-metrics will only accept authenticated and authorized requests to the /metrics endpoints.
Kube-state-metrics uses Kubernetes' RBAC mechanisms for this, so this means that every scrape will trigger a request against the API Server for TokenReview and SubjectAccessReview.
The clients scraping the endpoint, need to use a token which can be provided by a ServiceAccount that can be set up the following way:
A ClusterRole providing access like this:
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metrics-reader
rules:
- nonResourceURLs:
- "/metrics"
verbs:
- get
```
and a matching ClusterRoleBinding
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metrics-reader-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metrics-reader
subjects:
- kind: ServiceAccount
name: YOUR_SERVICE_ACCOUNT
namespace: NAMESPACE_OF_THE_SERVICE_ACCOUNT
```
Your client can then use either this ServiceAccount to gather metrics or you can create a token, that can be used to fetch data like this:
```bash
TOKEN=$(kubectl create token YOUR_SERVICE_ACCOUNT -n NAMESPACE_OF_THE_SERVICE_ACCOUNT)
curl -H "Authorization: Bearer $TOKEN" KUBE_STATE_METRICS_URL:8080/metrics
```

View File

@ -58,7 +58,7 @@ properties in memory via the Kubernetes client-go cache, use a map, addressable
by the Kubernetes object uuid, containing all time series of that object as a
single multi-line string.
```
```go
var cache = map[uuid][]byte{}
```
@ -76,7 +76,7 @@ On a scrape request on the /metrics endpoint, kube-state-metrics iterates over
the cache map and concatenates all time series string blobs into a single
string, which is finally passed on as a response.
```
```text
+---------------+ +-----------+ +---------------+ +-------------------+
| pod_reflector | | pod_store | | pod_collector | | metrics_endpoint |
+---------------+ +-----------+ +---------------+ +-------------------+
@ -116,7 +116,7 @@ string, which is finally passed on as a response.
Build via [text-diagram](http://weidagang.github.io/text-diagram/)
```
```text
object pod_reflector pod_store pod_collector metrics_endpoint
note left of pod_reflector: new pod p1
@ -163,8 +163,6 @@ pod_collector -> metrics_endpoint: concat(metrics)
of saving unstructured strings inside the cache map, one can structure them,
using pointers to deduplicate e.g. metric names.
* ...
* Kube-state-metrics does not make use of all properties of all Kubernetes
objects. Instead of unmarshalling unused properties, their json struct tags or
their Protobuf representation could be removed.

View File

@ -41,9 +41,10 @@ Flags:
--add_dir_header If true, adds the file directory to the header of the log messages
--alsologtostderr log to standard error as well as files (no effect when -logtostderr=true)
--apiserver string The URL of the apiserver to use as a master
--auth-filter If true, requires authentication and authorization through Kubernetes API to access metrics endpoints
--auto-gomemlimit Automatically set GOMEMLIMIT to match container or system memory limit. (experimental)
--auto-gomemlimit-ratio float The ratio of reserved GOMEMLIMIT memory to the detected maximum container or system memory. (experimental) (default 0.9)
--config string Path to the kube-state-metrics options config file
--config string Path to the kube-state-metrics options config YAML file. If this flag is set, the flags defined in the file override the command line flags.
--custom-resource-state-config string Inline Custom Resource State Metrics config YAML (experimental)
--custom-resource-state-config-file string Path to a Custom Resource State Metrics config file (experimental)
--custom-resource-state-only Only provide Custom Resource State metrics (experimental)
@ -56,14 +57,15 @@ Flags:
--log_file string If non-empty, use this log file (no effect when -logtostderr=true)
--log_file_max_size uint Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
--logtostderr log to standard error instead of files (default true)
--metric-allowlist string Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.
--metric-allowlist string Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or *ECMAScript-based* regex patterns. The allowlist and denylist are mutually exclusive.
--metric-annotations-allowlist string Comma-separated list of Kubernetes annotations keys that will be used in the resource' labels metric. By default the annotations metrics are not exposed. To include them, provide a list of resource names in their plural form and Kubernetes annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. A single '*' can be provided per resource instead to allow any annotations, but that has severe performance implications (Example: '=pods=[*]').
--metric-denylist string Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.
--metric-denylist string Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or *ECMAScript-based* regex patterns. The allowlist and denylist are mutually exclusive.
--metric-labels-allowlist string Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the labels metrics are not exposed. To include them, provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]'). Additionally, an asterisk (*) can be provided as a key, which will resolve to all resources, i.e., assuming '--resources=deployments,pods', '=*=[*]' will resolve to '=deployments=[*],pods=[*]'.
--metric-opt-in-list string Comma-separated list of metrics which are opt-in and not enabled by default. This is in addition to the metric allow- and denylists
--namespaces string Comma-separated list of namespaces to be enabled. Defaults to ""
--namespaces-denylist string Comma-separated list of namespaces not to be enabled. If namespaces and namespaces-denylist are both set, only namespaces that are excluded in namespaces-denylist will be used.
--node string Name of the node that contains the kube-state-metrics pod. Most likely it should be passed via the downward API. This is used for daemonset sharding. Only available for resources (pod metrics) that support spec.nodeName fieldSelector. This is experimental.
--object-limit int The total number of objects to list per resource from the API Server. (experimental)
--one_output If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)
--pod string Name of the pod that contains the kube-state-metrics container. When set, it is expected that --pod and --pod-namespace are both set. Most likely this should be passed via the downward API. This is used for auto-detecting sharding. If set, this has preference over statically configured sharding. This is experimental, it may be removed without notice.
--pod-namespace string Name of the namespace of the pod specified by --pod. When set, it is expected that --pod and --pod-namespace are both set. Most likely this should be passed via the downward API. This is used for auto-detecting sharding. If set, this has preference over statically configured sharding. This is experimental, it may be removed without notice.

View File

@ -269,7 +269,7 @@ kube_customresource_ref_info{customresource_group="myteam.io", customresource_ki
For example in VPA we have above attributes and we want to have a same metrics for both CPU and Memory, you can use below config:
```
```yaml
kind: CustomResourceStateMetrics
spec:
resources:

View File

@ -1,11 +1,11 @@
# Ingress Metrics
| Metric name | Metric type | Description | Labels/tags | Status |
| -------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| kube_ingress_annotations | Gauge | Kubernetes annotations converted to Prometheus labels controlled via [--metric-annotations-allowlist](../../developer/cli-arguments.md) | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `annotation_INGRESS_ANNOTATION`=&lt;ANNOTATION_LABEL&gt; | EXPERIMENTAL |
| kube_ingress_info | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `ingressclass`=&lt;ingress-class&gt; or `_default` if not set | STABLE |
| kube_ingress_labels | Gauge | Kubernetes labels converted to Prometheus labels controlled via [--metric-labels-allowlist](../../developer/cli-arguments.md) | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `label_INGRESS_LABEL`=&lt;INGRESS_LABEL&gt; | STABLE |
| kube_ingress_created | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; | STABLE |
| kube_ingress_metadata_resource_version | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; | EXPERIMENTAL |
| kube_ingress_path | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `host`=&lt;ingress-host&gt; <br> `path`=&lt;ingress-path&gt; <br><i> If path served by Service Backend</i> <br> `service_name`=&lt;service name for the path&gt; <br> `service_port`=&lt;service port for the path&gt;<br><i> If path served by Resource Backend</i><br> `resource_api_group`=&lt;resource backend api group&gt; <br> `resource_kind`=&lt;resource backend kind&gt; <br> `resource_name`=&lt;resource backend name&gt; | STABLE |
| kube_ingress_tls | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `tls_host`=&lt;tls hostname&gt; <br> `secret`=&lt;tls secret name&gt; | STABLE |
| Metric name | Metric type | Description | Labels/tags | Status |
| -------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------ |
| kube_ingress_annotations | Gauge | Kubernetes annotations converted to Prometheus labels controlled via [--metric-annotations-allowlist](../../developer/cli-arguments.md) | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `annotation_INGRESS_ANNOTATION`=&lt;ANNOTATION_LABEL&gt; | EXPERIMENTAL |
| kube_ingress_info | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `ingressclass`=&lt;ingress-class&gt; or `_default` if not set | STABLE |
| kube_ingress_labels | Gauge | Kubernetes labels converted to Prometheus labels controlled via [--metric-labels-allowlist](../../developer/cli-arguments.md) | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `label_INGRESS_LABEL`=&lt;INGRESS_LABEL&gt; | STABLE |
| kube_ingress_created | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; | STABLE |
| kube_ingress_metadata_resource_version | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; | EXPERIMENTAL |
| kube_ingress_path | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `host`=&lt;ingress-host&gt; <br> `path`=&lt;ingress-path&gt; <br> `path_type`=&lt;ingress-path type&gt; <br> If path served by Service Backend <br> `service_name`=&lt;service name for the path&gt; <br> `service_port`=&lt;service port for the path&gt; <br> If path served by Resource Backend <br> `resource_api_group`=&lt;resource backend api group&gt; <br> `resource_kind`=&lt;resource backend kind&gt; <br> `resource_name`=&lt;resource backend name&gt; | STABLE |
| kube_ingress_tls | Gauge | | `ingress`=&lt;ingress-name&gt; <br> `namespace`=&lt;ingress-namespace&gt; <br> `tls_host`=&lt;tls hostname&gt; <br> `secret`=&lt;tls secret name&gt; | STABLE |

View File

@ -5,9 +5,9 @@
| kube_persistentvolume_annotations | Gauge | Kubernetes annotations converted to Prometheus labels controlled via [--metric-annotations-allowlist](../../developer/cli-arguments.md) | | `persistentvolume`=&lt;persistentvolume-name&gt; <br> `annotation_PERSISTENTVOLUME_ANNOTATION`=&lt;PERSISTENTVOLUME_ANNOTATION&gt; | EXPERIMENTAL |
| kube_persistentvolume_capacity_bytes | Gauge | | | `persistentvolume`=&lt;pv-name&gt; | STABLE |
| kube_persistentvolume_status_phase | Gauge | | | `persistentvolume`=&lt;pv-name&gt; <br>`phase`=&lt;Bound\|Failed\|Pending\|Available\|Released&gt; | STABLE |
| kube_persistentvolume_claim_ref | Gauge | | | `persistentvolume`=&lt;pv-name&gt; <br>`claim_namespace`=&lt;<namespace>&gt; <br>`name`=&lt;<name>&gt; | STABLE |
| kube_persistentvolume_claim_ref | Gauge | | | `persistentvolume`=&lt;pv-name&gt; <br>`claim_namespace`=`<namespace>`; <br>`name`=`<name>`; | STABLE |
| kube_persistentvolume_labels | Gauge | Kubernetes labels converted to Prometheus labels controlled via [--metric-labels-allowlist](../../developer/cli-arguments.md) | | `persistentvolume`=&lt;persistentvolume-name&gt; <br> `label_PERSISTENTVOLUME_LABEL`=&lt;PERSISTENTVOLUME_LABEL&gt; | STABLE |
| kube_persistentvolume_info | Gauge | Information about Persistent Volumes | | `persistentvolume`=&lt;pv-name&gt; <br> `storageclass`=&lt;storageclass-name&gt; <br> `gce_persistent_disk_name`=&lt;pd-name&gt; <br> `host_path`=&lt;path-of-a-host-volume&gt; <br> `host_path_type`=&lt;host-mount-type&gt; <br> `ebs_volume_id`=&lt;ebs-volume-id&gt; <br> `azure_disk_name`=&lt;azure-disk-name&gt; <br> `fc_wwids`=&lt;fc-wwids-comma-separated&gt; <br> `fc_lun`=&lt;fc-lun&gt; <br> `fc_target_wwns`=&lt;fc-target-wwns-comma-separated&gt; <br> `iscsi_target_portal`=&lt;iscsi-target-portal&gt; <br> `iscsi_iqn`=&lt;iscsi-iqn&gt; <br> `iscsi_lun`=&lt;iscsi-lun&gt; <br> `iscsi_initiator_name`=&lt;iscsi-initiator-name&gt; <br> `local_path`=&lt;path-of-a-local-volume&gt; <br> `local_fs`=&lt;local-volume-fs-type&gt; <br> `nfs_server`=&lt;nfs-server&gt; <br> `nfs_path`=&lt;nfs-path&gt; <br> `csi_driver`=&lt;csi-driver&gt; <br> `csi_volume_handle`=&lt;csi-volume-handle&gt; | STABLE |
| kube_persistentvolume_info | Gauge | Information about Persistent Volumes | | `persistentvolume`=&lt;pv-name&gt; <br> `storageclass`=&lt;storageclass-name&gt; <br> `gce_persistent_disk_name`=&lt;pd-name&gt; <br> `host_path`=&lt;path-of-a-host-volume&gt; <br> `host_path_type`=&lt;host-mount-type&gt; <br> `ebs_volume_id`=&lt;ebs-volume-id&gt; <br> `azure_disk_name`=&lt;azure-disk-name&gt; <br> `fc_wwids`=&lt;fc-wwids-comma-separated&gt; <br> `fc_lun`=&lt;fc-lun&gt; <br> `fc_target_wwns`=&lt;fc-target-wwns-comma-separated&gt; <br> `iscsi_target_portal`=&lt;iscsi-target-portal&gt; <br> `iscsi_iqn`=&lt;iscsi-iqn&gt; <br> `iscsi_lun`=&lt;iscsi-lun&gt; <br> `iscsi_initiator_name`=&lt;iscsi-initiator-name&gt; <br> `local_path`=&lt;path-of-a-local-volume&gt; <br> `local_fs`=&lt;local-volume-fs-type&gt; <br> `nfs_server`=&lt;nfs-server&gt; <br> `nfs_path`=&lt;nfs-path&gt; <br> `csi_driver`=&lt;csi-driver&gt; <br> `csi_volume_handle`=&lt;csi-volume-handle&gt; <br> `reclaim_policy`=&lt;reclaim-policy&gt; | STABLE |
| kube_persistentvolume_created | Gauge | Unix creation timestamp | seconds | `persistentvolume`=&lt;persistentvolume-name&gt; <br> | EXPERIMENTAL |
| kube_persistentvolume_deletion_timestamp | Gauge | Unix deletion timestamp | seconds | `persistentvolume`=&lt;persistentvolume-name&gt; <br> | EXPERIMENTAL |
| kube_persistentvolume_csi_attributes | Gauge | CSI attributes of the Persistent Volume, disabled by default, manage with [--metric-opt-in-list](../../developer/cli-arguments.md)) | | `persistentvolume`=&lt;persistentvolume-name&gt; <br> `csi_mounter`=&lt;csi-mounter&gt; <br> `csi_map_options`=&lt;csi-map-options&gt; | EXPERIMENTAL |

View File

@ -9,7 +9,7 @@
| kube_deployment_status_replicas_unavailable | Gauge | | `deployment`=&lt;deployment-name&gt; <br> `namespace`=&lt;deployment-namespace&gt; | STABLE |
| kube_deployment_status_replicas_updated | Gauge | | `deployment`=&lt;deployment-name&gt; <br> `namespace`=&lt;deployment-namespace&gt; | STABLE |
| kube_deployment_status_observed_generation | Gauge | | `deployment`=&lt;deployment-name&gt; <br> `namespace`=&lt;deployment-namespace&gt; | STABLE |
| kube_deployment_status_condition | Gauge | | `deployment`=&lt;deployment-name&gt; <br> `namespace`=&lt;deployment-namespace&gt; <br> `condition`=&lt;deployment-condition&gt; <br> `status`=&lt;true\|false\|unknown&gt; | STABLE |
| kube_deployment_status_condition | Gauge | | `deployment`=&lt;deployment-name&gt; <br> `namespace`=&lt;deployment-namespace&gt; <br> `reason`=&lt;deployment-transition-reason&gt; <br> `condition`=&lt;deployment-condition&gt; <br> `status`=&lt;true\|false\|unknown&gt; | STABLE |
| kube_deployment_spec_replicas | Gauge | | `deployment`=&lt;deployment-name&gt; <br> `namespace`=&lt;deployment-namespace&gt; | STABLE |
| kube_deployment_spec_paused | Gauge | | `deployment`=&lt;deployment-name&gt; <br> `namespace`=&lt;deployment-namespace&gt; | STABLE |
| kube_deployment_spec_strategy_rollingupdate_max_unavailable | Gauge | | `deployment`=&lt;deployment-name&gt; <br> `namespace`=&lt;deployment-namespace&gt; | STABLE |

View File

@ -53,6 +53,7 @@
| kube_pod_status_reason | Gauge | The pod status reasons | | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `reason`=&lt;Evicted\|NodeAffinity\|NodeLost\|Shutdown\|UnexpectedAdmissionError&gt; <br> `uid`=&lt;pod-uid&gt; | EXPERIMENTAL | - |
| kube_pod_status_scheduled_time | Gauge | Unix timestamp when pod moved into scheduled status | seconds | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `uid`=&lt;pod-uid&gt; | STABLE | - |
| kube_pod_status_unschedulable | Gauge | Describes the unschedulable status for the pod | | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `uid`=&lt;pod-uid&gt; | STABLE | - |
| kube_pod_status_unscheduled_time | Gauge | Unix timestamp when pod moved into unscheduled status | seconds | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `uid`=&lt;pod-uid&gt; | EXPERIMENTAL | - |
| kube_pod_tolerations | Gauge | Information about the pod tolerations | | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `uid`=&lt;pod-uid&gt; <br> `key`=&lt;toleration-key&gt; <br> `operator`=&lt;toleration-operator&gt; <br> `value`=&lt;toleration-value&gt; <br> `effect`=&lt;toleration-effect&gt; `toleration_seconds`=&lt;toleration-seconds&gt; | EXPERIMENTAL | - |
| kube_pod_service_account | Gauge | The service account for a pod | | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `uid`=&lt;pod-uid&gt; <br> `service_account`=&lt;service_account&gt; | EXPERIMENTAL | - |
| kube_pod_scheduler | Gauge | The scheduler for a pod | | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `uid`=&lt;pod-uid&gt; <br> `name`=&lt;scheduler-name&gt; | EXPERIMENTAL | - |

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
roleRef:
apiGroup: rbac.authorization.k8s.io

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
rules:
- apiGroups:

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system
roleRef:

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system
rules:

View File

@ -5,6 +5,6 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system
spec:

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system
spec:
@ -18,7 +18,7 @@ spec:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
spec:
automountServiceAccountToken: true
containers:
@ -34,7 +34,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.15.0
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.16.0
livenessProbe:
httpGet:
path: /livez

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
roleRef:
apiGroup: rbac.authorization.k8s.io

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
rules:
- apiGroups:

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics-shard
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics-shard
namespace: kube-system
spec:

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics-shard
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics-shard
namespace: kube-system
spec:
@ -16,7 +16,7 @@ spec:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics-shard
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
spec:
automountServiceAccountToken: true
containers:
@ -29,7 +29,7 @@ spec:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.15.0
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.16.0
livenessProbe:
httpGet:
path: /livez

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system
spec:

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics-unscheduled-pods-fetching
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics-unscheduled-pods-fetching
namespace: kube-system
spec:

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics-unscheduled-pods-fetching
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics-unscheduled-pods-fetching
namespace: kube-system
spec:
@ -17,14 +17,14 @@ spec:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics-unscheduled-pods-fetching
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
spec:
automountServiceAccountToken: true
containers:
- args:
- --resources=pods
- --track-unscheduled-pods
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.15.0
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.16.0
livenessProbe:
httpGet:
path: /livez

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system
spec:
@ -17,13 +17,13 @@ spec:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
spec:
automountServiceAccountToken: true
containers:
- args:
- --resources=certificatesigningrequests,configmaps,cronjobs,daemonsets,deployments,endpoints,horizontalpodautoscalers,ingresses,jobs,leases,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,replicasets,replicationcontrollers,resourcequotas,secrets,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.15.0
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.16.0
livenessProbe:
httpGet:
path: /livez

View File

@ -5,6 +5,6 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
roleRef:
apiGroup: rbac.authorization.k8s.io

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
rules:
- apiGroups:

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system
spec:
@ -17,11 +17,11 @@ spec:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
spec:
automountServiceAccountToken: true
containers:
- image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.15.0
- image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.16.0
livenessProbe:
httpGet:
path: /livez

View File

@ -5,6 +5,6 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system

View File

@ -4,7 +4,7 @@ metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.15.0
app.kubernetes.io/version: 2.16.0
name: kube-state-metrics
namespace: kube-system
spec:

262
go.mod
View File

@ -1,96 +1,264 @@
module k8s.io/kube-state-metrics/v2
go 1.23.0
go 1.24.0
require (
github.com/KimMachineGun/automemlimit v0.7.0
github.com/KimMachineGun/automemlimit v0.7.4
github.com/dgryski/go-jump v0.0.0-20211018200510-ba001c3ffce0
github.com/fsnotify/fsnotify v1.8.0
github.com/go-logr/logr v1.4.2
github.com/dlclark/regexp2 v1.11.5
github.com/fsnotify/fsnotify v1.9.0
github.com/go-logr/logr v1.4.3
github.com/gobuffalo/flect v1.0.3
github.com/google/go-cmp v0.6.0
github.com/oklog/run v1.1.0
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.62.0
github.com/prometheus/exporter-toolkit v0.13.2
github.com/google/go-cmp v0.7.0
github.com/oklog/run v1.2.0
github.com/prometheus/client_golang v1.23.0
github.com/prometheus/client_model v0.6.2
github.com/prometheus/common v0.65.0
github.com/prometheus/exporter-toolkit v0.14.0
github.com/robfig/cron/v3 v3.0.1
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.20.1
github.com/stretchr/testify v1.10.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.32.1
k8s.io/apimachinery v0.32.1
k8s.io/client-go v0.32.1
k8s.io/component-base v0.32.1
k8s.io/api v0.33.3
k8s.io/apimachinery v0.33.3
k8s.io/client-go v0.33.3
k8s.io/component-base v0.33.3
k8s.io/klog/v2 v2.130.1
k8s.io/sample-controller v0.32.1
k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078
k8s.io/sample-controller v0.33.3
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
sigs.k8s.io/controller-runtime v0.21.0
sigs.k8s.io/yaml v1.6.0
)
require (
cel.dev/expr v0.19.1 // indirect
cloud.google.com/go v0.116.0 // indirect
cloud.google.com/go/auth v0.13.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/iam v1.2.2 // indirect
cloud.google.com/go/monitoring v1.21.2 // indirect
cloud.google.com/go/storage v1.49.0 // indirect
cuelang.org/go v0.11.0 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/Shopify/ejson v1.5.3 // indirect
github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794 // indirect
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go v1.55.5 // indirect
github.com/aws/aws-sdk-go-v2 v1.32.6 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
github.com/aws/aws-sdk-go-v2/config v1.28.6 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.47 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 // indirect
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 // indirect
github.com/aws/smithy-go v1.22.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/brancz/gojsontoyaml v0.1.0 // indirect
github.com/campoy/embedmd v1.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudflare/circl v1.3.9 // indirect
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect
github.com/elliotchance/orderedmap/v2 v2.2.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/envoyproxy/go-control-plane v0.13.1 // indirect
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/cel-go v0.23.2 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-jsonnet v0.20.0 // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/wire v0.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/gosimple/slug v1.14.0 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/hack-pad/hackpadfs v0.2.4 // indirect
github.com/hairyhenderson/go-fsimpl v0.2.1 // indirect
github.com/hairyhenderson/go-git/v5 v5.12.1-0.20240530140403-1b868a7b8a3c // indirect
github.com/hairyhenderson/gomplate/v4 v4.3.0 // indirect
github.com/hairyhenderson/toml v0.4.2-0.20210923231440-40456b8e66cf // indirect
github.com/hairyhenderson/xignore v0.3.3-0.20230403012150-95fe86932830 // indirect
github.com/hairyhenderson/yaml v0.0.0-20220618171115-2d35fca545ce // indirect
github.com/hashicorp/consul/api v1.30.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-secure-stdlib/awsutil v0.3.0 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/hashicorp/vault/api v1.15.0 // indirect
github.com/hashicorp/vault/api/auth/approle v0.8.0 // indirect
github.com/hashicorp/vault/api/auth/aws v0.8.0 // indirect
github.com/hashicorp/vault/api/auth/userpass v0.8.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/itchyny/gojq v0.12.17 // indirect
github.com/itchyny/timefmt-go v0.1.6 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/jsonnet-bundler/jsonnet-bundler v0.6.0 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lmittmann/tint v1.0.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.2.2 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.29.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.7.0 // indirect
google.golang.org/protobuf v1.36.1 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.3 // indirect
go4.org/intern v0.0.0-20230525184215-6c62f75575cb // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect
gocloud.dev v0.40.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/perf v0.0.0-20250214215153-c95ad7d5b636 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/term v0.33.0 // indirect
golang.org/x/text v0.27.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
google.golang.org/api v0.215.0 // indirect
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
google.golang.org/grpc v1.68.1 // indirect
google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // 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
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a // indirect
k8s.io/apiserver v0.33.0 // indirect
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
)
tool (
github.com/brancz/gojsontoyaml
github.com/campoy/embedmd
github.com/google/go-jsonnet/cmd/jsonnet
github.com/hairyhenderson/gomplate/v4/cmd/gomplate
github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb
golang.org/x/perf/cmd/benchstat
)

901
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -64,8 +64,8 @@ func (r *CRDiscoverer) StartDiscovery(ctx context.Context, config *rest.Config)
},
Plural: p,
}
r.AppendToMap(gotGVKP)
r.SafeWrite(func() {
r.AppendToMap(gotGVKP)
r.WasUpdated = true
})
}
@ -89,8 +89,8 @@ func (r *CRDiscoverer) StartDiscovery(ctx context.Context, config *rest.Config)
},
Plural: p,
}
r.RemoveFromMap(gotGVKP)
r.SafeWrite(func() {
r.RemoveFromMap(gotGVKP)
r.WasUpdated = true
})
}

View File

@ -45,6 +45,8 @@ type CRDiscoverer struct {
CRDsCacheCountGauge prometheus.Gauge
// Map is a cache of the collected GVKs.
Map map[string]map[string][]kindPlural
// GVKToReflectorStopChanMap is a map of GVKs to channels that can be used to stop their corresponding reflector.
GVKToReflectorStopChanMap map[string]chan struct{}
// m is a mutex to protect the cache.
m sync.RWMutex
// ShouldUpdate is a flag that indicates whether the cache was updated.
@ -70,6 +72,9 @@ func (r *CRDiscoverer) AppendToMap(gvkps ...groupVersionKindPlural) {
if r.Map == nil {
r.Map = map[string]map[string][]kindPlural{}
}
if r.GVKToReflectorStopChanMap == nil {
r.GVKToReflectorStopChanMap = map[string]chan struct{}{}
}
for _, gvkp := range gvkps {
if _, ok := r.Map[gvkp.Group]; !ok {
r.Map[gvkp.Group] = map[string][]kindPlural{}
@ -78,6 +83,7 @@ func (r *CRDiscoverer) AppendToMap(gvkps ...groupVersionKindPlural) {
r.Map[gvkp.Group][gvkp.Version] = []kindPlural{}
}
r.Map[gvkp.Group][gvkp.Version] = append(r.Map[gvkp.Group][gvkp.Version], kindPlural{Kind: gvkp.Kind, Plural: gvkp.Plural})
r.GVKToReflectorStopChanMap[gvkp.GroupVersionKind.String()] = make(chan struct{})
}
}
@ -92,6 +98,8 @@ func (r *CRDiscoverer) RemoveFromMap(gvkps ...groupVersionKindPlural) {
}
for i, el := range r.Map[gvkp.Group][gvkp.Version] {
if el.Kind == gvkp.Kind {
close(r.GVKToReflectorStopChanMap[gvkp.GroupVersionKind.String()])
delete(r.GVKToReflectorStopChanMap, gvkp.GroupVersionKind.String())
if len(r.Map[gvkp.Group][gvkp.Version]) == 1 {
delete(r.Map[gvkp.Group], gvkp.Version)
if len(r.Map[gvkp.Group]) == 0 {

View File

@ -38,6 +38,7 @@ import (
policyv1 "k8s.io/api/policy/v1"
rbacv1 "k8s.io/api/rbac/v1"
storagev1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
@ -83,6 +84,9 @@ type Builder struct {
totalShards int
shard int32
useAPIServerCache bool
objectLimit int64
GVKToReflectorStopChanMap *map[string]chan struct{}
}
// NewBuilder returns a new builder.
@ -165,6 +169,12 @@ func (b *Builder) WithUsingAPIServerCache(u bool) {
b.useAPIServerCache = u
}
// WithObjectLimit sets a limit on how many objects you can list from the APIServer.
// This is to protect kube-state-metrics from running out of memory if the APIServer has a lot of objects.
func (b *Builder) WithObjectLimit(l int64) {
b.objectLimit = l
}
// WithFamilyGeneratorFilter configures the family generator filter which decides which
// metrics are to be exposed by the store build by the Builder.
func (b *Builder) WithFamilyGeneratorFilter(l generator.FamilyGeneratorFilter) {
@ -215,6 +225,7 @@ func (b *Builder) WithCustomResourceStoreFactories(fs ...customresource.Registry
f.ExpectedType(),
f.ListWatch,
b.useAPIServerCache,
b.objectLimit,
)
}
}
@ -363,150 +374,150 @@ func availableResources() []string {
}
func (b *Builder) buildConfigMapStores() []cache.Store {
return b.buildStoresFunc(configMapMetricFamilies(b.allowAnnotationsList["configmaps"], b.allowLabelsList["configmaps"]), &v1.ConfigMap{}, createConfigMapListWatch, b.useAPIServerCache)
return b.buildStoresFunc(configMapMetricFamilies(b.allowAnnotationsList["configmaps"], b.allowLabelsList["configmaps"]), &v1.ConfigMap{}, createConfigMapListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildCronJobStores() []cache.Store {
return b.buildStoresFunc(cronJobMetricFamilies(b.allowAnnotationsList["cronjobs"], b.allowLabelsList["cronjobs"]), &batchv1.CronJob{}, createCronJobListWatch, b.useAPIServerCache)
return b.buildStoresFunc(cronJobMetricFamilies(b.allowAnnotationsList["cronjobs"], b.allowLabelsList["cronjobs"]), &batchv1.CronJob{}, createCronJobListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildDaemonSetStores() []cache.Store {
return b.buildStoresFunc(daemonSetMetricFamilies(b.allowAnnotationsList["daemonsets"], b.allowLabelsList["daemonsets"]), &appsv1.DaemonSet{}, createDaemonSetListWatch, b.useAPIServerCache)
return b.buildStoresFunc(daemonSetMetricFamilies(b.allowAnnotationsList["daemonsets"], b.allowLabelsList["daemonsets"]), &appsv1.DaemonSet{}, createDaemonSetListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildDeploymentStores() []cache.Store {
return b.buildStoresFunc(deploymentMetricFamilies(b.allowAnnotationsList["deployments"], b.allowLabelsList["deployments"]), &appsv1.Deployment{}, createDeploymentListWatch, b.useAPIServerCache)
return b.buildStoresFunc(deploymentMetricFamilies(b.allowAnnotationsList["deployments"], b.allowLabelsList["deployments"]), &appsv1.Deployment{}, createDeploymentListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildEndpointsStores() []cache.Store {
return b.buildStoresFunc(endpointMetricFamilies(b.allowAnnotationsList["endpoints"], b.allowLabelsList["endpoints"]), &v1.Endpoints{}, createEndpointsListWatch, b.useAPIServerCache)
return b.buildStoresFunc(endpointMetricFamilies(b.allowAnnotationsList["endpoints"], b.allowLabelsList["endpoints"]), &v1.Endpoints{}, createEndpointsListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildEndpointSlicesStores() []cache.Store {
return b.buildStoresFunc(endpointSliceMetricFamilies(b.allowAnnotationsList["endpointslices"], b.allowLabelsList["endpointslices"]), &discoveryv1.EndpointSlice{}, createEndpointSliceListWatch, b.useAPIServerCache)
return b.buildStoresFunc(endpointSliceMetricFamilies(b.allowAnnotationsList["endpointslices"], b.allowLabelsList["endpointslices"]), &discoveryv1.EndpointSlice{}, createEndpointSliceListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildHPAStores() []cache.Store {
return b.buildStoresFunc(hpaMetricFamilies(b.allowAnnotationsList["horizontalpodautoscalers"], b.allowLabelsList["horizontalpodautoscalers"]), &autoscaling.HorizontalPodAutoscaler{}, createHPAListWatch, b.useAPIServerCache)
return b.buildStoresFunc(hpaMetricFamilies(b.allowAnnotationsList["horizontalpodautoscalers"], b.allowLabelsList["horizontalpodautoscalers"]), &autoscaling.HorizontalPodAutoscaler{}, createHPAListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildIngressStores() []cache.Store {
return b.buildStoresFunc(ingressMetricFamilies(b.allowAnnotationsList["ingresses"], b.allowLabelsList["ingresses"]), &networkingv1.Ingress{}, createIngressListWatch, b.useAPIServerCache)
return b.buildStoresFunc(ingressMetricFamilies(b.allowAnnotationsList["ingresses"], b.allowLabelsList["ingresses"]), &networkingv1.Ingress{}, createIngressListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildJobStores() []cache.Store {
return b.buildStoresFunc(jobMetricFamilies(b.allowAnnotationsList["jobs"], b.allowLabelsList["jobs"]), &batchv1.Job{}, createJobListWatch, b.useAPIServerCache)
return b.buildStoresFunc(jobMetricFamilies(b.allowAnnotationsList["jobs"], b.allowLabelsList["jobs"]), &batchv1.Job{}, createJobListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildLimitRangeStores() []cache.Store {
return b.buildStoresFunc(limitRangeMetricFamilies, &v1.LimitRange{}, createLimitRangeListWatch, b.useAPIServerCache)
return b.buildStoresFunc(limitRangeMetricFamilies, &v1.LimitRange{}, createLimitRangeListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildMutatingWebhookConfigurationStores() []cache.Store {
return b.buildStoresFunc(mutatingWebhookConfigurationMetricFamilies, &admissionregistrationv1.MutatingWebhookConfiguration{}, createMutatingWebhookConfigurationListWatch, b.useAPIServerCache)
return b.buildStoresFunc(mutatingWebhookConfigurationMetricFamilies, &admissionregistrationv1.MutatingWebhookConfiguration{}, createMutatingWebhookConfigurationListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildNamespaceStores() []cache.Store {
return b.buildStoresFunc(namespaceMetricFamilies(b.allowAnnotationsList["namespaces"], b.allowLabelsList["namespaces"]), &v1.Namespace{}, createNamespaceListWatch, b.useAPIServerCache)
return b.buildStoresFunc(namespaceMetricFamilies(b.allowAnnotationsList["namespaces"], b.allowLabelsList["namespaces"]), &v1.Namespace{}, createNamespaceListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildNetworkPolicyStores() []cache.Store {
return b.buildStoresFunc(networkPolicyMetricFamilies(b.allowAnnotationsList["networkpolicies"], b.allowLabelsList["networkpolicies"]), &networkingv1.NetworkPolicy{}, createNetworkPolicyListWatch, b.useAPIServerCache)
return b.buildStoresFunc(networkPolicyMetricFamilies(b.allowAnnotationsList["networkpolicies"], b.allowLabelsList["networkpolicies"]), &networkingv1.NetworkPolicy{}, createNetworkPolicyListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildNodeStores() []cache.Store {
return b.buildStoresFunc(nodeMetricFamilies(b.allowAnnotationsList["nodes"], b.allowLabelsList["nodes"]), &v1.Node{}, createNodeListWatch, b.useAPIServerCache)
return b.buildStoresFunc(nodeMetricFamilies(b.allowAnnotationsList["nodes"], b.allowLabelsList["nodes"]), &v1.Node{}, createNodeListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildPersistentVolumeClaimStores() []cache.Store {
return b.buildStoresFunc(persistentVolumeClaimMetricFamilies(b.allowAnnotationsList["persistentvolumeclaims"], b.allowLabelsList["persistentvolumeclaims"]), &v1.PersistentVolumeClaim{}, createPersistentVolumeClaimListWatch, b.useAPIServerCache)
return b.buildStoresFunc(persistentVolumeClaimMetricFamilies(b.allowAnnotationsList["persistentvolumeclaims"], b.allowLabelsList["persistentvolumeclaims"]), &v1.PersistentVolumeClaim{}, createPersistentVolumeClaimListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildPersistentVolumeStores() []cache.Store {
return b.buildStoresFunc(persistentVolumeMetricFamilies(b.allowAnnotationsList["persistentvolumes"], b.allowLabelsList["persistentvolumes"]), &v1.PersistentVolume{}, createPersistentVolumeListWatch, b.useAPIServerCache)
return b.buildStoresFunc(persistentVolumeMetricFamilies(b.allowAnnotationsList["persistentvolumes"], b.allowLabelsList["persistentvolumes"]), &v1.PersistentVolume{}, createPersistentVolumeListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildPodDisruptionBudgetStores() []cache.Store {
return b.buildStoresFunc(podDisruptionBudgetMetricFamilies(b.allowAnnotationsList["poddisruptionbudgets"], b.allowLabelsList["poddisruptionbudgets"]), &policyv1.PodDisruptionBudget{}, createPodDisruptionBudgetListWatch, b.useAPIServerCache)
return b.buildStoresFunc(podDisruptionBudgetMetricFamilies(b.allowAnnotationsList["poddisruptionbudgets"], b.allowLabelsList["poddisruptionbudgets"]), &policyv1.PodDisruptionBudget{}, createPodDisruptionBudgetListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildReplicaSetStores() []cache.Store {
return b.buildStoresFunc(replicaSetMetricFamilies(b.allowAnnotationsList["replicasets"], b.allowLabelsList["replicasets"]), &appsv1.ReplicaSet{}, createReplicaSetListWatch, b.useAPIServerCache)
return b.buildStoresFunc(replicaSetMetricFamilies(b.allowAnnotationsList["replicasets"], b.allowLabelsList["replicasets"]), &appsv1.ReplicaSet{}, createReplicaSetListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildReplicationControllerStores() []cache.Store {
return b.buildStoresFunc(replicationControllerMetricFamilies, &v1.ReplicationController{}, createReplicationControllerListWatch, b.useAPIServerCache)
return b.buildStoresFunc(replicationControllerMetricFamilies, &v1.ReplicationController{}, createReplicationControllerListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildResourceQuotaStores() []cache.Store {
return b.buildStoresFunc(resourceQuotaMetricFamilies(b.allowAnnotationsList["resourcequotas"], b.allowLabelsList["resourcequotas"]), &v1.ResourceQuota{}, createResourceQuotaListWatch, b.useAPIServerCache)
return b.buildStoresFunc(resourceQuotaMetricFamilies(b.allowAnnotationsList["resourcequotas"], b.allowLabelsList["resourcequotas"]), &v1.ResourceQuota{}, createResourceQuotaListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildSecretStores() []cache.Store {
return b.buildStoresFunc(secretMetricFamilies(b.allowAnnotationsList["secrets"], b.allowLabelsList["secrets"]), &v1.Secret{}, createSecretListWatch, b.useAPIServerCache)
return b.buildStoresFunc(secretMetricFamilies(b.allowAnnotationsList["secrets"], b.allowLabelsList["secrets"]), &v1.Secret{}, createSecretListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildServiceAccountStores() []cache.Store {
return b.buildStoresFunc(serviceAccountMetricFamilies(b.allowAnnotationsList["serviceaccounts"], b.allowLabelsList["serviceaccounts"]), &v1.ServiceAccount{}, createServiceAccountListWatch, b.useAPIServerCache)
return b.buildStoresFunc(serviceAccountMetricFamilies(b.allowAnnotationsList["serviceaccounts"], b.allowLabelsList["serviceaccounts"]), &v1.ServiceAccount{}, createServiceAccountListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildServiceStores() []cache.Store {
return b.buildStoresFunc(serviceMetricFamilies(b.allowAnnotationsList["services"], b.allowLabelsList["services"]), &v1.Service{}, createServiceListWatch, b.useAPIServerCache)
return b.buildStoresFunc(serviceMetricFamilies(b.allowAnnotationsList["services"], b.allowLabelsList["services"]), &v1.Service{}, createServiceListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildStatefulSetStores() []cache.Store {
return b.buildStoresFunc(statefulSetMetricFamilies(b.allowAnnotationsList["statefulsets"], b.allowLabelsList["statefulsets"]), &appsv1.StatefulSet{}, createStatefulSetListWatch, b.useAPIServerCache)
return b.buildStoresFunc(statefulSetMetricFamilies(b.allowAnnotationsList["statefulsets"], b.allowLabelsList["statefulsets"]), &appsv1.StatefulSet{}, createStatefulSetListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildStorageClassStores() []cache.Store {
return b.buildStoresFunc(storageClassMetricFamilies(b.allowAnnotationsList["storageclasses"], b.allowLabelsList["storageclasses"]), &storagev1.StorageClass{}, createStorageClassListWatch, b.useAPIServerCache)
return b.buildStoresFunc(storageClassMetricFamilies(b.allowAnnotationsList["storageclasses"], b.allowLabelsList["storageclasses"]), &storagev1.StorageClass{}, createStorageClassListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildPodStores() []cache.Store {
return b.buildStoresFunc(podMetricFamilies(b.allowAnnotationsList["pods"], b.allowLabelsList["pods"]), &v1.Pod{}, createPodListWatch, b.useAPIServerCache)
return b.buildStoresFunc(podMetricFamilies(b.allowAnnotationsList["pods"], b.allowLabelsList["pods"]), &v1.Pod{}, createPodListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildCsrStores() []cache.Store {
return b.buildStoresFunc(csrMetricFamilies(b.allowAnnotationsList["certificatesigningrequests"], b.allowLabelsList["certificatesigningrequests"]), &certv1.CertificateSigningRequest{}, createCSRListWatch, b.useAPIServerCache)
return b.buildStoresFunc(csrMetricFamilies(b.allowAnnotationsList["certificatesigningrequests"], b.allowLabelsList["certificatesigningrequests"]), &certv1.CertificateSigningRequest{}, createCSRListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildValidatingWebhookConfigurationStores() []cache.Store {
return b.buildStoresFunc(validatingWebhookConfigurationMetricFamilies, &admissionregistrationv1.ValidatingWebhookConfiguration{}, createValidatingWebhookConfigurationListWatch, b.useAPIServerCache)
return b.buildStoresFunc(validatingWebhookConfigurationMetricFamilies, &admissionregistrationv1.ValidatingWebhookConfiguration{}, createValidatingWebhookConfigurationListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildVolumeAttachmentStores() []cache.Store {
return b.buildStoresFunc(volumeAttachmentMetricFamilies, &storagev1.VolumeAttachment{}, createVolumeAttachmentListWatch, b.useAPIServerCache)
return b.buildStoresFunc(volumeAttachmentMetricFamilies, &storagev1.VolumeAttachment{}, createVolumeAttachmentListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildLeasesStores() []cache.Store {
return b.buildStoresFunc(leaseMetricFamilies, &coordinationv1.Lease{}, createLeaseListWatch, b.useAPIServerCache)
return b.buildStoresFunc(leaseMetricFamilies, &coordinationv1.Lease{}, createLeaseListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildClusterRoleStores() []cache.Store {
return b.buildStoresFunc(clusterRoleMetricFamilies(b.allowAnnotationsList["clusterroles"], b.allowLabelsList["clusterroles"]), &rbacv1.ClusterRole{}, createClusterRoleListWatch, b.useAPIServerCache)
return b.buildStoresFunc(clusterRoleMetricFamilies(b.allowAnnotationsList["clusterroles"], b.allowLabelsList["clusterroles"]), &rbacv1.ClusterRole{}, createClusterRoleListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildRoleStores() []cache.Store {
return b.buildStoresFunc(roleMetricFamilies(b.allowAnnotationsList["roles"], b.allowLabelsList["roles"]), &rbacv1.Role{}, createRoleListWatch, b.useAPIServerCache)
return b.buildStoresFunc(roleMetricFamilies(b.allowAnnotationsList["roles"], b.allowLabelsList["roles"]), &rbacv1.Role{}, createRoleListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildClusterRoleBindingStores() []cache.Store {
return b.buildStoresFunc(clusterRoleBindingMetricFamilies(b.allowAnnotationsList["clusterrolebindings"], b.allowLabelsList["clusterrolebindings"]), &rbacv1.ClusterRoleBinding{}, createClusterRoleBindingListWatch, b.useAPIServerCache)
return b.buildStoresFunc(clusterRoleBindingMetricFamilies(b.allowAnnotationsList["clusterrolebindings"], b.allowLabelsList["clusterrolebindings"]), &rbacv1.ClusterRoleBinding{}, createClusterRoleBindingListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildRoleBindingStores() []cache.Store {
return b.buildStoresFunc(roleBindingMetricFamilies(b.allowAnnotationsList["rolebindings"], b.allowLabelsList["rolebindings"]), &rbacv1.RoleBinding{}, createRoleBindingListWatch, b.useAPIServerCache)
return b.buildStoresFunc(roleBindingMetricFamilies(b.allowAnnotationsList["rolebindings"], b.allowLabelsList["rolebindings"]), &rbacv1.RoleBinding{}, createRoleBindingListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildIngressClassStores() []cache.Store {
return b.buildStoresFunc(ingressClassMetricFamilies(b.allowAnnotationsList["ingressclasses"], b.allowLabelsList["ingressclasses"]), &networkingv1.IngressClass{}, createIngressClassListWatch, b.useAPIServerCache)
return b.buildStoresFunc(ingressClassMetricFamilies(b.allowAnnotationsList["ingressclasses"], b.allowLabelsList["ingressclasses"]), &networkingv1.IngressClass{}, createIngressClassListWatch, b.useAPIServerCache, b.objectLimit)
}
func (b *Builder) buildStores(
metricFamilies []generator.FamilyGenerator,
expectedType interface{},
listWatchFunc func(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher,
useAPIServerCache bool,
useAPIServerCache bool, objectLimit int64,
) []cache.Store {
metricFamilies = generator.FilterFamilyGenerators(b.familyGeneratorFilter, metricFamilies)
composedMetricGenFuncs := generator.ComposeMetricGenFuncs(metricFamilies)
@ -521,7 +532,7 @@ func (b *Builder) buildStores(
klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter)
}
listWatcher := listWatchFunc(b.kubeClient, v1.NamespaceAll, b.fieldSelectorFilter)
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
b.startReflector(expectedType, store, listWatcher, useAPIServerCache, objectLimit)
return []cache.Store{store}
}
@ -535,7 +546,7 @@ func (b *Builder) buildStores(
klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter)
}
listWatcher := listWatchFunc(b.kubeClient, ns, b.fieldSelectorFilter)
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
b.startReflector(expectedType, store, listWatcher, useAPIServerCache, objectLimit)
stores = append(stores, store)
}
@ -547,7 +558,7 @@ func (b *Builder) buildCustomResourceStores(resourceName string,
metricFamilies []generator.FamilyGenerator,
expectedType interface{},
listWatchFunc func(customResourceClient interface{}, ns string, fieldSelector string) cache.ListerWatcher,
useAPIServerCache bool,
useAPIServerCache bool, objectLimit int64,
) []cache.Store {
metricFamilies = generator.FilterFamilyGenerators(b.familyGeneratorFilter, metricFamilies)
composedMetricGenFuncs := generator.ComposeMetricGenFuncs(metricFamilies)
@ -579,7 +590,7 @@ func (b *Builder) buildCustomResourceStores(resourceName string,
klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter)
}
listWatcher := listWatchFunc(customResourceClient, v1.NamespaceAll, b.fieldSelectorFilter)
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
b.startReflector(expectedType, store, listWatcher, useAPIServerCache, objectLimit)
return []cache.Store{store}
}
@ -591,7 +602,7 @@ func (b *Builder) buildCustomResourceStores(resourceName string,
)
klog.InfoS("FieldSelector is used", "fieldSelector", b.fieldSelectorFilter)
listWatcher := listWatchFunc(customResourceClient, ns, b.fieldSelectorFilter)
b.startReflector(expectedType, store, listWatcher, useAPIServerCache)
b.startReflector(expectedType, store, listWatcher, useAPIServerCache, objectLimit)
stores = append(stores, store)
}
@ -605,10 +616,15 @@ func (b *Builder) startReflector(
store cache.Store,
listWatcher cache.ListerWatcher,
useAPIServerCache bool,
objectLimit int64,
) {
instrumentedListWatch := watch.NewInstrumentedListerWatcher(listWatcher, b.listWatchMetrics, reflect.TypeOf(expectedType).String(), useAPIServerCache)
instrumentedListWatch := watch.NewInstrumentedListerWatcher(listWatcher, b.listWatchMetrics, reflect.TypeOf(expectedType).String(), useAPIServerCache, objectLimit)
reflector := cache.NewReflectorWithOptions(sharding.NewShardedListWatch(b.shard, b.totalShards, instrumentedListWatch), expectedType, store, cache.ReflectorOptions{ResyncPeriod: 0})
go reflector.Run(b.ctx.Done())
if cr, ok := expectedType.(*unstructured.Unstructured); ok {
go reflector.Run((*b.GVKToReflectorStopChanMap)[cr.GroupVersionKind().String()])
} else {
go reflector.Run(b.ctx.Done())
}
}
// cacheStoresToMetricStores converts []cache.Store into []*metricsstore.MetricsStore

View File

@ -131,7 +131,7 @@ func clusterRoleMetricFamilies(allowAnnotationsList, allowLabelsList []string) [
"",
wrapClusterRoleFunc(func(r *rbacv1.ClusterRole) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(r.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(r.ResourceVersion),
}
}),
),

View File

@ -133,7 +133,7 @@ func clusterRoleBindingMetricFamilies(allowAnnotationsList, allowLabelsList []st
"",
wrapClusterRoleBindingFunc(func(r *rbacv1.ClusterRoleBinding) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(r.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(r.ResourceVersion),
}
}),
),

View File

@ -127,7 +127,7 @@ func configMapMetricFamilies(allowAnnotationsList, allowLabelsList []string) []g
"",
wrapConfigMapFunc(func(c *v1.ConfigMap) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(c.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(c.ResourceVersion),
}
}),
),

View File

@ -273,7 +273,7 @@ func cronJobMetricFamilies(allowAnnotationsList, allowLabelsList []string) []gen
"",
wrapCronJobFunc(func(j *batchv1.CronJob) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(j.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(j.ResourceVersion),
}
}),
),
@ -358,7 +358,7 @@ func getNextScheduledTime(schedule string, lastScheduleTime *metav1.Time, create
sched, err := cron.ParseStandard(schedule)
if err != nil {
return time.Time{}, fmt.Errorf("Failed to parse cron job schedule '%s': %w", schedule, err)
return time.Time{}, fmt.Errorf("failed to parse cron job schedule '%s': %w", schedule, err)
}
if !lastScheduleTime.IsZero() {
return sched.Next(lastScheduleTime.Time), nil

View File

@ -217,7 +217,7 @@ func daemonSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) []g
{
LabelKeys: []string{},
LabelValues: []string{},
Value: float64(d.ObjectMeta.Generation),
Value: float64(d.Generation),
},
},
}

View File

@ -41,6 +41,23 @@ var (
descDeploymentLabelsDefaultLabels = []string{"namespace", "deployment"}
)
// Reasons copied from kubernetes/pkg/controller/deployment/deployment_utils.go.
var (
allowedDeploymentReasons = map[string]struct{}{
"ReplicaSetUpdated": {},
"ReplicaSetCreateError": {},
"NewReplicaSetCreated": {},
"FoundNewReplicaSet": {},
"NewReplicaSetAvailable": {},
"ProgressDeadlineExceeded": {},
"DeploymentPaused": {},
"DeploymentResumed": {},
"MinimumReplicasAvailable": {},
"MinimumReplicasUnavailable": {},
"": {},
}
)
func deploymentMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator {
return []generator.FamilyGenerator{
*generator.NewFamilyGeneratorWithStability(
@ -174,8 +191,13 @@ func deploymentMetricFamilies(allowAnnotationsList, allowLabelsList []string) []
for j, m := range conditionMetrics {
metric := m
metric.LabelKeys = []string{"condition", "status"}
metric.LabelValues = append([]string{string(c.Type)}, metric.LabelValues...)
reason := c.Reason
if _, ok := allowedDeploymentReasons[reason]; !ok {
reason = "unknown"
}
metric.LabelKeys = []string{"reason", "condition", "status"}
metric.LabelValues = append([]string{reason, string(c.Type)}, metric.LabelValues...)
ms[i*len(conditionStatuses)+j] = metric
}
}
@ -277,7 +299,7 @@ func deploymentMetricFamilies(allowAnnotationsList, allowLabelsList []string) []
return &metric.Family{
Metrics: []*metric.Metric{
{
Value: float64(d.ObjectMeta.Generation),
Value: float64(d.Generation),
},
},
}

View File

@ -31,6 +31,7 @@ import (
var (
depl1Replicas int32 = 200
depl2Replicas int32 = 5
depl3Replicas int32 = 1
depl1MaxUnavailable = intstr.FromInt(10)
depl2MaxUnavailable = intstr.FromString("25%")
@ -98,8 +99,8 @@ func TestDeploymentStore(t *testing.T) {
UpdatedReplicas: 2,
ObservedGeneration: 111,
Conditions: []v1.DeploymentCondition{
{Type: v1.DeploymentAvailable, Status: corev1.ConditionTrue},
{Type: v1.DeploymentProgressing, Status: corev1.ConditionTrue},
{Type: v1.DeploymentAvailable, Status: corev1.ConditionTrue, Reason: "MinimumReplicasAvailable"},
{Type: v1.DeploymentProgressing, Status: corev1.ConditionTrue, Reason: "NewReplicaSetAvailable"},
},
},
Spec: v1.DeploymentSpec{
@ -126,12 +127,12 @@ func TestDeploymentStore(t *testing.T) {
kube_deployment_status_replicas_updated{deployment="depl1",namespace="ns1"} 2
kube_deployment_status_replicas{deployment="depl1",namespace="ns1"} 15
kube_deployment_status_replicas_ready{deployment="depl1",namespace="ns1"} 10
kube_deployment_status_condition{deployment="depl1",namespace="ns1",condition="Available",status="true"} 1
kube_deployment_status_condition{deployment="depl1",namespace="ns1",condition="Progressing",status="true"} 1
kube_deployment_status_condition{deployment="depl1",namespace="ns1",condition="Available",status="false"} 0
kube_deployment_status_condition{deployment="depl1",namespace="ns1",condition="Progressing",status="false"} 0
kube_deployment_status_condition{deployment="depl1",namespace="ns1",condition="Available",status="unknown"} 0
kube_deployment_status_condition{deployment="depl1",namespace="ns1",condition="Progressing",status="unknown"} 0
kube_deployment_status_condition{condition="Available",deployment="depl1",namespace="ns1",reason="MinimumReplicasAvailable",status="true"} 1
kube_deployment_status_condition{condition="Available",deployment="depl1",namespace="ns1",reason="MinimumReplicasAvailable",status="false"} 0
kube_deployment_status_condition{condition="Available",deployment="depl1",namespace="ns1",reason="MinimumReplicasAvailable",status="unknown"} 0
kube_deployment_status_condition{condition="Progressing",deployment="depl1",namespace="ns1",reason="NewReplicaSetAvailable",status="true"} 1
kube_deployment_status_condition{condition="Progressing",deployment="depl1",namespace="ns1",reason="NewReplicaSetAvailable",status="false"} 0
kube_deployment_status_condition{condition="Progressing",deployment="depl1",namespace="ns1",reason="NewReplicaSetAvailable",status="unknown"} 0
`,
},
{
@ -152,9 +153,9 @@ func TestDeploymentStore(t *testing.T) {
UpdatedReplicas: 1,
ObservedGeneration: 1111,
Conditions: []v1.DeploymentCondition{
{Type: v1.DeploymentAvailable, Status: corev1.ConditionFalse},
{Type: v1.DeploymentProgressing, Status: corev1.ConditionFalse},
{Type: v1.DeploymentReplicaFailure, Status: corev1.ConditionTrue},
{Type: v1.DeploymentAvailable, Status: corev1.ConditionFalse, Reason: "MinimumReplicasUnavailable"},
{Type: v1.DeploymentProgressing, Status: corev1.ConditionFalse, Reason: "ProgressDeadlineExceeded"},
{Type: v1.DeploymentReplicaFailure, Status: corev1.ConditionTrue, Reason: "ReplicaSetCreateError"},
},
},
Spec: v1.DeploymentSpec{
@ -180,15 +181,49 @@ func TestDeploymentStore(t *testing.T) {
kube_deployment_status_replicas_updated{deployment="depl2",namespace="ns2"} 1
kube_deployment_status_replicas{deployment="depl2",namespace="ns2"} 10
kube_deployment_status_replicas_ready{deployment="depl2",namespace="ns2"} 5
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="Available",status="true"} 0
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="Progressing",status="true"} 0
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="ReplicaFailure",status="true"} 1
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="Available",status="false"} 1
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="Progressing",status="false"} 1
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="ReplicaFailure",status="false"} 0
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="Available",status="unknown"} 0
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="Progressing",status="unknown"} 0
kube_deployment_status_condition{deployment="depl2",namespace="ns2",condition="ReplicaFailure",status="unknown"} 0
kube_deployment_status_condition{condition="Available",deployment="depl2",namespace="ns2",reason="MinimumReplicasUnavailable",status="true"} 0
kube_deployment_status_condition{condition="Available",deployment="depl2",namespace="ns2",reason="MinimumReplicasUnavailable",status="false"} 1
kube_deployment_status_condition{condition="Available",deployment="depl2",namespace="ns2",reason="MinimumReplicasUnavailable",status="unknown"} 0
kube_deployment_status_condition{condition="Progressing",deployment="depl2",namespace="ns2",reason="ProgressDeadlineExceeded",status="true"} 0
kube_deployment_status_condition{condition="Progressing",deployment="depl2",namespace="ns2",reason="ProgressDeadlineExceeded",status="false"} 1
kube_deployment_status_condition{condition="Progressing",deployment="depl2",namespace="ns2",reason="ProgressDeadlineExceeded",status="unknown"} 0
kube_deployment_status_condition{condition="ReplicaFailure",deployment="depl2",namespace="ns2",reason="ReplicaSetCreateError",status="true"} 1
kube_deployment_status_condition{condition="ReplicaFailure",deployment="depl2",namespace="ns2",reason="ReplicaSetCreateError",status="false"} 0
kube_deployment_status_condition{condition="ReplicaFailure",deployment="depl2",namespace="ns2",reason="ReplicaSetCreateError",status="unknown"} 0
`,
},
{
Obj: &v1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "depl3",
Namespace: "ns3",
},
Status: v1.DeploymentStatus{
Conditions: []v1.DeploymentCondition{
{Type: v1.DeploymentAvailable, Status: corev1.ConditionFalse, Reason: "ThisReasonIsNotAllowed"},
{Type: v1.DeploymentProgressing, Status: corev1.ConditionTrue},
},
},
Spec: v1.DeploymentSpec{
Replicas: &depl3Replicas,
},
},
Want: metadata + `
kube_deployment_metadata_generation{deployment="depl3",namespace="ns3"} 0
kube_deployment_spec_paused{deployment="depl3",namespace="ns3"} 0
kube_deployment_spec_replicas{deployment="depl3",namespace="ns3"} 1
kube_deployment_status_condition{condition="Available",deployment="depl3",namespace="ns3",reason="unknown",status="true"} 0
kube_deployment_status_condition{condition="Available",deployment="depl3",namespace="ns3",reason="unknown",status="false"} 1
kube_deployment_status_condition{condition="Available",deployment="depl3",namespace="ns3",reason="unknown",status="unknown"} 0
kube_deployment_status_observed_generation{deployment="depl3",namespace="ns3"} 0
kube_deployment_status_replicas{deployment="depl3",namespace="ns3"} 0
kube_deployment_status_replicas_available{deployment="depl3",namespace="ns3"} 0
kube_deployment_status_replicas_ready{deployment="depl3",namespace="ns3"} 0
kube_deployment_status_replicas_unavailable{deployment="depl3",namespace="ns3"} 0
kube_deployment_status_replicas_updated{deployment="depl3",namespace="ns3"} 0
kube_deployment_status_condition{condition="Progressing",deployment="depl3",namespace="ns3",reason="",status="false"} 0
kube_deployment_status_condition{condition="Progressing",deployment="depl3",namespace="ns3",reason="",status="true"} 1
kube_deployment_status_condition{condition="Progressing",deployment="depl3",namespace="ns3",reason="",status="unknown"} 0
`,
},
}

View File

@ -134,7 +134,7 @@ func createHPAMetaDataGeneration() generator.FamilyGenerator {
return &metric.Family{
Metrics: []*metric.Metric{
{
Value: float64(a.ObjectMeta.Generation),
Value: float64(a.Generation),
},
},
}

View File

@ -140,7 +140,7 @@ func ingressMetricFamilies(allowAnnotationsList, allowLabelsList []string) []gen
"",
wrapIngressFunc(func(i *networkingv1.Ingress) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(i.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(i.ResourceVersion),
}
}),
),
@ -155,10 +155,14 @@ func ingressMetricFamilies(allowAnnotationsList, allowLabelsList []string) []gen
for _, rule := range i.Spec.Rules {
if rule.HTTP != nil {
for _, path := range rule.HTTP.Paths {
pathType := ""
if path.PathType != nil {
pathType = string(*path.PathType)
}
if path.Backend.Service != nil {
ms = append(ms, &metric.Metric{
LabelKeys: []string{"host", "path", "service_name", "service_port"},
LabelValues: []string{rule.Host, path.Path, path.Backend.Service.Name, strconv.Itoa(int(path.Backend.Service.Port.Number))},
LabelKeys: []string{"host", "path", "path_type", "service_name", "service_port"},
LabelValues: []string{rule.Host, path.Path, pathType, path.Backend.Service.Name, strconv.Itoa(int(path.Backend.Service.Port.Number))},
Value: 1,
})
} else {
@ -167,8 +171,8 @@ func ingressMetricFamilies(allowAnnotationsList, allowLabelsList []string) []gen
apiGroup = *path.Backend.Resource.APIGroup
}
ms = append(ms, &metric.Metric{
LabelKeys: []string{"host", "path", "resource_api_group", "resource_kind", "resource_name"},
LabelValues: []string{rule.Host, path.Path, apiGroup, path.Backend.Resource.Kind, path.Backend.Resource.Name},
LabelKeys: []string{"host", "path", "path_type", "resource_api_group", "resource_kind", "resource_name"},
LabelValues: []string{rule.Host, path.Path, pathType, apiGroup, path.Backend.Resource.Kind, path.Backend.Resource.Name},
Value: 1,
})
}

View File

@ -22,6 +22,7 @@ import (
v1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
)
@ -141,6 +142,7 @@ func TestIngressStore(t *testing.T) {
},
},
},
PathType: ptr.To(networkingv1.PathTypeExact),
},
{
Path: "/somepath2",
@ -164,8 +166,8 @@ func TestIngressStore(t *testing.T) {
Want: metadata + `
kube_ingress_info{namespace="ns4",ingress="ingress4",ingressclass="_default"} 1
kube_ingress_created{namespace="ns4",ingress="ingress4"} 1.501569018e+09
kube_ingress_path{namespace="ns4",ingress="ingress4",host="somehost",path="/somepath",service_name="someservice",service_port="1234"} 1
kube_ingress_path{namespace="ns4",ingress="ingress4",host="somehost",path="/somepath2",resource_api_group="",resource_kind="somekind",resource_name="somename"} 1
kube_ingress_path{namespace="ns4",ingress="ingress4",host="somehost",path="/somepath",path_type="Exact",service_name="someservice",service_port="1234"} 1
kube_ingress_path{namespace="ns4",ingress="ingress4",host="somehost",path="/somepath2",path_type="",resource_api_group="",resource_kind="somekind",resource_name="somename"} 1
`,
MetricNames: []string{"kube_ingress_info", "kube_ingress_metadata_resource_version", "kube_ingress_created", "kube_ingress_labels", "kube_ingress_path", "kube_ingress_tls"},
},

View File

@ -78,7 +78,7 @@ var (
"",
wrapMutatingWebhookConfigurationFunc(func(mwc *admissionregistrationv1.MutatingWebhookConfiguration) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(mwc.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(mwc.ResourceVersion),
}
}),
),

View File

@ -243,50 +243,50 @@ func createPersistentVolumeInfo() generator.FamilyGenerator {
)
switch {
case p.Spec.PersistentVolumeSource.GCEPersistentDisk != nil:
gcePDDiskName = p.Spec.PersistentVolumeSource.GCEPersistentDisk.PDName
case p.Spec.PersistentVolumeSource.AWSElasticBlockStore != nil:
ebsVolumeID = p.Spec.PersistentVolumeSource.AWSElasticBlockStore.VolumeID
case p.Spec.PersistentVolumeSource.AzureDisk != nil:
azureDiskName = p.Spec.PersistentVolumeSource.AzureDisk.DiskName
case p.Spec.PersistentVolumeSource.FC != nil:
if p.Spec.PersistentVolumeSource.FC.Lun != nil {
fcLun = strconv.FormatInt(int64(*p.Spec.PersistentVolumeSource.FC.Lun), 10)
case p.Spec.GCEPersistentDisk != nil:
gcePDDiskName = p.Spec.GCEPersistentDisk.PDName
case p.Spec.AWSElasticBlockStore != nil:
ebsVolumeID = p.Spec.AWSElasticBlockStore.VolumeID
case p.Spec.AzureDisk != nil:
azureDiskName = p.Spec.AzureDisk.DiskName
case p.Spec.FC != nil:
if p.Spec.FC.Lun != nil {
fcLun = strconv.FormatInt(int64(*p.Spec.FC.Lun), 10)
}
for _, wwn := range p.Spec.PersistentVolumeSource.FC.TargetWWNs {
for _, wwn := range p.Spec.FC.TargetWWNs {
if len(fcTargetWWNs) != 0 {
fcTargetWWNs += ","
}
fcTargetWWNs += wwn
}
for _, wwid := range p.Spec.PersistentVolumeSource.FC.WWIDs {
for _, wwid := range p.Spec.FC.WWIDs {
if len(fcWWIDs) != 0 {
fcWWIDs += ","
}
fcWWIDs += wwid
}
case p.Spec.PersistentVolumeSource.ISCSI != nil:
iscsiTargetPortal = p.Spec.PersistentVolumeSource.ISCSI.TargetPortal
iscsiIQN = p.Spec.PersistentVolumeSource.ISCSI.IQN
iscsiLun = strconv.FormatInt(int64(p.Spec.PersistentVolumeSource.ISCSI.Lun), 10)
if p.Spec.PersistentVolumeSource.ISCSI.InitiatorName != nil {
iscsiInitiatorName = *p.Spec.PersistentVolumeSource.ISCSI.InitiatorName
case p.Spec.ISCSI != nil:
iscsiTargetPortal = p.Spec.ISCSI.TargetPortal
iscsiIQN = p.Spec.ISCSI.IQN
iscsiLun = strconv.FormatInt(int64(p.Spec.ISCSI.Lun), 10)
if p.Spec.ISCSI.InitiatorName != nil {
iscsiInitiatorName = *p.Spec.ISCSI.InitiatorName
}
case p.Spec.PersistentVolumeSource.NFS != nil:
nfsServer = p.Spec.PersistentVolumeSource.NFS.Server
nfsPath = p.Spec.PersistentVolumeSource.NFS.Path
case p.Spec.PersistentVolumeSource.CSI != nil:
csiDriver = p.Spec.PersistentVolumeSource.CSI.Driver
csiVolumeHandle = p.Spec.PersistentVolumeSource.CSI.VolumeHandle
case p.Spec.PersistentVolumeSource.Local != nil:
localPath = p.Spec.PersistentVolumeSource.Local.Path
if p.Spec.PersistentVolumeSource.Local.FSType != nil {
localFS = *p.Spec.PersistentVolumeSource.Local.FSType
case p.Spec.NFS != nil:
nfsServer = p.Spec.NFS.Server
nfsPath = p.Spec.NFS.Path
case p.Spec.CSI != nil:
csiDriver = p.Spec.CSI.Driver
csiVolumeHandle = p.Spec.CSI.VolumeHandle
case p.Spec.Local != nil:
localPath = p.Spec.Local.Path
if p.Spec.Local.FSType != nil {
localFS = *p.Spec.Local.FSType
}
case p.Spec.PersistentVolumeSource.HostPath != nil:
hostPath = p.Spec.PersistentVolumeSource.HostPath.Path
if p.Spec.PersistentVolumeSource.HostPath.Type != nil {
hostPathType = string(*p.Spec.PersistentVolumeSource.HostPath.Type)
case p.Spec.HostPath != nil:
hostPath = p.Spec.HostPath.Path
if p.Spec.HostPath.Type != nil {
hostPathType = string(*p.Spec.HostPath.Type)
}
}
@ -313,6 +313,7 @@ func createPersistentVolumeInfo() generator.FamilyGenerator {
"local_fs",
"host_path",
"host_path_type",
"reclaim_policy",
},
LabelValues: []string{
p.Spec.StorageClassName,
@ -334,6 +335,7 @@ func createPersistentVolumeInfo() generator.FamilyGenerator {
localFS,
hostPath,
hostPathType,
string(p.Spec.PersistentVolumeReclaimPolicy),
},
Value: 1,
},
@ -428,11 +430,12 @@ func createPersistentVolumeCSIAttributes() generator.FamilyGenerator {
}
var csiMounter, csiMapOptions string
for k, v := range p.Spec.PersistentVolumeSource.CSI.VolumeAttributes {
for k, v := range p.Spec.CSI.VolumeAttributes {
// storage attributes handled by external CEPH CSI driver
if k == "mapOptions" {
switch k {
case "mapOptions":
csiMapOptions = v
} else if k == "mounter" {
case "mounter":
csiMounter = v
}
}

View File

@ -31,6 +31,7 @@ import (
func TestPersistentVolumeStore(t *testing.T) {
iscsiInitiatorName := "iqn.my.test.initiator:112233"
volumeMode := v1.PersistentVolumeBlock
var reclaimPolicy v1.PersistentVolumeReclaimPolicy = "Retain"
cases := []generateMetricsTestCase{
// Verify phase enumerations.
{
@ -166,6 +167,9 @@ func TestPersistentVolumeStore(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: "test-pv-available",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: reclaimPolicy,
},
Status: v1.PersistentVolumeStatus{
Phase: v1.VolumeAvailable,
},
@ -173,7 +177,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="Retain",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -192,7 +196,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -215,7 +219,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="name",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="name",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -238,7 +242,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="aws://eu-west-1c/vol-012d34d567890123b",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="aws://eu-west-1c/vol-012d34d567890123b",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -261,7 +265,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="azure_disk_1",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="azure_disk_1",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -285,7 +289,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="123",fc_target_wwns="0123456789abcdef,abcdef0123456789",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="123",fc_target_wwns="0123456789abcdef,abcdef0123456789",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -308,7 +312,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="0123456789abcdef,abcdef0123456789",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="0123456789abcdef,abcdef0123456789",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -333,7 +337,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="iqn.my.test.server.target00",iscsi_lun="123",iscsi_target_portal="1.2.3.4:3260",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="iqn.my.test.server.target00",iscsi_lun="123",iscsi_target_portal="1.2.3.4:3260",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -359,7 +363,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="iqn.my.test.initiator:112233",iscsi_iqn="iqn.my.test.server.target00",iscsi_lun="123",iscsi_target_portal="1.2.3.4:3260",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="iqn.my.test.initiator:112233",iscsi_iqn="iqn.my.test.server.target00",iscsi_lun="123",iscsi_target_portal="1.2.3.4:3260",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -383,7 +387,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="/myPath",nfs_server="1.2.3.4",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="/myPath",nfs_server="1.2.3.4",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -407,7 +411,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="test-driver",csi_volume_handle="test-volume-handle",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="test-driver",csi_volume_handle="test-volume-handle",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -431,7 +435,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="/mnt/data",local_fs="ext4",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="/mnt/data",local_fs="ext4",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -454,7 +458,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="/mnt/data",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="/mnt/data",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -478,7 +482,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="/mnt/data",host_path_type="Directory",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="/mnt/data",host_path_type="Directory",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},
@ -501,7 +505,7 @@ func TestPersistentVolumeStore(t *testing.T) {
Want: `
# HELP kube_persistentvolume_info [STABLE] Information about persistentvolume.
# TYPE kube_persistentvolume_info gauge
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="/mnt/data",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",storageclass=""} 1
kube_persistentvolume_info{azure_disk_name="",ebs_volume_id="",fc_lun="",fc_target_wwns="",fc_wwids="",gce_persistent_disk_name="",host_path="/mnt/data",host_path_type="",iscsi_initiator_name="",iscsi_iqn="",iscsi_lun="",iscsi_target_portal="",local_path="",local_fs="",nfs_path="",nfs_server="",csi_driver="",csi_volume_handle="",persistentvolume="test-pv-available",reclaim_policy="",storageclass=""} 1
`,
MetricNames: []string{"kube_persistentvolume_info"},
},

View File

@ -92,6 +92,7 @@ func podMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generat
createPodStatusScheduledFamilyGenerator(),
createPodStatusScheduledTimeFamilyGenerator(),
createPodStatusUnschedulableFamilyGenerator(),
createPodStatusUnscheduledTimeFamilyGenerator(),
createPodTolerationsFamilyGenerator(),
createPodNodeSelectorsFamilyGenerator(),
createPodServiceAccountFamilyGenerator(),
@ -1541,15 +1542,12 @@ func createPodStatusReasonFamilyGenerator() generator.FamilyGenerator {
ms := []*metric.Metric{}
for _, reason := range podStatusReasons {
metric := &metric.Metric{}
metric.LabelKeys = []string{"reason"}
metric.LabelValues = []string{reason}
if p.Status.Reason == reason {
metric.Value = boolFloat64(true)
} else {
metric.Value = boolFloat64(false)
m := &metric.Metric{
LabelKeys: []string{"reason"},
LabelValues: []string{reason},
Value: getPodStatusReasonValue(p, reason),
}
ms = append(ms, metric)
ms = append(ms, m)
}
return &metric.Family{
@ -1559,6 +1557,23 @@ func createPodStatusReasonFamilyGenerator() generator.FamilyGenerator {
)
}
func getPodStatusReasonValue(p *v1.Pod, reason string) float64 {
if p.Status.Reason == reason {
return 1
}
for _, cond := range p.Status.Conditions {
if cond.Reason == reason {
return 1
}
}
for _, cs := range p.Status.ContainerStatuses {
if cs.State.Terminated != nil && cs.State.Terminated.Reason == reason {
return 1
}
}
return 0
}
func createPodStatusScheduledFamilyGenerator() generator.FamilyGenerator {
return *generator.NewFamilyGeneratorWithStability(
"kube_pod_status_scheduled",
@ -1642,6 +1657,33 @@ func createPodStatusUnschedulableFamilyGenerator() generator.FamilyGenerator {
)
}
func createPodStatusUnscheduledTimeFamilyGenerator() generator.FamilyGenerator {
return *generator.NewFamilyGeneratorWithStability(
"kube_pod_status_unscheduled_time",
"Unix timestamp when pod moved into unscheduled status",
metric.Gauge,
basemetrics.ALPHA,
"",
wrapPodFunc(func(p *v1.Pod) *metric.Family {
ms := []*metric.Metric{}
for _, c := range p.Status.Conditions {
if c.Type == v1.PodScheduled && c.Status == v1.ConditionFalse {
ms = append(ms, &metric.Metric{
LabelKeys: []string{},
LabelValues: []string{},
Value: float64(c.LastTransitionTime.Unix()),
})
}
}
return &metric.Family{
Metrics: ms,
}
}),
)
}
// getUniqueTolerations takes an array
func getUniqueTolerations(tolerations []v1.Toleration) []v1.Toleration {
uniqueTolerationsMap := make(map[v1.Toleration]struct{})

View File

@ -2282,7 +2282,7 @@ func BenchmarkPodStore(b *testing.B) {
},
}
expectedFamilies := 54
expectedFamilies := 55
for n := 0; n < b.N; n++ {
families := f(pod)
if len(families) != expectedFamilies {
@ -2290,3 +2290,85 @@ func BenchmarkPodStore(b *testing.B) {
}
}
}
func TestGetPodStatusReasonValue(t *testing.T) {
reason := "TestReason"
tests := []struct {
name string
pod *v1.Pod
want float64
}{
{
name: "matches Status.Reason",
pod: &v1.Pod{
Status: v1.PodStatus{
Reason: "TestReason",
},
},
want: 1,
},
{
name: "matches condition Reason",
pod: &v1.Pod{
Status: v1.PodStatus{
Conditions: []v1.PodCondition{
{
Reason: "TestReason",
},
},
},
},
want: 1,
},
{
name: "matches container terminated Reason",
pod: &v1.Pod{
Status: v1.PodStatus{
ContainerStatuses: []v1.ContainerStatus{
{
State: v1.ContainerState{
Terminated: &v1.ContainerStateTerminated{
Reason: "TestReason",
},
},
},
},
},
},
want: 1,
},
{
name: "no match returns 0",
pod: &v1.Pod{
Status: v1.PodStatus{
Reason: "OtherReason",
Conditions: []v1.PodCondition{
{
Reason: "NotTestReason",
},
},
ContainerStatuses: []v1.ContainerStatus{
{
State: v1.ContainerState{
Terminated: &v1.ContainerStateTerminated{
Reason: "AnotherReason",
},
},
},
},
},
},
want: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := getPodStatusReasonValue(tt.pod, reason)
if got != tt.want {
t.Errorf("getPodStatusReasonValue() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -158,7 +158,7 @@ func replicaSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) []
return &metric.Family{
Metrics: []*metric.Metric{
{
Value: float64(r.ObjectMeta.Generation),
Value: float64(r.Generation),
},
},
}

View File

@ -166,7 +166,7 @@ var (
return &metric.Family{
Metrics: []*metric.Metric{
{
Value: float64(r.ObjectMeta.Generation),
Value: float64(r.Generation),
},
},
}

View File

@ -131,7 +131,7 @@ func roleMetricFamilies(allowAnnotationsList, allowLabelsList []string) []genera
"",
wrapRoleFunc(func(r *rbacv1.Role) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(r.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(r.ResourceVersion),
}
}),
),

View File

@ -133,7 +133,7 @@ func roleBindingMetricFamilies(allowAnnotationsList, allowLabelsList []string) [
"",
wrapRoleBindingFunc(func(r *rbacv1.RoleBinding) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(r.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(r.ResourceVersion),
}
}),
),

View File

@ -150,7 +150,7 @@ func secretMetricFamilies(allowAnnotationsList, allowLabelsList []string) []gene
"",
wrapSecretFunc(func(s *v1.Secret) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(s.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(s.ResourceVersion),
}
}),
),

View File

@ -208,7 +208,7 @@ func statefulSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) [
return &metric.Family{
Metrics: []*metric.Metric{
{
Value: float64(s.ObjectMeta.Generation),
Value: float64(s.Generation),
},
},
}

View File

@ -257,7 +257,7 @@ func TestKubeLabelsToPrometheusLabels(t *testing.T) {
}
for i := range tc.expectKeys {
if !(tc.expectKeys[i] == labelKeys[i] && tc.expectValues[i] == labelValues[i]) {
if tc.expectKeys[i] != labelKeys[i] || tc.expectValues[i] != labelValues[i] {
t.Errorf("Got Prometheus label %q: %q but expected %q: %q", labelKeys[i], labelValues[i], tc.expectKeys[i], tc.expectValues[i])
}
}

View File

@ -78,7 +78,7 @@ var (
"",
wrapValidatingWebhookConfigurationFunc(func(vwc *admissionregistrationv1.ValidatingWebhookConfiguration) *metric.Family {
return &metric.Family{
Metrics: resourceVersionMetric(vwc.ObjectMeta.ResourceVersion),
Metrics: resourceVersionMetric(vwc.ResourceVersion),
}
}),
),

View File

@ -25,8 +25,8 @@ import (
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
"k8s.io/klog/v2"
yaml "sigs.k8s.io/yaml/goyaml.v3"
"k8s.io/kube-state-metrics/v2/pkg/app"
"k8s.io/kube-state-metrics/v2/pkg/options"

View File

@ -18,13 +18,24 @@ package allowdenylist
import (
"errors"
"regexp"
"strings"
"sync"
"time"
regexp "github.com/dlclark/regexp2"
"k8s.io/klog/v2"
generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
)
// AllowDenyList encapsulates the logic needed to filter based on a string.
// Use ECMAScript as the default regexp spec to support lookarounds (#2594).
var (
once sync.Once
regexpDefaultSpec regexp.RegexOptions = regexp.ECMAScript
regexpDefaultTimeout = time.Minute
)
// AllowDenyList namespaceencapsulates the logic needed to filter based on a string.
type AllowDenyList struct {
list map[string]struct{}
rList []*regexp.Regexp
@ -34,6 +45,9 @@ type AllowDenyList struct {
// New constructs a new AllowDenyList based on a allow- and a
// denylist. Only one of them can be not empty.
func New(allow, deny map[string]struct{}) (*AllowDenyList, error) {
once.Do(func() {
regexp.DefaultMatchTimeout = regexpDefaultTimeout
})
if len(allow) != 0 && len(deny) != 0 {
return nil, errors.New(
"allowlist and denylist are both set, they are mutually exclusive, only one of them can be set",
@ -62,7 +76,7 @@ func New(allow, deny map[string]struct{}) (*AllowDenyList, error) {
func (l *AllowDenyList) Parse() error {
regexes := make([]*regexp.Regexp, 0, len(l.list))
for item := range l.list {
r, err := regexp.Compile(item)
r, err := regexp.Compile(item, regexpDefaultSpec)
if err != nil {
return err
}
@ -99,25 +113,36 @@ func (l *AllowDenyList) Exclude(items []string) {
}
// IsIncluded returns if the given item is included.
func (l *AllowDenyList) IsIncluded(item string) bool {
var matched bool
func (l *AllowDenyList) IsIncluded(item string) (bool, error) {
var (
matched bool
err error
)
for _, r := range l.rList {
matched = r.MatchString(item)
matched, err = r.MatchString(item)
if err != nil {
return false, err
}
if matched {
break
}
}
if l.isAllowList {
return matched
return matched, nil
}
return !matched
return !matched, nil
}
// IsExcluded returns if the given item is excluded.
func (l *AllowDenyList) IsExcluded(item string) bool {
return !l.IsIncluded(item)
func (l *AllowDenyList) IsExcluded(item string) (bool, error) {
isIncluded, err := l.IsIncluded(item)
if err != nil {
return false, err
}
return !isIncluded, nil
}
// Status returns the status of the AllowDenyList that can e.g. be passed into
@ -137,7 +162,13 @@ func (l *AllowDenyList) Status() string {
// Test returns if the given family generator passes (is included in) the AllowDenyList
func (l *AllowDenyList) Test(generator generator.FamilyGenerator) bool {
return l.IsIncluded(generator.Name)
isIncluded, err := l.IsIncluded(generator.Name)
if err != nil {
klog.ErrorS(err, "Error while processing allow-deny entries for generator", "generator", generator.Name)
return false
}
return isIncluded
}
func copyList(l map[string]struct{}) map[string]struct{} {

View File

@ -17,8 +17,12 @@ limitations under the License.
package allowdenylist
import (
"regexp"
"fmt"
"strings"
"testing"
"time"
regexp "github.com/dlclark/regexp2"
)
func TestNew(t *testing.T) {
@ -76,7 +80,11 @@ func TestInclude(t *testing.T) {
t.Fatal("expected Parse() to not fail")
}
if !allowlist.IsIncluded("item1") {
isIncluded, err := allowlist.IsIncluded("item1")
if err != nil {
t.Fatal("expected IsIncluded() to not fail")
}
if !isIncluded {
t.Fatal("expected included item to be included")
}
})
@ -93,7 +101,11 @@ func TestInclude(t *testing.T) {
t.Fatalf("expected Parse() to not fail, but got error : %v", err)
}
if !denylist.IsIncluded(item1) {
isIncluded, err := denylist.IsIncluded(item1)
if err != nil {
t.Fatal("expected IsIncluded() to not fail")
}
if !isIncluded {
t.Fatal("expected included item to be included")
}
})
@ -103,13 +115,17 @@ func TestInclude(t *testing.T) {
t.Fatal("expected New() to not fail")
}
allowlist.Include([]string{"kube_.*_info"})
allowlist.Include([]string{"kube_(?=secret).*_info"})
err = allowlist.Parse()
if err != nil {
t.Fatalf("expected Parse() to not fail, but got error : %v", err)
}
if !allowlist.IsIncluded("kube_secret_info") {
isIncluded, err := allowlist.IsIncluded("kube_secret_info")
if err != nil {
t.Fatal("expected IsIncluded() to not fail")
}
if !isIncluded {
t.Fatal("expected included item to be included")
}
})
@ -124,22 +140,38 @@ func TestInclude(t *testing.T) {
t.Fatal("expected New() to not fail")
}
denylist.Exclude([]string{"kube_node_.*_cores", "kube_pod_.*_bytes"})
denylist.Exclude([]string{"kube_(?=node.*cores|pod.*bytes)"})
err = denylist.Parse()
if err != nil {
t.Fatalf("expected Parse() to not fail, but got error : %v", err)
}
if denylist.IsExcluded(item1) {
isExcluded, err := denylist.IsExcluded(item1)
if err != nil {
t.Fatal("expected IsExcluded() to not fail")
}
if isExcluded {
t.Fatalf("expected included %s to be included", item1)
}
if denylist.IsIncluded(item2) {
isIncluded, err := denylist.IsIncluded(item2)
if err != nil {
t.Fatal("expected IsIncluded() to not fail")
}
if isIncluded {
t.Fatalf("expected included %s to be excluded", item2)
}
if denylist.IsIncluded(item3) {
isIncluded, err = denylist.IsIncluded(item3)
if err != nil {
t.Fatal("expected IsIncluded() to not fail")
}
if isIncluded {
t.Fatalf("expected included %s to be excluded", item3)
}
if denylist.IsExcluded(item4) {
isExcluded, err = denylist.IsExcluded(item4)
if err != nil {
t.Fatal("expected IsExcluded() to not fail")
}
if isExcluded {
t.Fatalf("expected included %s to be included", item4)
}
})
@ -159,7 +191,11 @@ func TestExclude(t *testing.T) {
t.Fatalf("expected Parse() to not fail, but got error : %v", err)
}
if allowlist.IsIncluded(item1) {
isIncluded, err := allowlist.IsIncluded(item1)
if err != nil {
t.Fatal("expected IsIncluded() to not fail")
}
if isIncluded {
t.Fatal("expected excluded item to be excluded")
}
})
@ -176,7 +212,11 @@ func TestExclude(t *testing.T) {
t.Fatalf("expected Parse() to not fail, but got error : %v", err)
}
if denylist.IsIncluded(item1) {
isIncluded, err := denylist.IsIncluded(item1)
if err != nil {
t.Fatal("expected IsIncluded() to not fail")
}
if isIncluded {
t.Fatal("expected excluded item to be excluded")
}
})
@ -224,7 +264,8 @@ func TestStatus(t *testing.T) {
allowlist, _ := New(map[string]struct{}{item1: {}, item2: {}}, map[string]struct{}{})
actualStatusString := allowlist.Status()
expectedRegexPattern := `^Including the following lists that were on allowlist: (item1|item2), (item2|item1)$`
matched, _ := regexp.MatchString(expectedRegexPattern, actualStatusString)
re := regexp.MustCompile(expectedRegexPattern, regexpDefaultSpec)
matched, _ := re.MatchString(actualStatusString)
if !matched {
t.Errorf("expected status %q but got %q", expectedRegexPattern, actualStatusString)
}
@ -244,9 +285,38 @@ func TestStatus(t *testing.T) {
denylist, _ := New(map[string]struct{}{}, map[string]struct{}{item1: {}, item2: {}})
actualStatusString := denylist.Status()
expectedRegexPattern := `^Excluding the following lists that were on denylist: (item1|item2), (item2|item1)$`
matched, _ := regexp.MatchString(expectedRegexPattern, actualStatusString)
re := regexp.MustCompile(expectedRegexPattern, regexpDefaultSpec)
matched, _ := re.MatchString(actualStatusString)
if !matched {
t.Errorf("expected status %q but got %q", expectedRegexPattern, actualStatusString)
}
})
}
func TestCatastrophicBacktrackTimeout(t *testing.T) {
r, err := regexp.Compile("(.+)*\\?", 0)
if err != nil {
t.Fatal(err)
}
var exp = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
exp = strings.Repeat(exp, 2^10)
timeout := regexpDefaultTimeout
t.Logf("regexp.DefaultMatchTimeout set to: %v", timeout)
buffer := 500 * time.Millisecond
t.Run(fmt.Sprint(timeout), func(t *testing.T) {
r.MatchTimeout = timeout
start := time.Now()
_, err = r.FindStringMatch(exp)
if err != nil && !strings.HasPrefix(err.Error(), "match timeout") {
t.Fatal(err)
}
if err == nil {
t.Fatal("expected catastrophic backtracking error")
}
elapsed := time.Since(start)
if elapsed > timeout+buffer {
t.Fatalf("timeout %v exceeded: %v", timeout, elapsed)
}
})
}

View File

@ -33,11 +33,13 @@ import (
"github.com/go-logr/logr"
"gopkg.in/yaml.v3"
"k8s.io/client-go/kubernetes"
_ "k8s.io/client-go/plugin/pkg/client/auth" // Initialize common client auth plugins.
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
yaml "sigs.k8s.io/yaml/goyaml.v3"
"github.com/KimMachineGun/automemlimit/memlimit"
"github.com/oklog/run"
@ -147,6 +149,7 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
hash := md5HashAsMetricValue(configFile)
configHash.WithLabelValues("config", filepath.Clean(got)).Set(hash)
}
opts = configureResourcesAndMetrics(opts, configFile)
}
if opts.AutoGoMemlimit {
@ -247,6 +250,7 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
))
storeBuilder.WithUsingAPIServerCache(opts.UseAPIServerCache)
storeBuilder.WithObjectLimit(opts.ObjectLimit)
storeBuilder.WithGenerateStoresFunc(storeBuilder.DefaultGenerateStoresFunc())
proc.StartReaper()
@ -261,9 +265,12 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
if err := storeBuilder.WithAllowAnnotations(opts.AnnotationsAllowList); err != nil {
return fmt.Errorf("failed to set up annotations allowlist: %v", err)
}
klog.InfoS("Using annotations allowlist", "annotationsAllowList", opts.AnnotationsAllowList)
if err := storeBuilder.WithAllowLabels(opts.LabelsAllowList); err != nil {
return fmt.Errorf("failed to set up labels allowlist: %v", err)
}
klog.InfoS("Using labels allowlist", "labelsAllowList", opts.LabelsAllowList)
ksmMetricsRegistry.MustRegister(
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
@ -295,6 +302,8 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
CRDsDeleteEventsCounter: crdsDeleteEventsCounter,
CRDsCacheCountGauge: crdsCacheCountGauge,
}
// storeBuilder starts reflectors for the discovered GVKs, and as such, should close them too.
storeBuilder.GVKToReflectorStopChanMap = &discovererInstance.GVKToReflectorStopChanMap
// This starts a goroutine that will watch for any new GVKs to extract from CRDs.
err = discovererInstance.StartDiscovery(ctx, kubeConfig)
if err != nil {
@ -315,18 +324,17 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
)
}
telemetryMux := buildTelemetryServer(ksmMetricsRegistry)
telemetryMux := buildTelemetryServer(ksmMetricsRegistry, opts.AuthFilter, kubeConfig)
telemetryListenAddress := net.JoinHostPort(opts.TelemetryHost, strconv.Itoa(opts.TelemetryPort))
telemetryServer := http.Server{
Handler: telemetryMux,
ReadHeaderTimeout: 5 * time.Second}
telemetryFlags := web.FlagConfig{
WebListenAddresses: &[]string{telemetryListenAddress},
WebSystemdSocket: new(bool),
WebConfigFile: &tlsConfig,
}
metricsMux := buildMetricsServer(m, durationVec, kubeClient)
metricsMux := buildMetricsServer(m, durationVec, kubeClient, opts.AuthFilter, kubeConfig)
metricsServerListenAddress := net.JoinHostPort(opts.Host, strconv.Itoa(opts.Port))
metricsServer := http.Server{
Handler: metricsMux,
@ -337,7 +345,6 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
}
metricsFlags := web.FlagConfig{
WebListenAddresses: &[]string{metricsServerListenAddress},
WebSystemdSocket: new(bool),
WebConfigFile: &tlsConfig,
}
@ -375,14 +382,86 @@ func RunKubeStateMetrics(ctx context.Context, opts *options.Options) error {
return nil
}
func buildTelemetryServer(registry prometheus.Gatherer) *http.ServeMux {
func configureResourcesAndMetrics(opts *options.Options, configFile []byte) *options.Options {
// If the config file is set, we will overwrite the opts with the config file.
// This is only needed for maps because the default behaviour of yaml.Unmarshal is to append keys (and overwrite any conflicting ones).
config := options.NewOptions()
err := yaml.Unmarshal(configFile, &config)
if err == nil {
if len(config.Resources) > 0 {
opts.Resources = options.ResourceSet{}
for resource := range config.Resources {
opts.Resources[resource] = struct{}{}
}
}
if len(config.MetricAllowlist) > 0 {
opts.MetricAllowlist = options.MetricSet{}
for metric := range config.MetricAllowlist {
opts.MetricAllowlist[metric] = struct{}{}
}
}
if len(config.MetricDenylist) > 0 {
opts.MetricDenylist = options.MetricSet{}
for metric := range config.MetricDenylist {
opts.MetricDenylist[metric] = struct{}{}
}
}
if len(config.MetricOptInList) > 0 {
opts.MetricOptInList = options.MetricSet{}
for metric := range config.MetricOptInList {
opts.MetricOptInList[metric] = struct{}{}
}
}
if len(config.LabelsAllowList) > 0 {
opts.LabelsAllowList = options.LabelsAllowList{}
for label, value := range config.LabelsAllowList {
opts.LabelsAllowList[label] = value
}
}
if len(config.AnnotationsAllowList) > 0 {
opts.AnnotationsAllowList = options.LabelsAllowList{}
for annotation, value := range config.AnnotationsAllowList {
opts.AnnotationsAllowList[annotation] = value
}
}
} else {
klog.ErrorS(err, "failed to unmarshal configFile")
}
return opts
}
func buildTelemetryServer(registry prometheus.Gatherer, authFilter bool, kubeConfig *rest.Config) *http.ServeMux {
mux := http.NewServeMux()
handler := logr.ToSlogHandler(klog.Background())
sLogger := slog.NewLogLogger(handler, slog.LevelError)
loghandler := logr.ToSlogHandler(klog.Background())
sLogger := slog.NewLogLogger(loghandler, slog.LevelError)
// Add metricsPath
mux.Handle(metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorLog: sLogger}))
metricsHandler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorLog: sLogger})
// Add Authentication/Authorization via Kubernetes API
if authFilter {
client, err := rest.HTTPClientFor(kubeConfig)
if err != nil {
klog.ErrorS(err, "failed to create HTTP client from config")
}
metricsFilter, err := filters.WithAuthenticationAndAuthorization(kubeConfig, client)
if err != nil {
klog.ErrorS(err, "failed to create auth handler")
}
metricsHandler, err = metricsFilter(klog.Background(), metricsHandler)
if err != nil {
klog.ErrorS(err, "failed to apply metrics filter")
}
}
mux.Handle(metricsPath, metricsHandler)
// Add readyzPath
mux.Handle(readyzPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
@ -429,7 +508,7 @@ func handleClusterDelegationForProber(client kubernetes.Interface, probeType str
}
}
func buildMetricsServer(m *metricshandler.MetricsHandler, durationObserver prometheus.ObserverVec, client kubernetes.Interface) *http.ServeMux {
func buildMetricsServer(m *metricshandler.MetricsHandler, durationObserver prometheus.ObserverVec, client kubernetes.Interface, authFilter bool, kubeConfig *rest.Config) *http.ServeMux {
mux := http.NewServeMux()
// TODO: This doesn't belong into serveMetrics
@ -440,7 +519,29 @@ func buildMetricsServer(m *metricshandler.MetricsHandler, durationObserver prome
mux.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))
// Add metricsPath
mux.Handle(metricsPath, promhttp.InstrumentHandlerDuration(durationObserver, m))
metricsHandler := promhttp.InstrumentHandlerDuration(durationObserver, m)
// Add Authentication/Authorization via Kubernetes API
if authFilter {
client, err := rest.HTTPClientFor(kubeConfig)
if err != nil {
klog.ErrorS(err, "failed to create HTTP client from config")
}
metricsFilter, err := filters.WithAuthenticationAndAuthorization(kubeConfig, client)
if err != nil {
klog.ErrorS(err, "failed to create auth handler")
}
handler, err := metricsFilter(klog.Background(), metricsHandler)
if err != nil {
klog.ErrorS(err, "failed to apply metrics filter")
}
metricsHandler = handler.(http.HandlerFunc)
}
mux.Handle(metricsPath, metricsHandler)
// Add livezPath
mux.Handle(livezPath, handleClusterDelegationForProber(client, livezPath))
@ -497,7 +598,7 @@ func resolveCustomResourceConfig(opts *options.Options) (customresourcestate.Con
if file := opts.CustomResourceConfigFile; file != "" {
f, err := os.Open(filepath.Clean(file))
if err != nil {
return nil, fmt.Errorf("Custom Resource State Metrics file could not be opened: %v", err)
return nil, fmt.Errorf("unable to open Custom Resource State Metrics file: %v", err)
}
return yaml.NewDecoder(f), nil
}

View File

@ -259,6 +259,7 @@ func TestFullScrapeCycle(t *testing.T) {
# HELP kube_pod_status_scheduled [STABLE] Describes the status of the scheduling process for the pod.
# HELP kube_pod_status_scheduled_time [STABLE] Unix timestamp when pod moved into scheduled status
# HELP kube_pod_status_unschedulable [STABLE] Describes the unschedulable status for the pod.
# HELP kube_pod_status_unscheduled_time Unix timestamp when pod moved into unscheduled status
# HELP kube_pod_tolerations Information about the pod tolerations
# TYPE kube_pod_annotations gauge
# TYPE kube_pod_completion_time gauge
@ -312,6 +313,7 @@ func TestFullScrapeCycle(t *testing.T) {
# TYPE kube_pod_status_scheduled gauge
# TYPE kube_pod_status_scheduled_time gauge
# TYPE kube_pod_status_unschedulable gauge
# TYPE kube_pod_status_unscheduled_time gauge
# TYPE kube_pod_tolerations gauge
kube_pod_container_info{namespace="default",pod="pod0",uid="abc-0",container="pod1_con1",image_spec="k8s.gcr.io/hyperkube2_spec",image="k8s.gcr.io/hyperkube2",image_id="docker://sha256:bbb",container_id="docker://cd456"} 1
kube_pod_container_info{namespace="default",pod="pod0",uid="abc-0",container="pod1_con2",image_spec="k8s.gcr.io/hyperkube3_spec",image="k8s.gcr.io/hyperkube3",image_id="docker://sha256:ccc",container_id="docker://ef789"} 1
@ -387,7 +389,7 @@ kube_pod_status_reason{namespace="default",pod="pod0",uid="abc-0",reason="Unexpe
}
}
telemetryMux := buildTelemetryServer(reg)
telemetryMux := buildTelemetryServer(reg, false, nil)
req2 := httptest.NewRequest("GET", "http://localhost:8081/metrics", nil)
@ -979,3 +981,96 @@ func (f *fooFactory) ListWatch(customResourceClient interface{}, ns string, fiel
},
}
}
func TestConfigureResourcesAndMetrics(t *testing.T) {
// Prepare a config file in YAML format
configYAML := `
"resources":
"pod": {}
"service": {}
"metric_allowlist":
"kube_pod_info": {}
"metric_denylist":
"kube_pod_labels": {}
"metric_opt_in_list":
"kube_pod_status_phase": {}
"labels_allow_list":
"labelX":
- foo
- bar
"annotations_allow_list":
"annotationY":
- baz
`
opts := options.NewOptions()
// Set some initial values to be overwritten
opts.Resources = options.ResourceSet{"oldresource": {}}
opts.MetricAllowlist = options.MetricSet{"oldallow": {}}
opts.MetricDenylist = options.MetricSet{"olddeny": {}}
opts.MetricOptInList = options.MetricSet{"oldoptin": {}}
opts.LabelsAllowList = options.LabelsAllowList{"oldlabel": {"oldvalue"}}
opts.AnnotationsAllowList = options.LabelsAllowList{"oldannotation": {"oldvalue"}}
newOpts := configureResourcesAndMetrics(opts, []byte(configYAML))
// Check resources
expectedResources := []string{"pod", "service"}
for _, r := range expectedResources {
if _, ok := newOpts.Resources[r]; !ok {
t.Errorf("expected resource %q in opts.Resources", r)
}
}
if _, ok := newOpts.Resources["oldresource"]; ok {
t.Errorf("expected oldresource to be overwritten")
}
// Check metric allowlist
if _, ok := newOpts.MetricAllowlist["kube_pod_info"]; !ok {
t.Errorf("expected kube_pod_info in MetricAllowlist")
}
if _, ok := newOpts.MetricAllowlist["oldallow"]; ok {
t.Errorf("expected oldallow to be overwritten")
}
// Check metric denylist
if _, ok := newOpts.MetricDenylist["kube_pod_labels"]; !ok {
t.Errorf("expected kube_pod_labels in MetricDenylist")
}
if _, ok := newOpts.MetricDenylist["olddeny"]; ok {
t.Errorf("expected olddeny to be overwritten")
}
// Check metric opt-in list
if _, ok := newOpts.MetricOptInList["kube_pod_status_phase"]; !ok {
t.Errorf("expected kube_pod_status_phase in MetricOptInList")
}
if _, ok := newOpts.MetricOptInList["oldoptin"]; ok {
t.Errorf("expected oldoptin to be overwritten")
}
// Check labels allow list
if vals, ok := newOpts.LabelsAllowList["labelX"]; !ok || len(vals) != 2 || vals[0] != "foo" || vals[1] != "bar" {
t.Errorf("expected labelX with values [foo bar], got %v", vals)
}
if vals, ok := newOpts.LabelsAllowList["oldlabel"]; ok {
t.Errorf("expected oldlabel to be overwritten, got %v", vals)
}
// Check annotations allow list
if vals, ok := newOpts.AnnotationsAllowList["annotationY"]; !ok || len(vals) != 1 || vals[0] != "baz" {
t.Errorf("expected annotationY with value [baz], got %v", vals)
}
if vals, ok := newOpts.AnnotationsAllowList["oldannotation"]; ok {
t.Errorf("expected oldannotation to be overwritten, got %v", vals)
}
}
func TestConfigureResourcesAndMetrics_InvalidYAML(t *testing.T) {
opts := options.NewOptions()
invalidYAML := []byte("invalid: [unclosed")
// Should not panic or overwrite opts
result := configureResourcesAndMetrics(opts, invalidYAML)
if result != opts {
t.Errorf("expected opts to be returned unchanged on invalid YAML")
}
}

View File

@ -67,6 +67,7 @@ func customStore(_ []generator.FamilyGenerator,
_ interface{},
_ func(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher,
_ bool,
_ int64,
) []cache.Store {
stores := make([]cache.Store, 0, 2)
stores = append(stores, newFakeStore(fakeMetricLists[0]))

View File

@ -57,7 +57,7 @@ type BuilderInterface interface {
type BuildStoresFunc func(metricFamilies []generator.FamilyGenerator,
expectedType interface{},
listWatchFunc func(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher,
useAPIServerCache bool,
useAPIServerCache bool, limit int64,
) []cache.Store
// BuildCustomResourceStoresFunc function signature that is used to return a list of custom resource cache.Store
@ -65,7 +65,7 @@ type BuildCustomResourceStoresFunc func(resourceName string,
metricFamilies []generator.FamilyGenerator,
expectedType interface{},
listWatchFunc func(customResourceClient interface{}, ns string, fieldSelector string) cache.ListerWatcher,
useAPIServerCache bool,
useAPIServerCache bool, limit int64,
) []cache.Store
// AllowDenyLister interface for AllowDeny lister that can allow or exclude metrics by there names

View File

@ -22,8 +22,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"k8s.io/klog/v2"
yaml "sigs.k8s.io/yaml/goyaml.v3"
)
//go:embed example_config.yaml

View File

@ -70,7 +70,7 @@ func compileCommon(c MetricMeta) (*compiledCommon, error) {
}
func compileFamily(f Generator, resource Resource) (*compiledFamily, error) {
labels := resource.Labels.Merge(f.Labels)
labels := resource.Merge(f.Labels)
if f.Each.Type == metric.Info && !strings.HasSuffix(f.Name, "_info") {
klog.InfoS("Info metric does not have _info suffix", "gvk", resource.GroupVersionKind.String(), "name", f.Name)
@ -652,7 +652,7 @@ func compilePath(path []string) (out valuePath, _ error) {
// negative index
i += len(s)
}
if !(0 <= i && i < len(s)) {
if i < 0 || i >= len(s) {
return fmt.Errorf("list index out of range: %s", part)
}
return s[i]

View File

@ -79,6 +79,8 @@ type Options struct {
Help bool `yaml:"help"`
TrackUnscheduledPods bool `yaml:"track_unscheduled_pods"`
UseAPIServerCache bool `yaml:"use_api_server_cache"`
ObjectLimit int64 `yaml:"object_limit"`
AuthFilter bool `yaml:"auth_filter"`
}
// GetConfigFile is the getter for --config value.
@ -143,11 +145,13 @@ func (o *Options) AddFlags(cmd *cobra.Command) {
o.cmd.Flags().BoolVar(&o.TrackUnscheduledPods, "track-unscheduled-pods", false, "This configuration is used in conjunction with node configuration. When this configuration is true, node configuration is empty and the metric of unscheduled pods is fetched from the Kubernetes API Server. This is experimental.")
o.cmd.Flags().BoolVarP(&o.Help, "help", "h", false, "Print Help text")
o.cmd.Flags().BoolVarP(&o.UseAPIServerCache, "use-apiserver-cache", "", false, "Sets resourceVersion=0 for ListWatch requests, using cached resources from the apiserver instead of an etcd quorum read.")
o.cmd.Flags().Int64Var(&o.ObjectLimit, "object-limit", 0, "The total number of objects to list per resource from the API Server. (experimental)")
o.cmd.Flags().Int32Var(&o.Shard, "shard", int32(0), "The instances shard nominal (zero indexed) within the total number of shards. (default 0)")
o.cmd.Flags().IntVar(&o.Port, "port", 8080, `Port to expose metrics on.`)
o.cmd.Flags().IntVar(&o.TelemetryPort, "telemetry-port", 8081, `Port to expose kube-state-metrics self metrics on.`)
o.cmd.Flags().IntVar(&o.TotalShards, "total-shards", 1, "The total number of shards. Sharding is disabled when total shards is set to 1.")
o.cmd.Flags().StringVar(&o.Apiserver, "apiserver", "", `The URL of the apiserver to use as a master`)
o.cmd.Flags().BoolVar(&o.AuthFilter, "auth-filter", false, "If true, requires authentication and authorization through Kubernetes API to access metrics endpoints")
o.cmd.Flags().BoolVar(&o.AutoGoMemlimit, "auto-gomemlimit", false, "Automatically set GOMEMLIMIT to match container or system memory limit. (experimental)")
o.cmd.Flags().Float64Var(&o.AutoGoMemlimitRatio, "auto-gomemlimit-ratio", float64(0.9), "The ratio of reserved GOMEMLIMIT memory to the detected maximum container or system memory. (experimental)")
o.cmd.Flags().StringVar(&o.CustomResourceConfig, "custom-resource-state-config", "", "Inline Custom Resource State Metrics config YAML (experimental)")
@ -158,12 +162,12 @@ func (o *Options) AddFlags(cmd *cobra.Command) {
o.cmd.Flags().StringVar(&o.Pod, "pod", "", "Name of the pod that contains the kube-state-metrics container. "+autoshardingNotice)
o.cmd.Flags().StringVar(&o.TLSConfig, "tls-config", "", "Path to the TLS configuration file")
o.cmd.Flags().StringVar(&o.TelemetryHost, "telemetry-host", "::", `Host to expose kube-state-metrics self metrics on.`)
o.cmd.Flags().StringVar(&o.Config, "config", "", "Path to the kube-state-metrics options config file")
o.cmd.Flags().StringVar(&o.Config, "config", "", "Path to the kube-state-metrics options config YAML file. If this flag is set, the flags defined in the file override the command line flags.")
o.cmd.Flags().StringVar((*string)(&o.Node), "node", "", "Name of the node that contains the kube-state-metrics pod. Most likely it should be passed via the downward API. This is used for daemonset sharding. Only available for resources (pod metrics) that support spec.nodeName fieldSelector. This is experimental.")
o.cmd.Flags().Var(&o.AnnotationsAllowList, "metric-annotations-allowlist", "Comma-separated list of Kubernetes annotations keys that will be used in the resource' labels metric. By default the annotations metrics are not exposed. To include them, provide a list of resource names in their plural form and Kubernetes annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. A single '*' can be provided per resource instead to allow any annotations, but that has severe performance implications (Example: '=pods=[*]').")
o.cmd.Flags().Var(&o.LabelsAllowList, "metric-labels-allowlist", "Comma-separated list of additional Kubernetes label keys that will be used in the resource' labels metric. By default the labels metrics are not exposed. To include them, provide a list of resource names in their plural form and Kubernetes label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. A single '*' can be provided per resource instead to allow any labels, but that has severe performance implications (Example: '=pods=[*]'). Additionally, an asterisk (*) can be provided as a key, which will resolve to all resources, i.e., assuming '--resources=deployments,pods', '=*=[*]' will resolve to '=deployments=[*],pods=[*]'.")
o.cmd.Flags().Var(&o.MetricAllowlist, "metric-allowlist", "Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.")
o.cmd.Flags().Var(&o.MetricDenylist, "metric-denylist", "Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or regex patterns. The allowlist and denylist are mutually exclusive.")
o.cmd.Flags().Var(&o.MetricAllowlist, "metric-allowlist", "Comma-separated list of metrics to be exposed. This list comprises of exact metric names and/or *ECMAScript-based* regex patterns. The allowlist and denylist are mutually exclusive.")
o.cmd.Flags().Var(&o.MetricDenylist, "metric-denylist", "Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or *ECMAScript-based* regex patterns. The allowlist and denylist are mutually exclusive.")
o.cmd.Flags().Var(&o.MetricOptInList, "metric-opt-in-list", "Comma-separated list of metrics which are opt-in and not enabled by default. This is in addition to the metric allow- and denylists")
o.cmd.Flags().Var(&o.Namespaces, "namespaces", fmt.Sprintf("Comma-separated list of namespaces to be enabled. Defaults to %q", &DefaultNamespaces))
o.cmd.Flags().Var(&o.NamespacesDenylist, "namespaces-denylist", "Comma-separated list of namespaces not to be enabled. If namespaces and namespaces-denylist are both set, only namespaces that are excluded in namespaces-denylist will be used.")
@ -202,5 +206,9 @@ func (o *Options) Validate() error {
return fmt.Errorf("value for --auto-gomemlimit-ratio=%f must be greater than 0 and less than or equal to 1", o.AutoGoMemlimitRatio)
}
if o.ObjectLimit < 0 {
return fmt.Errorf("value for --object-limit=%d must be equal or greater than 0", o.ObjectLimit)
}
return nil
}

View File

@ -50,7 +50,7 @@ func TestResourceSetSet(t *testing.T) {
for _, test := range tests {
cs := &ResourceSet{}
gotError := cs.Set(test.Value)
if !(((gotError == nil && !test.WantedError) || (gotError != nil && test.WantedError)) && reflect.DeepEqual(*cs, test.Wanted)) {
if ((gotError != nil || test.WantedError) && (gotError == nil || !test.WantedError)) || !reflect.DeepEqual(*cs, test.Wanted) {
t.Errorf("Test error for Desc: %s. Want: %+v. Got: %+v. Wanted Error: %v, Got Error: %v", test.Desc, test.Wanted, *cs, test.WantedError, gotError)
}
}

View File

@ -69,7 +69,7 @@ func (s *shardedListWatch) List(options metav1.ListOptions) (runtime.Object, err
res.Items = append(res.Items, runtime.RawExtension{Object: item})
}
}
res.ListMeta.ResourceVersion = metaObj.GetResourceVersion()
res.ResourceVersion = metaObj.GetResourceVersion()
return res, nil
}

View File

@ -42,7 +42,7 @@ func TestSharding(t *testing.T) {
totalShards: 2,
}
if !(s1.keep(cm) || s2.keep(cm)) {
if !s1.keep(cm) && !s2.keep(cm) {
t.Fatal("One shard must pick up the object.")
}

View File

@ -135,7 +135,7 @@ func GVRFromType(resourceName string, expectedType interface{}) (*schema.GroupVe
}
t, err := meta.TypeAccessor(expectedType)
if err != nil {
return nil, fmt.Errorf("Failed to get type accessor for %T: %w", expectedType, err)
return nil, fmt.Errorf("failed to get type accessor for %T: %w", expectedType, err)
}
apiVersion := t.GetAPIVersion()
g, v, found := strings.Cut(apiVersion, "/")

View File

@ -19,6 +19,7 @@ package watch
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
@ -27,8 +28,10 @@ import (
// ListWatchMetrics stores the pointers of kube_state_metrics_[list|watch]_total metrics.
type ListWatchMetrics struct {
WatchTotal *prometheus.CounterVec
ListTotal *prometheus.CounterVec
WatchRequestsTotal *prometheus.CounterVec
ListRequestsTotal *prometheus.CounterVec
ListObjectsLimit *prometheus.GaugeVec
ListObjectsCurrent *prometheus.GaugeVec
}
// NewListWatchMetrics takes in a prometheus registry and initializes
@ -36,20 +39,34 @@ type ListWatchMetrics struct {
// kube_state_metrics_watch_total metrics. It returns those registered metrics.
func NewListWatchMetrics(r prometheus.Registerer) *ListWatchMetrics {
return &ListWatchMetrics{
WatchTotal: promauto.With(r).NewCounterVec(
WatchRequestsTotal: promauto.With(r).NewCounterVec(
prometheus.CounterOpts{
Name: "kube_state_metrics_watch_total",
Help: "Number of total resource watches in kube-state-metrics",
Help: "Number of total resource watch calls in kube-state-metrics",
},
[]string{"result", "resource"},
),
ListTotal: promauto.With(r).NewCounterVec(
ListRequestsTotal: promauto.With(r).NewCounterVec(
prometheus.CounterOpts{
Name: "kube_state_metrics_list_total",
Help: "Number of total resource list in kube-state-metrics",
Help: "Number of total resource list calls in kube-state-metrics",
},
[]string{"result", "resource"},
),
ListObjectsCurrent: promauto.With(r).NewGaugeVec(
prometheus.GaugeOpts{
Name: "kube_state_metrics_list_objects",
Help: "Number of resources listed in kube-state-metrics",
},
[]string{"resource"},
),
ListObjectsLimit: promauto.With(r).NewGaugeVec(
prometheus.GaugeOpts{
Name: "kube_state_metrics_list_objects_limit",
Help: "Number of resource list limit in kube-state-metrics",
},
[]string{"resource"},
),
}
}
@ -60,34 +77,59 @@ type InstrumentedListerWatcher struct {
metrics *ListWatchMetrics
resource string
useAPIServerCache bool
limit int64
}
// NewInstrumentedListerWatcher returns a new InstrumentedListerWatcher.
func NewInstrumentedListerWatcher(lw cache.ListerWatcher, metrics *ListWatchMetrics, resource string, useAPIServerCache bool) cache.ListerWatcher {
func NewInstrumentedListerWatcher(lw cache.ListerWatcher, metrics *ListWatchMetrics, resource string, useAPIServerCache bool, limit int64) cache.ListerWatcher {
return &InstrumentedListerWatcher{
lw: lw,
metrics: metrics,
resource: resource,
useAPIServerCache: useAPIServerCache,
limit: limit,
}
}
// List is a wrapper func around the cache.ListerWatcher.List func. It increases the success/error
// / counters based on the outcome of the List operation it instruments.
// It supports setting object limits, this means if it is set it will only list and process
// n objects of the same resource type.
func (i *InstrumentedListerWatcher) List(options metav1.ListOptions) (runtime.Object, error) {
if i.useAPIServerCache {
options.ResourceVersion = "0"
}
if i.limit > 0 {
options.Limit = i.limit
i.metrics.ListObjectsLimit.WithLabelValues(i.resource).Set(float64(i.limit))
}
res, err := i.lw.List(options)
if err != nil {
i.metrics.ListTotal.WithLabelValues("error", i.resource).Inc()
i.metrics.ListRequestsTotal.WithLabelValues("error", i.resource).Inc()
return nil, err
}
i.metrics.ListTotal.WithLabelValues("success", i.resource).Inc()
list, err := meta.ExtractList(res)
if err != nil {
return nil, err
}
i.metrics.ListRequestsTotal.WithLabelValues("success", i.resource).Inc()
if i.limit > 0 {
if int64(len(list)) > i.limit {
meta.SetList(res, list[0:i.limit])
i.metrics.ListObjectsCurrent.WithLabelValues(i.resource).Set(float64(i.limit))
} else {
i.metrics.ListObjectsCurrent.WithLabelValues(i.resource).Set(float64(len(list)))
}
}
return res, nil
}
// Watch is a wrapper func around the cache.ListerWatcher.Watch func. It increases the success/error
@ -95,10 +137,10 @@ func (i *InstrumentedListerWatcher) List(options metav1.ListOptions) (runtime.Ob
func (i *InstrumentedListerWatcher) Watch(options metav1.ListOptions) (watch.Interface, error) {
res, err := i.lw.Watch(options)
if err != nil {
i.metrics.WatchTotal.WithLabelValues("error", i.resource).Inc()
i.metrics.WatchRequestsTotal.WithLabelValues("error", i.resource).Inc()
return nil, err
}
i.metrics.WatchTotal.WithLabelValues("success", i.resource).Inc()
i.metrics.WatchRequestsTotal.WithLabelValues("success", i.resource).Inc()
return res, nil
}

View File

@ -43,7 +43,7 @@ echo "### Result"
echo "old=${REF_TO_COMPARE} new=${REF_CURRENT}"
if [[ -z "${BENCHSTAT_OUTPUT_FILE}" ]]; then
benchstat "${REF_TO_COMPARE}=${RESULT_TO_COMPARE}" "${REF_CURRENT}=${RESULT_CURRENT}"
go tool golang.org/x/perf/cmd/benchstat "${REF_TO_COMPARE}=${RESULT_TO_COMPARE}" "${REF_CURRENT}=${RESULT_CURRENT}"
else
benchstat "${REF_TO_COMPARE}=${RESULT_TO_COMPARE}" "${REF_CURRENT}=${RESULT_CURRENT}" | tee -a "${BENCHSTAT_OUTPUT_FILE}"
go tool golang.org/x/perf/cmd/benchstat "${REF_TO_COMPARE}=${RESULT_TO_COMPARE}" "${REF_CURRENT}=${RESULT_CURRENT}" | tee -a "${BENCHSTAT_OUTPUT_FILE}"
fi

View File

@ -25,13 +25,13 @@ case $(uname -m) in
esac
NODE_IMAGE_NAME="docker.io/kindest/node"
KUBERNETES_VERSION=${KUBERNETES_VERSION:-"v1.32.0"}
KUBERNETES_VERSION=${KUBERNETES_VERSION:-"v1.33.0"}
KUBE_STATE_METRICS_LOG_DIR=./log
KUBE_STATE_METRICS_CURRENT_IMAGE_NAME="registry.k8s.io/kube-state-metrics/kube-state-metrics"
KUBE_STATE_METRICS_IMAGE_NAME="registry.k8s.io/kube-state-metrics/kube-state-metrics-${ARCH}"
E2E_SETUP_KIND=${E2E_SETUP_KIND:-}
E2E_SETUP_KUBECTL=${E2E_SETUP_KUBECTL:-}
KIND_VERSION=v0.25.0
KIND_VERSION=v0.29.0
SUDO=${SUDO:-}
OS=$(uname -s | awk '{print tolower($0)}')
@ -247,9 +247,15 @@ sleep 33
klog_err=E$(date +%m%d)
echo "check for errors in logs"
echo "running authfiler tests.."
go test -v ./tests/e2e/auth-filter_test.go
echo "running discovery tests..."
go test -race -v ./tests/e2e/discovery_test.go
echo "running object limits test..."
go test -v ./tests/e2e/object-limits_test.go
echo "running hot-reload tests..."
go test -v ./tests/e2e/hot-reload_test.go

View File

@ -1,3 +1,5 @@
# End-to-End Tests
To run these tests, you need to provide two CLI flags:
* `--ksm-http-metrics-url`: url to access the kube-state-metrics service
@ -5,7 +7,7 @@ To run these tests, you need to provide two CLI flags:
Example:
```
```bash
go test -v ./tests/e2e \
--ksm-http-metrics-url=http://localhost:8080/ \
--ksm-telemetry-url=http://localhost:8081/

View File

@ -0,0 +1,169 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e
import (
"context"
"net"
"os"
"os/exec"
"strings"
"testing"
"time"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog/v2"
"k8s.io/kube-state-metrics/v2/internal"
"k8s.io/kube-state-metrics/v2/pkg/options"
)
func TestAuthFilter(t *testing.T) {
// Initialise options.
opts := options.NewOptions()
cmd := options.InitCommand
opts.AddFlags(cmd)
klog.InfoS("options", "options", opts)
// Populate options, and parse them.
opts.AuthFilter = true
opts.Kubeconfig = os.Getenv("HOME") + "/.kube/config"
if err := opts.Parse(); err != nil {
t.Fatalf("failed to parse options: %v", err)
}
klog.InfoS("parsed options", "options", opts)
var err error
// Create ClusterRole and ClusterRoleBinding
klog.InfoS("Setting up RBAC")
err = exec.Command("kubectl", "apply", "-f", "testdata/metrics-reader_role.yaml").Run()
if err != nil {
t.Fatalf("failed to set up clusterrole")
}
err = exec.Command("kubectl", "apply", "-f", "testdata/metrics-reader_rolebinding.yaml").Run()
if err != nil {
t.Fatalf("failed to set up clusterrolebinding")
}
// Make the process asynchronous.
go internal.RunKubeStateMetricsWrapper(opts)
klog.InfoS("started KSM")
// Wait for port 8080 to come up.
err = wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, 20*time.Second, true, func(_ context.Context) (bool, error) {
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
return false, nil
}
err = conn.Close()
if err != nil {
return false, err
}
return true, nil
})
if err != nil {
t.Fatalf("failed while waiting for port 8080 to come up: %v", err)
}
klog.InfoS("port 8080 up")
// Wait for the metric to be available.
ch := make(chan bool, 1)
klog.InfoS("waiting for first metrics to become available")
testMetric := `kube_configmap_info`
token, err := exec.Command("kubectl", "create", "token", "kube-state-metrics", "-n", "kube-system").Output()
if err != nil {
t.Fatalf("failed to create token %v", err)
}
klog.InfoS("token created")
err = wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, 20*time.Second, true, func(_ context.Context) (bool, error) {
out, err := exec.Command("curl", "-H", "Authorization: Bearer "+string(token), "localhost:8080/metrics").Output() // nolint:gosec
if err != nil {
return false, err
}
if string(out) == "" {
return false, nil
}
if strings.Contains(string(out), testMetric) {
klog.InfoS("metrics fetched with bearer token")
// Signal the process to exit, since we know the metrics are being generated as expected.
out, err := exec.Command("curl", "localhost:8080/metrics").Output()
if err != nil {
return false, err
}
if string(out) == "Unauthorized\n" {
return true, nil
}
}
return false, nil
})
if err != nil {
t.Fatalf("failed while waiting for initial metrics to be available: %v", err)
}
klog.InfoS("waiting for first telemetry metrics to become available")
telemetryTestMetric := "kube_state_metrics_build_info"
err = wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, 20*time.Second, true, func(_ context.Context) (bool, error) {
out, err := exec.Command("curl", "-H", "Authorization: Bearer "+string(token), "localhost:8081/metrics").Output() // nolint:gosec
if err != nil {
return false, err
}
if string(out) == "" {
return false, nil
}
// Note: we use count to make sure that only one metrics handler is running
if strings.Contains(string(out), telemetryTestMetric) {
// klog.InfoS("metrics available", "metric", string(out))
klog.InfoS("telemetry metrics fetched with bearer token")
// Signal the process to exit, since we know the metrics are being generated as expected.
out, err := exec.Command("curl", "localhost:8081/metrics").Output()
if err != nil {
return false, err
}
if string(out) == "Unauthorized\n" {
ch <- true
return true, nil
}
}
return false, nil
})
if err != nil {
t.Fatalf("failed while waiting for initial telemetry metrics to be available: %v", err)
}
// Clean up
err = exec.Command("kubectl", "delete", "clusterrolebindings.rbac.authorization.k8s.io", "metrics-reader-rolebinding").Run()
if err != nil {
t.Fatalf("failed to clean up clusterrolebinding")
}
err = exec.Command("kubectl", "delete", "clusterroles.rbac.authorization.k8s.io", "metrics-reader").Run()
if err != nil {
t.Fatalf("failed to clean up clusterrole")
}
// Wait for process to exit.
select {
case <-ch:
t.Log("initial metrics are available")
case <-time.After(40 * time.Second):
t.Fatal("timed out waiting for test to pass, check the logs for more info")
}
}

View File

@ -118,7 +118,7 @@ func (k *KSMClient) IsHealthz() (bool, error) {
func (k *KSMClient) writeMetrics(endpoint *url.URL, w io.Writer) error {
if endpoint == nil {
return errors.New("Endpoint is nil")
return errors.New("endpoint is nil")
}
u := *endpoint
@ -165,7 +165,7 @@ func (f *Framework) ParseMetrics(metrics func(io.Writer) error) (map[string]*dto
buf := &bytes.Buffer{}
err := metrics(buf)
if err != nil {
return nil, fmt.Errorf("Failed to get metrics: %w", err)
return nil, fmt.Errorf("failed to get metrics: %w", err)
}
parser := &expfmt.TextParser{}

View File

@ -0,0 +1,123 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e
import (
"context"
"fmt"
"net"
"os"
"os/exec"
"strings"
"testing"
"time"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog/v2"
"k8s.io/kube-state-metrics/v2/internal"
"k8s.io/kube-state-metrics/v2/pkg/options"
)
func TestObjectLimits(t *testing.T) {
// Initialise options.
opts := options.NewOptions()
cmd := options.InitCommand
opts.AddFlags(cmd)
klog.InfoS("options", "options", opts)
// Populate options, and parse them.
opts.ObjectLimit = 5
opts.Resources = options.ResourceSet{"configmaps": struct{}{}}
opts.Kubeconfig = os.Getenv("HOME") + "/.kube/config"
if err := opts.Parse(); err != nil {
t.Fatalf("failed to parse options: %v", err)
}
klog.InfoS("parsed options", "options", opts)
// Create ConfigMaps as Test Objects
for i := 0; i < 6; i++ {
err := exec.Command("kubectl", "create", "configmap", fmt.Sprintf("testcm%v", i)).Run() //nolint:gosec
if err != nil {
t.Fatalf("failed to create configmap : %v", err)
}
}
// Make the process asynchronous.
go internal.RunKubeStateMetricsWrapper(opts)
klog.InfoS("started KSM")
// Wait for port 8080 to come up.
err := wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, 20*time.Second, true, func(_ context.Context) (bool, error) {
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
return false, nil
}
err = conn.Close()
if err != nil {
return false, err
}
return true, nil
})
if err != nil {
t.Fatalf("failed while waiting for port 8080 to come up: %v", err)
}
klog.InfoS("port 8080 up")
// Wait for the metric to be available.
ch := make(chan bool, 1)
klog.InfoS("waiting for first metrics to become available")
testMetric := `kube_configmap_info{namespace="default"`
err = wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, 20*time.Second, true, func(_ context.Context) (bool, error) {
out, err := exec.Command("curl", "localhost:8080/metrics").Output()
if err != nil {
return false, err
}
if string(out) == "" {
return false, nil
}
// Note: we use count to make sure that only one metrics handler is running
if strings.Count(string(out), testMetric) == 5 {
// klog.InfoS("metrics available", "metric", string(out))
// Signal the process to exit, since we know the metrics are being generated as expected.
ch <- true
return true, nil
}
return false, nil
})
if err != nil {
t.Fatalf("failed while waiting for initial metrics to be available: %v", err)
}
// Delete ConfigMaps as Test Objects
for i := 0; i < 6; i++ {
err := exec.Command("kubectl", "delete", "configmap", fmt.Sprintf("testcm%v", i)).Run() //nolint:gosec
if err != nil {
t.Fatalf("failed to delete configmap : %v", err)
}
}
// Wait for process to exit.
select {
case <-ch:
t.Log("initial metrics are available")
case <-time.After(40 * time.Second):
t.Fatal("timed out waiting for test to pass, check the logs for more info")
}
}

View File

@ -0,0 +1,9 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metrics-reader
rules:
- nonResourceURLs:
- "/metrics"
verbs:
- get

View File

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metrics-reader-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metrics-reader
subjects:
- kind: ServiceAccount
name: kube-state-metrics
namespace: kube-system

Some files were not shown because too many files have changed in this diff Show More