Skip to content

Commit 88eb7f8

Browse files
xcoulonrsoaresdMatousJobanek
authored
test(registration-service): expose metrics for the git commit (#1269)
also, test new `commit` and `short_commit` metrics for host and member operators --------- Signed-off-by: Xavier Coulon <xcoulon@redhat.com> Co-authored-by: Rafaela Maria Soares da Silva <rsoaresd@redhat.com> Co-authored-by: Matous Jobanek <mjobanek@redhat.com>
1 parent db61aea commit 88eb7f8

File tree

7 files changed

+155
-64
lines changed

7 files changed

+155
-64
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/e2e/parallel/registration_service_test.go

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,11 @@ import (
2323
"github.com/codeready-toolchain/toolchain-e2e/testsupport/wait"
2424
"github.com/davecgh/go-spew/spew"
2525
"github.com/gofrs/uuid"
26-
routev1 "github.com/openshift/api/route/v1"
2726
"github.com/stretchr/testify/assert"
2827
"github.com/stretchr/testify/require"
2928
corev1 "k8s.io/api/core/v1"
3029
apierrors "k8s.io/apimachinery/pkg/api/errors"
31-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3230
"k8s.io/apimachinery/pkg/types"
33-
"k8s.io/apimachinery/pkg/util/intstr"
3431
k8swait "k8s.io/apimachinery/pkg/util/wait"
3532
)
3633

@@ -73,27 +70,10 @@ func TestRegistrationServiceMetricsEndpoint(t *testing.T) {
7370

7471
t.Run("available from a custom route", func(t *testing.T) { // create a route for to expose the `registration-service-metrics` svc
7572
// given
76-
route := &routev1.Route{
77-
ObjectMeta: metav1.ObjectMeta{
78-
Namespace: await.Host().Namespace,
79-
Name: "registration-service-metrics",
80-
},
81-
Spec: routev1.RouteSpec{
82-
To: routev1.RouteTargetReference{
83-
Kind: "Service",
84-
Name: "registration-service-metrics",
85-
},
86-
Port: &routev1.RoutePort{
87-
TargetPort: intstr.FromString("regsvc-metrics"),
88-
},
89-
},
90-
}
91-
err := await.Host().CreateWithCleanup(t, route)
92-
require.NoError(t, err)
93-
_, err = await.Host().WaitForRouteToBeAvailable(t, route.Namespace, route.Name, "/metrics")
94-
require.NoError(t, err, "route not available", route)
73+
route, err := await.Host().WaitForRouteToBeAvailable(t, await.Host().Namespace, "registration-service-metrics", "/metrics")
74+
require.NoError(t, err, "route not available", "registration-service-metrics")
9575

96-
req, err := http.NewRequest("GET", "http://"+route.Spec.Host+"/metrics", nil)
76+
req, err := http.NewRequest("GET", "https://"+route.Spec.Host+"/metrics", nil)
9777
require.NoError(t, err)
9878
// when
9979
resp, err := httpClient.Do(req) // nolint:bodyclose // see `defer Close(t, resp)`

test/metrics/metrics_test.go

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,52 @@ 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)
3938

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

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

4970
t.Run("member-operators", func(t *testing.T) {
5071
// given
5172
member1Await := awaitilities.Member1()
52-
member2Await := awaitilities.Member1()
73+
member2Await := awaitilities.Member2()
5374
// member metrics should be available at this point
5475
member1Await.InitMetrics(t)
5576
member2Await.InitMetrics(t)
5677

5778
// --- member1 ---
5879
// when
59-
labels := member1Await.GetMetricLabels(t, wait.MemberOperatorVersionMetric)
80+
labels := member1Await.GetMetricLabels(t, member1Await.MetricsURL, wait.MemberOperatorVersionMetric)
6081

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

6687
// --- member2 ---
6788
// when
68-
labels = member2Await.GetMetricLabels(t, wait.MemberOperatorVersionMetric)
89+
labels = member2Await.GetMetricLabels(t, member2Await.MetricsURL, wait.MemberOperatorVersionMetric)
6990

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

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

testsupport/init.go

Lines changed: 48 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,46 @@ 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)
218+
require.NotEmpty(t, hostMetricsRoute.Status.Ingress, "route has no ingress status for host metrics service")
210219
initHostAwait.MetricsURL = "https://" + hostMetricsRoute.Status.Ingress[0].Host
220+
t.Logf("host metrics URL: %s", initHostAwait.MetricsURL)
221+
222+
// setup registration service metrics route for metrics verification in tests
223+
registrationServiceMetricsRoute, err := initHostAwait.SetupRouteForService(t, "registration-service-metrics", "/metrics",
224+
&routev1.RoutePort{
225+
TargetPort: intstr.FromString("regsvc-metrics"),
226+
},
227+
&routev1.TLSConfig{
228+
Termination: routev1.TLSTerminationEdge,
229+
},
230+
)
231+
require.NoError(t, err)
232+
require.NotEmpty(t, registrationServiceMetricsRoute.Status.Ingress, "route has no ingress status for registration service metrics service")
233+
initHostAwait.RegistrationServiceMetricsURL = "https://" + registrationServiceMetricsRoute.Status.Ingress[0].Host
234+
t.Logf("registration service metrics URL: %s", initHostAwait.RegistrationServiceMetricsURL)
211235

212236
// setup member metrics route for metrics verification in tests
213-
memberMetricsRoute, err := initMemberAwait.SetupRouteForService(t, "member-operator-metrics-service", "/metrics")
237+
memberMetricsRoute, err := initMemberAwait.SetupRouteForService(t, "member-operator-metrics-service", "/metrics",
238+
&routev1.RoutePort{
239+
TargetPort: intstr.FromString("https"),
240+
},
241+
&routev1.TLSConfig{
242+
Termination: routev1.TLSTerminationPassthrough,
243+
},
244+
)
214245
require.NoError(t, err, "failed while setting up or waiting for the route to the 'member-operator-metrics' service to be available")
246+
require.NotEmpty(t, memberMetricsRoute.Status.Ingress, "route has no ingress status for member metrics service")
215247
initMemberAwait.MetricsURL = "https://" + memberMetricsRoute.Status.Ingress[0].Host
248+
t.Logf("member metrics URL: %s", initMemberAwait.MetricsURL)
216249

217250
// Wait for the webhooks in Member 1 only because we do not deploy webhooks for Member 2
218251
// (we can't deploy the same webhook multiple times on the same cluster)
@@ -222,6 +255,19 @@ func WaitForDeployments(t *testing.T) wait.Awaitilities {
222255
if IsSecondMemberMode(t) {
223256
err = initMember2Await.WaitUntilWebhookDeleted(t) // webhook on member2 should be deleted
224257
require.NoError(t, err)
258+
memberMetricsRoute, err := initMember2Await.SetupRouteForService(t, "member-operator-metrics-service", "/metrics",
259+
&routev1.RoutePort{
260+
TargetPort: intstr.FromString("https"),
261+
},
262+
&routev1.TLSConfig{
263+
Termination: routev1.TLSTerminationPassthrough,
264+
},
265+
)
266+
require.NoError(t, err, "failed while setting up or waiting for the route to the 'member-operator-metrics' service to be available")
267+
require.NotEmpty(t, memberMetricsRoute.Status.Ingress, "route has no ingress status for member metrics service")
268+
initMember2Await.MetricsURL = "https://" + memberMetricsRoute.Status.Ingress[0].Host
269+
t.Logf("member metrics URL: %s", initMember2Await.MetricsURL)
270+
225271
}
226272
initMemberAwait.WaitForMemberWebhooks(t, webhookImage)
227273

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)