Skip to content

Commit a75907b

Browse files
committed
test(registration-service): expose metrics for the git commit
also, test new `commit` and `short_commit` metrics for host and member operators Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
1 parent 3c9d868 commit a75907b

File tree

6 files changed

+137
-40
lines changed

6 files changed

+137
-40
lines changed

.govulncheck.yaml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,14 @@
1-
ignored-vulnerabilities: []
1+
ignored-vulnerabilities:
2+
# Incorrect parsing of IPv6 host literals in net/url
3+
# Found in: net/url@go1.24.13
4+
# Fixed in: net/url@go1.25.8
5+
- id: GO-2026-4601
6+
info: https://pkg.go.dev/vuln/GO-2026-4601
7+
silence-until: 2026-04-23
8+
# FileInfo can escape from a Root in os
9+
# Found in: os@go1.24.13
10+
# Fixed in: os@go1.25.8
11+
- id: GO-2026-4602
12+
info: https://pkg.go.dev/vuln/GO-2026-4602
13+
silence-until: 2026-04-23
14+

test/metrics/metrics_test.go

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,41 @@ func TestOperatorVersionMetrics(t *testing.T) {
3232
awaitilities := WaitForDeployments(t)
3333

3434
t.Run("host-operator", func(t *testing.T) {
35+
3536
// given
3637
hostAwait := awaitilities.Host()
37-
// host metrics should be available at this point
38-
hostAwait.InitMetrics(t, awaitilities.Member1().ClusterName, awaitilities.Member2().ClusterName)
38+
_, err := hostAwait.WaitForRouteToBeAvailable(t, hostAwait.Namespace, "host-operator-metrics-service", "/metrics")
39+
require.NoError(t, err)
3940

40-
// when
41-
labels := hostAwait.GetMetricLabels(t, wait.HostOperatorVersionMetric)
41+
t.Run("commit", func(t *testing.T) {
42+
// when
43+
labels := hostAwait.GetMetricLabels(t, hostAwait.MetricsURL, wait.HostOperatorCommitMetric)
4244

43-
// verify that the "version" metric exists for Host Operator and that it has a non-empty `commit` label
44-
require.Len(t, labels, 1)
45-
commit := labels[0]["commit"]
46-
assert.Len(t, commit, 7)
45+
// verify that the "version" metric exists for Host Operator and that it has a non-empty `commit` label
46+
require.Len(t, labels, 1)
47+
commit := labels[0]["commit"]
48+
assert.Len(t, commit, len("e6a12a442a60dfd86d348a030ad2e789c79184b5")) // example value: 40 characters
49+
})
50+
51+
t.Run("short commit", func(t *testing.T) {
52+
// when
53+
labels := hostAwait.GetMetricLabels(t, hostAwait.MetricsURL, wait.HostOperatorShortCommitMetric)
54+
55+
// verify that the "version" metric exists for Host Operator and that it has a non-empty `commit` label
56+
require.Len(t, labels, 1)
57+
commit := labels[0]["commit"]
58+
assert.Len(t, commit, 7)
59+
})
60+
61+
t.Run("version", func(t *testing.T) {
62+
// when
63+
labels := hostAwait.GetMetricLabels(t, hostAwait.MetricsURL, wait.HostOperatorVersionMetric)
64+
65+
// verify that the "version" metric exists for Host Operator and that it has a non-empty `commit` label
66+
require.Len(t, labels, 1)
67+
commit := labels[0]["commit"]
68+
assert.Len(t, commit, 7)
69+
})
4770
})
4871

4972
t.Run("member-operators", func(t *testing.T) {
@@ -56,7 +79,7 @@ func TestOperatorVersionMetrics(t *testing.T) {
5679

5780
// --- member1 ---
5881
// when
59-
labels := member1Await.GetMetricLabels(t, wait.MemberOperatorVersionMetric)
82+
labels := member1Await.GetMetricLabels(t, member1Await.MetricsURL, wait.MemberOperatorVersionMetric)
6083

6184
// verify that the "version" metric exists for the first Member Operator and that it has a non-empty `commit` label
6285
require.Len(t, labels, 1)
@@ -65,7 +88,7 @@ func TestOperatorVersionMetrics(t *testing.T) {
6588

6689
// --- member2 ---
6790
// when
68-
labels = member2Await.GetMetricLabels(t, wait.MemberOperatorVersionMetric)
91+
labels = member2Await.GetMetricLabels(t, member2Await.MetricsURL, wait.MemberOperatorVersionMetric)
6992

7093
// verify that the "version" metric exists for the second Member Operator and that it has a non-empty `commit` label
7194
require.Len(t, labels, 1)
@@ -75,6 +98,35 @@ func TestOperatorVersionMetrics(t *testing.T) {
7598
// expect the same version on member1 and member2
7699
assert.Equal(t, commit1, commit2)
77100
})
101+
102+
t.Run("registration-service", func(t *testing.T) {
103+
104+
// given
105+
hostAwait := awaitilities.Host()
106+
_, err := hostAwait.WaitForRouteToBeAvailable(t, hostAwait.Namespace, "host-operator-metrics-service", "/metrics")
107+
require.NoError(t, err)
108+
109+
t.Run("commit", func(t *testing.T) {
110+
// when
111+
labels := hostAwait.GetMetricLabels(t, hostAwait.RegistrationServiceMetricsURL, wait.RegistrationServiceCommitMetric)
112+
113+
// verify that the "version" metric exists for Host Operator and that it has a non-empty `commit` label
114+
require.Len(t, labels, 1)
115+
commit := labels[0]["commit"]
116+
assert.Len(t, commit, len("da3f54634cc65075d51d067a157831d44bf1413e")) // example value: 40 characters
117+
})
118+
119+
t.Run("short commit", func(t *testing.T) {
120+
// when
121+
labels := hostAwait.GetMetricLabels(t, hostAwait.RegistrationServiceMetricsURL, wait.RegistrationServiceShortCommitMetric)
122+
123+
// verify that the "version" metric exists for Host Operator and that it has a non-empty `commit` label
124+
require.Len(t, labels, 1)
125+
commit := labels[0]["commit"]
126+
assert.Len(t, commit, 7)
127+
})
128+
})
129+
78130
}
79131

80132
// TestMetricsWhenUsersManuallyApproved verifies that `UserSignupsApprovedMetric` and `UserSignupsApprovedWithMethodMetric` counters are increased when users are approved

testsupport/init.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3535
"k8s.io/apimachinery/pkg/runtime"
3636
"k8s.io/apimachinery/pkg/types"
37+
"k8s.io/apimachinery/pkg/util/intstr"
3738
"k8s.io/client-go/rest"
3839
"k8s.io/client-go/tools/clientcmd"
3940
"k8s.io/client-go/tools/clientcmd/api"
@@ -205,14 +206,43 @@ func WaitForDeployments(t *testing.T) wait.Awaitilities {
205206
require.NoError(t, err, "failed to find proxy metrics service")
206207

207208
// setup host metrics route for metrics verification in tests
208-
hostMetricsRoute, err := initHostAwait.SetupRouteForService(t, "host-operator-metrics-service", "/metrics")
209+
hostMetricsRoute, err := initHostAwait.SetupRouteForService(t, "host-operator-metrics-service", "/metrics",
210+
&routev1.RoutePort{
211+
TargetPort: intstr.FromString("https"),
212+
},
213+
&routev1.TLSConfig{
214+
Termination: routev1.TLSTerminationPassthrough,
215+
},
216+
)
209217
require.NoError(t, err)
210218
initHostAwait.MetricsURL = "https://" + hostMetricsRoute.Status.Ingress[0].Host
219+
t.Logf("host metrics URL: %s", initHostAwait.MetricsURL)
220+
221+
// setup registration service metrics route for metrics verification in tests
222+
registrationServiceMetricsRoute, err := initHostAwait.SetupRouteForService(t, "registration-service-metrics", "/metrics",
223+
&routev1.RoutePort{
224+
TargetPort: intstr.FromString("regsvc-metrics"),
225+
},
226+
&routev1.TLSConfig{
227+
Termination: routev1.TLSTerminationEdge,
228+
},
229+
)
230+
require.NoError(t, err)
231+
initHostAwait.RegistrationServiceMetricsURL = "https://" + registrationServiceMetricsRoute.Status.Ingress[0].Host
232+
t.Logf("registration service metrics URL: %s", initHostAwait.RegistrationServiceMetricsURL)
211233

212234
// setup member metrics route for metrics verification in tests
213-
memberMetricsRoute, err := initMemberAwait.SetupRouteForService(t, "member-operator-metrics-service", "/metrics")
235+
memberMetricsRoute, err := initMemberAwait.SetupRouteForService(t, "member-operator-metrics-service", "/metrics",
236+
&routev1.RoutePort{
237+
TargetPort: intstr.FromString("https"),
238+
},
239+
&routev1.TLSConfig{
240+
Termination: routev1.TLSTerminationPassthrough,
241+
},
242+
)
214243
require.NoError(t, err, "failed while setting up or waiting for the route to the 'member-operator-metrics' service to be available")
215244
initMemberAwait.MetricsURL = "https://" + memberMetricsRoute.Status.Ingress[0].Host
245+
t.Logf("member metrics URL: %s", initMemberAwait.MetricsURL)
216246

217247
// Wait for the webhooks in Member 1 only because we do not deploy webhooks for Member 2
218248
// (we can't deploy the same webhook multiple times on the same cluster)

testsupport/metrics/metrics.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,14 @@ func getBuckets(t dto.MetricType, m *dto.Metric) (*[]*dto.Bucket, error) {
129129

130130
// GetMetricLabels return all labels (indexed by key) for all metrics of the given `family`
131131
func GetMetricLabels(restConfig *rest.Config, baseURL string, family string) ([]map[string]string, error) {
132-
uri := baseURL + "/metrics"
133-
var metrics []byte
134-
135132
client := http.Client{
136133
Timeout: time.Duration(30 * time.Second),
137134
Transport: &http.Transport{
138135
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
139136
},
140137
}
141-
request, err := http.NewRequest("Get", uri, nil)
138+
uri := baseURL + "/metrics"
139+
request, err := http.NewRequest("GET", uri, nil)
142140
if err != nil {
143141
return nil, err
144142
}
@@ -150,6 +148,7 @@ func GetMetricLabels(restConfig *rest.Config, baseURL string, family string) ([]
150148
defer func() {
151149
_ = resp.Body.Close()
152150
}()
151+
var metrics []byte
153152
metrics, err = io.ReadAll(resp.Body)
154153
if err != nil {
155154
return nil, err

testsupport/wait/awaitility.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import (
3232
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3333
"k8s.io/apimachinery/pkg/runtime/schema"
3434
"k8s.io/apimachinery/pkg/types"
35-
"k8s.io/apimachinery/pkg/util/intstr"
3635
"k8s.io/apimachinery/pkg/util/wait"
3736
"k8s.io/client-go/rest"
3837
"k8s.io/kubectl/pkg/util/podutils"
@@ -210,8 +209,8 @@ func (a *Awaitility) GetToolchainCluster(t *testing.T, namespace string, cdtype
210209
// SetupRouteForService if needed, creates a route for the given service (with the same namespace/name)
211210
// It waits until the route is available (or returns an error) by first checking the resource status
212211
// and then making a call to the given endpoint
213-
func (a *Awaitility) SetupRouteForService(t *testing.T, serviceName, endpoint string) (routev1.Route, error) {
214-
t.Logf("setting up route for service '%s' with endpoint '%s'", serviceName, endpoint)
212+
func (a *Awaitility) SetupRouteForService(t *testing.T, serviceName string, path string, port *routev1.RoutePort, tlsConfig *routev1.TLSConfig) (routev1.Route, error) {
213+
t.Logf("setting up route for service '%s' with endpoint '%s'", serviceName, path)
215214
service, err := a.WaitForService(t, serviceName)
216215
if err != nil {
217216
return routev1.Route{}, err
@@ -230,28 +229,24 @@ func (a *Awaitility) SetupRouteForService(t *testing.T, serviceName, endpoint st
230229
Name: service.Name,
231230
},
232231
Spec: routev1.RouteSpec{
233-
Port: &routev1.RoutePort{
234-
TargetPort: intstr.FromString("https"),
235-
},
236-
TLS: &routev1.TLSConfig{
237-
Termination: routev1.TLSTerminationPassthrough,
238-
},
239232
To: routev1.RouteTargetReference{
240233
Kind: service.Kind,
241234
Name: service.Name,
242235
},
236+
Port: port,
237+
TLS: tlsConfig,
243238
},
244239
}
245240
if err = a.Client.Create(context.TODO(), &route); err != nil {
246241
return route, err
247242
}
248243
}
249-
return a.WaitForRouteToBeAvailable(t, route.Namespace, route.Name, endpoint)
244+
return a.WaitForRouteToBeAvailable(t, route.Namespace, route.Name, path)
250245
}
251246

252247
// WaitForRouteToBeAvailable waits until the given route is available, ie, it has an Ingress with a host configured
253248
// and the endpoint is reachable (with a `200 OK` status response)
254-
func (a *Awaitility) WaitForRouteToBeAvailable(t *testing.T, ns, name, endpoint string) (routev1.Route, error) {
249+
func (a *Awaitility) WaitForRouteToBeAvailable(t *testing.T, ns, name, path string) (routev1.Route, error) {
255250
t.Logf("waiting for route '%s' in namespace '%s'", name, ns)
256251
route := routev1.Route{}
257252
// retrieve the route for the registration service
@@ -282,13 +277,13 @@ func (a *Awaitility) WaitForRouteToBeAvailable(t *testing.T, ns, name, endpoint
282277
InsecureSkipVerify: true, // nolint:gosec
283278
},
284279
}
285-
request, err = http.NewRequest("GET", "https://"+route.Status.Ingress[0].Host+endpoint, nil)
280+
request, err = http.NewRequest("GET", "https://"+route.Status.Ingress[0].Host+path, nil)
286281
if err != nil {
287282
return false, err
288283
}
289284
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.RestConfig.BearerToken))
290285
} else {
291-
request, err = http.NewRequest("GET", "http://"+route.Status.Ingress[0].Host+endpoint, nil)
286+
request, err = http.NewRequest("GET", "http://"+route.Status.Ingress[0].Host+path, nil)
292287
if err != nil {
293288
return false, err
294289
}
@@ -335,8 +330,9 @@ func (a *Awaitility) GetHistogramValues(t *testing.T, family string, labelAndVal
335330

336331
// GetMetricValue gets the value of the metric with the given family and label key-value pair
337332
// fails if the metric with the given labelAndValues does not exist
338-
func (a *Awaitility) GetMetricLabels(t *testing.T, family string) []map[string]string {
339-
labels, err := metrics.GetMetricLabels(a.RestConfig, a.MetricsURL, family)
333+
func (a *Awaitility) GetMetricLabels(t *testing.T, metricsURL, family string) []map[string]string {
334+
t.Logf("getting labels for metric '%s' from '%s'", family, metricsURL)
335+
labels, err := metrics.GetMetricLabels(a.RestConfig, metricsURL, family)
340336
require.NoError(t, err)
341337
return labels
342338
}

testsupport/wait/host.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@ var (
5858
// HostAwaitility the Awaitility for the Host cluster
5959
type HostAwaitility struct {
6060
*Awaitility
61-
RegistrationServiceNs string
62-
RegistrationServiceURL string
63-
APIProxyURL string
61+
RegistrationServiceNs string
62+
RegistrationServiceURL string
63+
RegistrationServiceMetricsURL string
64+
APIProxyURL string
6465
}
6566

6667
// NewHostAwaitility initializes a HostAwaitility
@@ -81,10 +82,11 @@ func NewHostAwaitility(cfg *rest.Config, cl client.Client, ns string, registrati
8182
// WithRetryOptions returns a new HostAwaitility with the given RetryOptions applied
8283
func (a *HostAwaitility) WithRetryOptions(options ...RetryOption) *HostAwaitility {
8384
return &HostAwaitility{
84-
Awaitility: a.Awaitility.WithRetryOptions(options...),
85-
RegistrationServiceNs: a.RegistrationServiceNs,
86-
RegistrationServiceURL: a.RegistrationServiceURL,
87-
APIProxyURL: a.APIProxyURL,
85+
Awaitility: a.Awaitility.WithRetryOptions(options...),
86+
RegistrationServiceNs: a.RegistrationServiceNs,
87+
RegistrationServiceURL: a.RegistrationServiceURL,
88+
RegistrationServiceMetricsURL: a.RegistrationServiceMetricsURL,
89+
APIProxyURL: a.APIProxyURL,
8890
}
8991
}
9092

@@ -111,7 +113,12 @@ const (
111113

112114
UsersPerActivationsAndDomainMetric = "sandbox_users_per_activations_and_domain"
113115

114-
HostOperatorVersionMetric = "sandbox_host_operator_version"
116+
HostOperatorVersionMetric = "sandbox_host_operator_version" // DEPRECATED: use HostOperatorCommitMetric instead
117+
HostOperatorCommitMetric = "sandbox_host_operator_commit"
118+
HostOperatorShortCommitMetric = "sandbox_host_operator_short_commit"
119+
120+
RegistrationServiceCommitMetric = "sandbox_registration_service_commit"
121+
RegistrationServiceShortCommitMetric = "sandbox_registration_service_short_commit"
115122

116123
SignupProvisionTimeMetric = "sandbox_user_signup_provision_time"
117124
)

0 commit comments

Comments
 (0)