@@ -19,50 +19,57 @@ import (
1919 "fmt"
2020 "io"
2121 "os/exec"
22- "strings"
2322 "testing"
2423 "time"
2524
2625 "github.com/stretchr/testify/require"
26+ "k8s.io/apimachinery/pkg/util/rand"
2727
2828 "github.com/operator-framework/operator-controller/test/utils"
2929)
3030
3131// TestOperatorControllerMetricsExportedEndpoint verifies that the metrics endpoint for the operator controller
3232func TestOperatorControllerMetricsExportedEndpoint (t * testing.T ) {
3333 client := utils .FindK8sClient (t )
34+ curlNamespace := createRandomNamespace (t , client )
35+ componentNamespace := getComponentNamespace (t , client , "control-plane=operator-controller-controller-manager" )
36+ metricsURL := fmt .Sprintf ("https://operator-controller-service.%s.svc.cluster.local:8443/metrics" , componentNamespace )
37+
3438 config := NewMetricsTestConfig (
35- t , client ,
36- "control-plane=operator-controller-controller-manager" ,
39+ client ,
40+ curlNamespace ,
3741 "operator-controller-metrics-reader" ,
3842 "operator-controller-metrics-binding" ,
39- "operator-controller-controller-manager " ,
43+ "operator-controller-metrics-reader " ,
4044 "oper-curl-metrics" ,
41- "https://operator-controller-service.NAMESPACE.svc.cluster.local:8443/metrics" ,
45+ metricsURL ,
4246 )
4347
44- config .run ()
48+ config .run (t )
4549}
4650
4751// TestCatalogdMetricsExportedEndpoint verifies that the metrics endpoint for catalogd
4852func TestCatalogdMetricsExportedEndpoint (t * testing.T ) {
4953 client := utils .FindK8sClient (t )
54+ curlNamespace := createRandomNamespace (t , client )
55+ componentNamespace := getComponentNamespace (t , client , "control-plane=catalogd-controller-manager" )
56+ metricsURL := fmt .Sprintf ("https://catalogd-service.%s.svc.cluster.local:7443/metrics" , componentNamespace )
57+
5058 config := NewMetricsTestConfig (
51- t , client ,
52- "control-plane=catalogd-controller-manager" ,
59+ client ,
60+ curlNamespace ,
5361 "catalogd-metrics-reader" ,
5462 "catalogd-metrics-binding" ,
55- "catalogd-controller-manager " ,
63+ "catalogd-metrics-reader " ,
5664 "catalogd-curl-metrics" ,
57- "https://catalogd-service.NAMESPACE.svc.cluster.local:7443/metrics" ,
65+ metricsURL ,
5866 )
5967
60- config .run ()
68+ config .run (t )
6169}
6270
6371// MetricsTestConfig holds the necessary configurations for testing metrics endpoints.
6472type MetricsTestConfig struct {
65- t * testing.T
6673 client string
6774 namespace string
6875 clusterRole string
@@ -73,12 +80,8 @@ type MetricsTestConfig struct {
7380}
7481
7582// NewMetricsTestConfig initializes a new MetricsTestConfig.
76- func NewMetricsTestConfig (t * testing.T , client , selector , clusterRole , clusterBinding , serviceAccount , curlPodName , metricsURL string ) * MetricsTestConfig {
77- namespace := getComponentNamespace (t , client , selector )
78- metricsURL = strings .ReplaceAll (metricsURL , "NAMESPACE" , namespace )
79-
83+ func NewMetricsTestConfig (client , namespace , clusterRole , clusterBinding , serviceAccount , curlPodName , metricsURL string ) * MetricsTestConfig {
8084 return & MetricsTestConfig {
81- t : t ,
8285 client : client ,
8386 namespace : namespace ,
8487 clusterRole : clusterRole ,
@@ -90,38 +93,44 @@ func NewMetricsTestConfig(t *testing.T, client, selector, clusterRole, clusterBi
9093}
9194
9295// run will execute all steps of those tests
93- func (c * MetricsTestConfig ) run () {
94- c .createMetricsClusterRoleBinding ()
95- token := c .getServiceAccountToken ()
96- c .createCurlMetricsPod ()
97- c .validate (token )
98- defer c .cleanup ()
96+ func (c * MetricsTestConfig ) run (t * testing.T ) {
97+ defer c .cleanup (t )
98+
99+ c .createMetricsClusterRoleBinding (t )
100+ token := c .getServiceAccountToken (t )
101+ c .createCurlMetricsPod (t )
102+ c .validate (t , token )
99103}
100104
101105// createMetricsClusterRoleBinding to binding and expose the metrics
102- func (c * MetricsTestConfig ) createMetricsClusterRoleBinding () {
103- c . t .Logf ("Creating ClusterRoleBinding %s in namespace %s" , c .clusterBinding , c .namespace )
106+ func (c * MetricsTestConfig ) createMetricsClusterRoleBinding (t * testing. T ) {
107+ t .Logf ("Creating ClusterRoleBinding %s for %s in namespace %s" , c .clusterBinding , c . serviceAccount , c .namespace )
104108 cmd := exec .Command (c .client , "create" , "clusterrolebinding" , c .clusterBinding ,
105109 "--clusterrole=" + c .clusterRole ,
106110 "--serviceaccount=" + c .namespace + ":" + c .serviceAccount )
107111 output , err := cmd .CombinedOutput ()
108- require .NoError (c . t , err , "Error creating ClusterRoleBinding: %s" , string (output ))
112+ require .NoError (t , err , "Error creating ClusterRoleBinding: %s" , string (output ))
109113}
110114
111115// getServiceAccountToken return the token requires to have access to the metrics
112- func (c * MetricsTestConfig ) getServiceAccountToken () string {
113- c .t .Logf ("Generating ServiceAccount token at namespace %s" , c .namespace )
114- cmd := exec .Command (c .client , "create" , "token" , c .serviceAccount , "-n" , c .namespace )
116+ func (c * MetricsTestConfig ) getServiceAccountToken (t * testing.T ) string {
117+ t .Logf ("Creating ServiceAccount %q in namespace %q" , c .serviceAccount , c .namespace )
118+ output , err := exec .Command (c .client , "create" , "serviceaccount" , c .serviceAccount , "--namespace=" + c .namespace ).CombinedOutput ()
119+ require .NoError (t , err , "Error creating service account: %v" , string (output ))
120+
121+ t .Logf ("Generating ServiceAccount token for %q in namespace %q" , c .serviceAccount , c .namespace )
122+ cmd := exec .Command (c .client , "create" , "token" , c .serviceAccount , "--namespace" , c .namespace )
115123 tokenOutput , tokenCombinedOutput , err := stdoutAndCombined (cmd )
116- require .NoError (c . t , err , "Error creating token: %s" , string (tokenCombinedOutput ))
124+ require .NoError (t , err , "Error creating token: %s" , string (tokenCombinedOutput ))
117125 return string (bytes .TrimSpace (tokenOutput ))
118126}
119127
120128// createCurlMetricsPod creates the Pod with curl image to allow check if the metrics are working
121- func (c * MetricsTestConfig ) createCurlMetricsPod () {
122- c . t .Logf ("Creating curl pod (%s/%s) to validate the metrics endpoint" , c .namespace , c .curlPodName )
129+ func (c * MetricsTestConfig ) createCurlMetricsPod (t * testing. T ) {
130+ t .Logf ("Creating curl pod (%s/%s) to validate the metrics endpoint" , c .namespace , c .curlPodName )
123131 cmd := exec .Command (c .client , "run" , c .curlPodName ,
124- "--image=curlimages/curl" , "-n" , c .namespace ,
132+ "--image=curlimages/curl" ,
133+ "--namespace" , c .namespace ,
125134 "--restart=Never" ,
126135 "--overrides" , `{
127136 "spec": {
@@ -142,55 +151,66 @@ func (c *MetricsTestConfig) createCurlMetricsPod() {
142151 }
143152 }` )
144153 output , err := cmd .CombinedOutput ()
145- require .NoError (c . t , err , "Error creating curl pod: %s" , string (output ))
154+ require .NoError (t , err , "Error creating curl pod: %s" , string (output ))
146155}
147156
148157// validate verifies if is possible to access the metrics
149- func (c * MetricsTestConfig ) validate (token string ) {
150- c . t .Log ("Waiting for the curl pod to be ready" )
151- waitCmd := exec .Command (c .client , "wait" , "--for=condition=Ready" , "pod" , c .curlPodName , "-n " , c .namespace , "--timeout=60s" )
158+ func (c * MetricsTestConfig ) validate (t * testing. T , token string ) {
159+ t .Log ("Waiting for the curl pod to be ready" )
160+ waitCmd := exec .Command (c .client , "wait" , "--for=condition=Ready" , "pod" , c .curlPodName , "--namespace " , c .namespace , "--timeout=60s" )
152161 waitOutput , waitErr := waitCmd .CombinedOutput ()
153- require .NoError (c . t , waitErr , "Error waiting for curl pod to be ready: %s" , string (waitOutput ))
162+ require .NoError (t , waitErr , "Error waiting for curl pod to be ready: %s" , string (waitOutput ))
154163
155- c . t .Log ("Validating the metrics endpoint" )
156- curlCmd := exec .Command (c .client , "exec" , c .curlPodName , "-n " , c .namespace , "--" ,
164+ t .Log ("Validating the metrics endpoint" )
165+ curlCmd := exec .Command (c .client , "exec" , c .curlPodName , "--namespace " , c .namespace , "--" ,
157166 "curl" , "-v" , "-k" , "-H" , "Authorization: Bearer " + token , c .metricsURL )
158167 output , err := curlCmd .CombinedOutput ()
159- require .NoError (c . t , err , "Error calling metrics endpoint: %s" , string (output ))
160- require .Contains (c . t , string (output ), "200 OK" , "Metrics endpoint did not return 200 OK" )
168+ require .NoError (t , err , "Error calling metrics endpoint: %s" , string (output ))
169+ require .Contains (t , string (output ), "200 OK" , "Metrics endpoint did not return 200 OK" )
161170}
162171
163172// cleanup removes the created resources. Uses a context with timeout to prevent hangs.
164- func (c * MetricsTestConfig ) cleanup () {
165- c .t .Log ("Cleaning up resources" )
166- _ = exec .Command (c .client , "delete" , "clusterrolebinding" , c .clusterBinding , "--ignore-not-found=true" , "--force" ).Run ()
167- _ = exec .Command (c .client , "delete" , "pod" , c .curlPodName , "-n" , c .namespace , "--ignore-not-found=true" , "--force" ).Run ()
173+ func (c * MetricsTestConfig ) cleanup (t * testing.T ) {
174+ type objDesc struct {
175+ resourceName string
176+ name string
177+ namespace string
178+ }
179+ objects := []objDesc {
180+ {"clusterrolebinding" , c .clusterBinding , "" },
181+ {"pod" , c .curlPodName , c .namespace },
182+ {"serviceaccount" , c .serviceAccount , c .namespace },
183+ {"namespace" , c .namespace , "" },
184+ }
185+
186+ t .Log ("Cleaning up resources" )
187+ for _ , obj := range objects {
188+ args := []string {"delete" , obj .resourceName , obj .name , "--ignore-not-found=true" , "--force" }
189+ if obj .namespace != "" {
190+ args = append (args , "--namespace" , obj .namespace )
191+ }
192+ output , err := exec .Command (c .client , args ... ).CombinedOutput ()
193+ require .NoError (t , err , "Error deleting %q %q in namespace %q: %v" , obj .resourceName , obj .name , obj .namespace , string (output ))
194+ }
168195
169196 // Create a context with a 60-second timeout.
170197 ctx , cancel := context .WithTimeout (context .Background (), 60 * time .Second )
171198 defer cancel ()
172199
173- // Wait for the ClusterRoleBinding to be deleted.
174- if err := waitForDeletion (ctx , c .client , "clusterrolebinding" , c .clusterBinding ); err != nil {
175- c .t .Logf ("Error waiting for clusterrolebinding deletion: %v" , err )
176- } else {
177- c .t .Log ("ClusterRoleBinding deleted" )
178- }
179-
180- // Wait for the Pod to be deleted.
181- if err := waitForDeletion (ctx , c .client , "pod" , c .curlPodName , "-n" , c .namespace ); err != nil {
182- c .t .Logf ("Error waiting for pod deletion: %v" , err )
183- } else {
184- c .t .Log ("Pod deleted" )
200+ for _ , obj := range objects {
201+ err := waitForDeletion (ctx , c .client , obj .resourceName , obj .name , obj .namespace )
202+ require .NoError (t , err , "Error deleting %q %q in namespace %q" , obj .resourceName , obj .name , obj .namespace )
203+ t .Logf ("Successfully deleted %q %q in namespace %q" , obj .resourceName , obj .name , obj .namespace )
185204 }
186205}
187206
188207// waitForDeletion uses "kubectl wait" to block until the specified resource is deleted
189208// or until the 60-second timeout is reached.
190- func waitForDeletion (ctx context.Context , client , resourceType , resourceName string , extraArgs ... string ) error {
191- args := []string {"wait" , "--for=delete" , resourceType , resourceName }
192- args = append (args , extraArgs ... )
193- args = append (args , "--timeout=60s" )
209+ func waitForDeletion (ctx context.Context , client , resourceType , resourceName , resourceNamespace string ) error {
210+ args := []string {"wait" , "--for=delete" , "--timeout=60s" , resourceType , resourceName }
211+ if resourceNamespace != "" {
212+ args = append (args , "--namespace" , resourceNamespace )
213+ }
194214 cmd := exec .CommandContext (ctx , client , args ... )
195215 output , err := cmd .CombinedOutput ()
196216 if err != nil {
@@ -199,6 +219,17 @@ func waitForDeletion(ctx context.Context, client, resourceType, resourceName str
199219 return nil
200220}
201221
222+ // createRandomNamespace creates a random namespace
223+ func createRandomNamespace (t * testing.T , client string ) string {
224+ nsName := fmt .Sprintf ("testns-%s" , rand .String (8 ))
225+
226+ cmd := exec .Command (client , "create" , "namespace" , nsName )
227+ output , err := cmd .CombinedOutput ()
228+ require .NoError (t , err , "Error creating namespace: %s" , string (output ))
229+
230+ return nsName
231+ }
232+
202233// getComponentNamespace returns the namespace where operator-controller or catalogd is running
203234func getComponentNamespace (t * testing.T , client , selector string ) string {
204235 cmd := exec .Command (client , "get" , "pods" , "--all-namespaces" , "--selector=" + selector , "--output=jsonpath={.items[0].metadata.namespace}" )
0 commit comments