diff --git a/docs/metrics/workload/deployment-metrics.md b/docs/metrics/workload/deployment-metrics.md
index 94f515901..75bf3334e 100644
--- a/docs/metrics/workload/deployment-metrics.md
+++ b/docs/metrics/workload/deployment-metrics.md
@@ -14,6 +14,7 @@
| kube_deployment_spec_paused | Gauge | | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | STABLE |
| kube_deployment_spec_strategy_rollingupdate_max_unavailable | Gauge | | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | STABLE |
| kube_deployment_spec_strategy_rollingupdate_max_surge | Gauge | | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | STABLE |
+| kube_deployment_spec_topology_spread_constraints | Gauge | | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | STABLE |
| kube_deployment_metadata_generation | Gauge | | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | STABLE |
| kube_deployment_labels | Gauge | Kubernetes labels converted to Prometheus labels controlled via [--metric-labels-allowlist](../../developer/cli-arguments.md) | `deployment`=<deployment-name>
`namespace`=<deployment-namespace>
`label_DEPLOYMENT_LABEL`=<DEPLOYMENT_LABEL> | STABLE |
| kube_deployment_created | Gauge | | `deployment`=<deployment-name>
`namespace`=<deployment-namespace> | STABLE |
diff --git a/internal/store/deployment.go b/internal/store/deployment.go
index 7f902b0c1..eb0565b7b 100644
--- a/internal/store/deployment.go
+++ b/internal/store/deployment.go
@@ -267,6 +267,22 @@ func deploymentMetricFamilies(allowAnnotationsList, allowLabelsList []string) []
}
}),
),
+ *generator.NewFamilyGeneratorWithStability(
+ "kube_deployment_spec_topology_spread_constraints",
+ "Number of topology spread constraints in the deployment's pod template.",
+ metric.Gauge,
+ basemetrics.STABLE,
+ "",
+ wrapDeploymentFunc(func(d *v1.Deployment) *metric.Family {
+ return &metric.Family{
+ Metrics: []*metric.Metric{
+ {
+ Value: float64(len(d.Spec.Template.Spec.TopologySpreadConstraints)),
+ },
+ },
+ }
+ }),
+ ),
*generator.NewFamilyGeneratorWithStability(
"kube_deployment_metadata_generation",
"Sequence number representing a specific generation of the desired state.",
diff --git a/internal/store/deployment_test.go b/internal/store/deployment_test.go
index 31be4a17d..c9dd75334 100644
--- a/internal/store/deployment_test.go
+++ b/internal/store/deployment_test.go
@@ -5,7 +5,7 @@ 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
+ 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,
@@ -29,51 +29,52 @@ import (
)
var (
- depl1Replicas int32 = 200
- depl2Replicas int32 = 5
-
- depl1MaxUnavailable = intstr.FromInt(10)
- depl2MaxUnavailable = intstr.FromString("25%")
-
- depl1MaxSurge = intstr.FromInt(10)
- depl2MaxSurge = intstr.FromString("20%")
+ depl1Replicas int32 = 200
+ depl2Replicas int32 = 5
+ depl1MaxUnavailable = intstr.FromInt(10)
+ depl2MaxUnavailable = intstr.FromString("25%")
+ depl1MaxSurge = intstr.FromInt(10)
+ depl2MaxSurge = intstr.FromString("20%")
)
func TestDeploymentStore(t *testing.T) {
// Fixed metadata on type and help text. We prepend this to every expected
// output so we only have to modify a single place when doing adjustments.
const metadata = `
- # HELP kube_deployment_annotations Kubernetes annotations converted to Prometheus labels.
- # TYPE kube_deployment_annotations gauge
- # HELP kube_deployment_created [STABLE] Unix creation timestamp
- # TYPE kube_deployment_created gauge
- # HELP kube_deployment_metadata_generation [STABLE] Sequence number representing a specific generation of the desired state.
- # TYPE kube_deployment_metadata_generation gauge
- # HELP kube_deployment_spec_paused [STABLE] Whether the deployment is paused and will not be processed by the deployment controller.
- # TYPE kube_deployment_spec_paused gauge
- # HELP kube_deployment_spec_replicas [STABLE] Number of desired pods for a deployment.
- # TYPE kube_deployment_spec_replicas gauge
- # HELP kube_deployment_status_replicas [STABLE] The number of replicas per deployment.
- # TYPE kube_deployment_status_replicas gauge
- # HELP kube_deployment_status_replicas_ready [STABLE] The number of ready replicas per deployment.
- # TYPE kube_deployment_status_replicas_ready gauge
- # HELP kube_deployment_status_replicas_available [STABLE] The number of available replicas per deployment.
- # TYPE kube_deployment_status_replicas_available gauge
- # HELP kube_deployment_status_replicas_unavailable [STABLE] The number of unavailable replicas per deployment.
- # TYPE kube_deployment_status_replicas_unavailable gauge
- # HELP kube_deployment_status_replicas_updated [STABLE] The number of updated replicas per deployment.
- # TYPE kube_deployment_status_replicas_updated gauge
- # HELP kube_deployment_status_observed_generation [STABLE] The generation observed by the deployment controller.
- # TYPE kube_deployment_status_observed_generation gauge
- # HELP kube_deployment_status_condition [STABLE] The current status conditions of a deployment.
- # TYPE kube_deployment_status_condition gauge
- # HELP kube_deployment_spec_strategy_rollingupdate_max_unavailable [STABLE] Maximum number of unavailable replicas during a rolling update of a deployment.
- # TYPE kube_deployment_spec_strategy_rollingupdate_max_unavailable gauge
- # HELP kube_deployment_spec_strategy_rollingupdate_max_surge [STABLE] Maximum number of replicas that can be scheduled above the desired number of replicas during a rolling update of a deployment.
- # TYPE kube_deployment_spec_strategy_rollingupdate_max_surge gauge
- # HELP kube_deployment_labels [STABLE] Kubernetes labels converted to Prometheus labels.
- # TYPE kube_deployment_labels gauge
- `
+# HELP kube_deployment_annotations Kubernetes annotations converted to Prometheus labels.
+# TYPE kube_deployment_annotations gauge
+# HELP kube_deployment_created [STABLE] Unix creation timestamp
+# TYPE kube_deployment_created gauge
+# HELP kube_deployment_metadata_generation [STABLE] Sequence number representing a specific generation of the desired state.
+# TYPE kube_deployment_metadata_generation gauge
+# HELP kube_deployment_spec_paused [STABLE] Whether the deployment is paused and will not be processed by the deployment controller.
+# TYPE kube_deployment_spec_paused gauge
+# HELP kube_deployment_spec_replicas [STABLE] Number of desired pods for a deployment.
+# TYPE kube_deployment_spec_replicas gauge
+# HELP kube_deployment_status_replicas [STABLE] The number of replicas per deployment.
+# TYPE kube_deployment_status_replicas gauge
+# HELP kube_deployment_status_replicas_ready [STABLE] The number of ready replicas per deployment.
+# TYPE kube_deployment_status_replicas_ready gauge
+# HELP kube_deployment_status_replicas_available [STABLE] The number of available replicas per deployment.
+# TYPE kube_deployment_status_replicas_available gauge
+# HELP kube_deployment_status_replicas_unavailable [STABLE] The number of unavailable replicas per deployment.
+# TYPE kube_deployment_status_replicas_unavailable gauge
+# HELP kube_deployment_status_replicas_updated [STABLE] The number of updated replicas per deployment.
+# TYPE kube_deployment_status_replicas_updated gauge
+# HELP kube_deployment_status_observed_generation [STABLE] The generation observed by the deployment controller.
+# TYPE kube_deployment_status_observed_generation gauge
+# HELP kube_deployment_status_condition [STABLE] The current status conditions of a deployment.
+# TYPE kube_deployment_status_condition gauge
+# HELP kube_deployment_spec_strategy_rollingupdate_max_unavailable [STABLE] Maximum number of unavailable replicas during a rolling update of a deployment.
+# TYPE kube_deployment_spec_strategy_rollingupdate_max_unavailable gauge
+# HELP kube_deployment_spec_strategy_rollingupdate_max_surge [STABLE] Maximum number of replicas that can be scheduled above the desired number of replicas during a rolling update of a deployment.
+# TYPE kube_deployment_spec_strategy_rollingupdate_max_surge gauge
+# HELP kube_deployment_spec_topology_spread_constraints [STABLE] Number of topology spread constraints in the deployment's pod template.
+# TYPE kube_deployment_spec_topology_spread_constraints gauge
+# HELP kube_deployment_labels [STABLE] Kubernetes labels converted to Prometheus labels.
+# TYPE kube_deployment_labels gauge
+`
+
cases := []generateMetricsTestCase{
{
AllowAnnotationsList: []string{"company.io/team"},
@@ -110,28 +111,45 @@ func TestDeploymentStore(t *testing.T) {
MaxSurge: &depl1MaxSurge,
},
},
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{
+ TopologySpreadConstraints: []corev1.TopologySpreadConstraint{
+ {
+ MaxSkew: 1,
+ TopologyKey: "kubernetes.io/zone",
+ WhenUnsatisfiable: corev1.DoNotSchedule,
+ },
+ {
+ MaxSkew: 1,
+ TopologyKey: "kubernetes.io/hostname",
+ WhenUnsatisfiable: corev1.ScheduleAnyway,
+ },
+ },
+ },
+ },
},
},
Want: metadata + `
- kube_deployment_annotations{annotation_company_io_team="my-brilliant-team",deployment="depl1",namespace="ns1"} 1
- kube_deployment_created{deployment="depl1",namespace="ns1"} 1.5e+09
- kube_deployment_metadata_generation{deployment="depl1",namespace="ns1"} 21
- kube_deployment_spec_paused{deployment="depl1",namespace="ns1"} 0
- kube_deployment_spec_replicas{deployment="depl1",namespace="ns1"} 200
- kube_deployment_spec_strategy_rollingupdate_max_surge{deployment="depl1",namespace="ns1"} 10
- kube_deployment_spec_strategy_rollingupdate_max_unavailable{deployment="depl1",namespace="ns1"} 10
- kube_deployment_status_observed_generation{deployment="depl1",namespace="ns1"} 111
- kube_deployment_status_replicas_available{deployment="depl1",namespace="ns1"} 10
- kube_deployment_status_replicas_unavailable{deployment="depl1",namespace="ns1"} 5
- 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_annotations{annotation_company_io_team="my-brilliant-team",deployment="depl1",namespace="ns1"} 1
+kube_deployment_created{deployment="depl1",namespace="ns1"} 1.5e+09
+kube_deployment_metadata_generation{deployment="depl1",namespace="ns1"} 21
+kube_deployment_spec_paused{deployment="depl1",namespace="ns1"} 0
+kube_deployment_spec_replicas{deployment="depl1",namespace="ns1"} 200
+kube_deployment_spec_strategy_rollingupdate_max_surge{deployment="depl1",namespace="ns1"} 10
+kube_deployment_spec_strategy_rollingupdate_max_unavailable{deployment="depl1",namespace="ns1"} 10
+kube_deployment_spec_topology_spread_constraints{deployment="depl1",namespace="ns1"} 2
+kube_deployment_status_observed_generation{deployment="depl1",namespace="ns1"} 111
+kube_deployment_status_replicas_available{deployment="depl1",namespace="ns1"} 10
+kube_deployment_status_replicas_unavailable{deployment="depl1",namespace="ns1"} 5
+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
`,
},
{
@@ -166,29 +184,35 @@ func TestDeploymentStore(t *testing.T) {
MaxSurge: &depl2MaxSurge,
},
},
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{
+ TopologySpreadConstraints: []corev1.TopologySpreadConstraint{},
+ },
+ },
},
},
Want: metadata + `
- kube_deployment_metadata_generation{deployment="depl2",namespace="ns2"} 14
- kube_deployment_spec_paused{deployment="depl2",namespace="ns2"} 1
- kube_deployment_spec_replicas{deployment="depl2",namespace="ns2"} 5
- kube_deployment_spec_strategy_rollingupdate_max_surge{deployment="depl2",namespace="ns2"} 1
- kube_deployment_spec_strategy_rollingupdate_max_unavailable{deployment="depl2",namespace="ns2"} 1
- kube_deployment_status_observed_generation{deployment="depl2",namespace="ns2"} 1111
- kube_deployment_status_replicas_available{deployment="depl2",namespace="ns2"} 5
- kube_deployment_status_replicas_unavailable{deployment="depl2",namespace="ns2"} 0
- 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_metadata_generation{deployment="depl2",namespace="ns2"} 14
+kube_deployment_spec_paused{deployment="depl2",namespace="ns2"} 1
+kube_deployment_spec_replicas{deployment="depl2",namespace="ns2"} 5
+kube_deployment_spec_strategy_rollingupdate_max_surge{deployment="depl2",namespace="ns2"} 1
+kube_deployment_spec_strategy_rollingupdate_max_unavailable{deployment="depl2",namespace="ns2"} 1
+kube_deployment_spec_topology_spread_constraints{deployment="depl2",namespace="ns2"} 0
+kube_deployment_status_observed_generation{deployment="depl2",namespace="ns2"} 1111
+kube_deployment_status_replicas_available{deployment="depl2",namespace="ns2"} 5
+kube_deployment_status_replicas_unavailable{deployment="depl2",namespace="ns2"} 0
+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
`,
},
}