Skip to content

Commit e88557e

Browse files
ryotaraiutam0k
andauthored
feat: Expose HRQ limit and usage on metrics endpoint. (#30)
* feat: Expose HRQ limit and usage on metrics endpoint. * docs: Add metrics documentation for HierarchicalResourceQuotas * Use AsApproximateFloat64 to get the value. Co-authored-by: Toru Komatsu <[email protected]> * fix: Remove unnecessary error handling for quantity value in HRQ metrics collection --------- Co-authored-by: Toru Komatsu <[email protected]>
1 parent 09f25e5 commit e88557e

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

docs/user-guide/metrics.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Metrics
2+
3+
The metrics endpoint is exposed on `:8080` by default (customizable with the `-metrics-addr` flag).
4+
5+
## Metric List
6+
7+
### `hnc_hierarchicalresourcequota`
8+
9+
This metric exposes resource limits and usage for HierarchicalResourceQuotas.
10+
11+
#### Labels
12+
13+
- `hrq`: Name of the HierarchicalResourceQuota
14+
- `namespace`: Namespace of the HierarchicalResourceQuota
15+
- `resource`: Resource type (e.g., `cpu`, `memory`, `pods`)
16+
- `type`: Either `hard` (limit) or `used` (current usage)
17+
18+
#### Example
19+
20+
```
21+
# HELP hnc_hierarchicalresourcequota HRQ hard/used like kube_resourcequota
22+
# TYPE hnc_hierarchicalresourcequota gauge
23+
hnc_hierarchicalresourcequota{hrq="team-quota",namespace="team-a",resource="cpu",type="hard"} 100
24+
hnc_hierarchicalresourcequota{hrq="team-quota",namespace="team-a",resource="cpu",type="used"} 45
25+
hnc_hierarchicalresourcequota{hrq="team-quota",namespace="team-a",resource="memory",type="hard"} 536870912
26+
hnc_hierarchicalresourcequota{hrq="team-quota",namespace="team-a",resource="memory",type="used"} 268435456
27+
```

internal/hrq/metrics.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package hrq
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/go-logr/logr"
8+
"github.com/prometheus/client_golang/prometheus"
9+
corev1 "k8s.io/api/core/v1"
10+
ctrl "sigs.k8s.io/controller-runtime"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
"sigs.k8s.io/controller-runtime/pkg/metrics"
13+
14+
api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
15+
)
16+
17+
func RegisterMetrics(mgr ctrl.Manager) error {
18+
if err := metrics.Registry.Register(&hrqCollector{
19+
client: mgr.GetClient(),
20+
logger: mgr.GetLogger().WithValues("collector", "hrqCollector"),
21+
timeout: time.Second * 10,
22+
}); err != nil {
23+
return err
24+
}
25+
return nil
26+
}
27+
28+
type hrqCollector struct {
29+
timeout time.Duration
30+
client client.Client
31+
logger logr.Logger
32+
}
33+
34+
func (c *hrqCollector) desc() *prometheus.Desc {
35+
return prometheus.NewDesc(
36+
"hnc_hierarchicalresourcequota",
37+
"HRQ hard/used like kube_resourcequota",
38+
[]string{"namespace", "hrq", "resource", "type"},
39+
nil,
40+
)
41+
}
42+
43+
func (c *hrqCollector) Describe(ch chan<- *prometheus.Desc) {
44+
ch <- c.desc()
45+
}
46+
47+
func (c *hrqCollector) Collect(ch chan<- prometheus.Metric) {
48+
ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
49+
defer cancel()
50+
51+
var hrqs api.HierarchicalResourceQuotaList
52+
if err := c.client.List(ctx, &hrqs); err != nil {
53+
c.logger.Error(err, "Failed to list HRQs during metrics collection")
54+
return
55+
}
56+
57+
for _, hrq := range hrqs.Items {
58+
for typeLabel, resList := range map[string]corev1.ResourceList{
59+
"hard": hrq.Status.Hard,
60+
"used": hrq.Status.Used,
61+
} {
62+
for res, qty := range resList {
63+
v := qty.AsApproximateFloat64()
64+
ch <- prometheus.MustNewConstMetric(
65+
c.desc(),
66+
prometheus.GaugeValue,
67+
float64(v),
68+
hrq.Namespace,
69+
hrq.Name,
70+
string(res),
71+
typeLabel,
72+
)
73+
}
74+
}
75+
}
76+
}

internal/setup/reconcilers.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ func CreateReconcilers(mgr ctrl.Manager, f *forest.Forest, opts Options) error {
109109
if opts.HRQSyncInterval != 0 {
110110
go watchHRQDrift(f, opts.HRQSyncInterval, hrqr)
111111
}
112+
113+
if err := hrq.RegisterMetrics(mgr); err != nil {
114+
return fmt.Errorf("cannot register HRQ metrics: %w", err)
115+
}
112116
}
113117

114118
if err := ar.SetupWithManager(mgr); err != nil {

0 commit comments

Comments
 (0)