@@ -17,7 +17,7 @@ limitations under the License.
17
17
package v3
18
18
19
19
import (
20
- "encoding/base64 "
20
+ "encoding/json "
21
21
"fmt"
22
22
"os"
23
23
"path/filepath"
@@ -38,11 +38,22 @@ import (
38
38
"sigs.k8s.io/kubebuilder/v3/test/e2e/utils"
39
39
)
40
40
41
+ const (
42
+ tokenRequestRawString = `{"apiVersion": "authentication.k8s.io/v1", "kind": "TokenRequest"}`
43
+ )
44
+
45
+ // tokenRequest is a trimmed down version of the authentication.k8s.io/v1/TokenRequest Type
46
+ // that we want to use for extracting the token.
47
+ type tokenRequest struct {
48
+ Status struct {
49
+ Token string `json:"token"`
50
+ } `json:"status"`
51
+ }
52
+
41
53
var _ = Describe ("kubebuilder" , func () {
42
54
Context ("project version 3" , func () {
43
55
var (
44
56
kbc * utils.TestContext
45
- sat bool
46
57
)
47
58
48
59
BeforeEach (func () {
@@ -53,8 +64,6 @@ var _ = Describe("kubebuilder", func() {
53
64
54
65
By ("installing the Prometheus operator" )
55
66
Expect (kbc .InstallPrometheusOperManager ()).To (Succeed ())
56
-
57
- sat = false
58
67
})
59
68
60
69
AfterEach (func () {
@@ -94,7 +103,7 @@ var _ = Describe("kubebuilder", func() {
94
103
kbc .Kubectl .ServiceAccount = "default"
95
104
defer func () { kbc .Kubectl .ServiceAccount = tmp }()
96
105
GenerateV2 (kbc )
97
- Run (kbc , sat )
106
+ Run (kbc )
98
107
})
99
108
})
100
109
@@ -119,15 +128,7 @@ var _ = Describe("kubebuilder", func() {
119
128
}
120
129
121
130
GenerateV3 (kbc , "v1" )
122
-
123
- // only if running on Kubernetes >= 1.24 do we need to generate the ServiceAccount token Secret
124
- // TODO: Remove this once a better implementation using something like the TokenRequest API
125
- // is used in the e2e tests
126
- if srvVer := kbc .K8sVersion .ServerVersion ; srvVer .GetMajorInt () == 1 && srvVer .GetMinorInt () >= 24 {
127
- sat = true
128
- }
129
-
130
- Run (kbc , sat )
131
+ Run (kbc )
131
132
})
132
133
It ("should generate a runnable project with the golang base plugin v3 and kustomize v4-alpha" , func () {
133
134
// Skip if cluster version < 1.16, when v1 CRDs and webhooks did not exist.
@@ -139,15 +140,7 @@ var _ = Describe("kubebuilder", func() {
139
140
}
140
141
141
142
GenerateV3WithKustomizeV2 (kbc , "v1" )
142
-
143
- // only if running on Kubernetes >= 1.24 do we need to generate the ServiceAccount token Secret
144
- // TODO: Remove this once a better implementation using something like the TokenRequest API
145
- // is used in the e2e tests
146
- if srvVer := kbc .K8sVersion .ServerVersion ; srvVer .GetMajorInt () == 1 && srvVer .GetMinorInt () >= 24 {
147
- sat = true
148
- }
149
-
150
- Run (kbc , sat )
143
+ Run (kbc )
151
144
})
152
145
It ("should generate a runnable project with v1beta1 CRDs and Webhooks" , func () {
153
146
// Skip if cluster version < 1.15, when `.spec.preserveUnknownFields` was not a v1beta1 CRD field.
@@ -161,14 +154,14 @@ var _ = Describe("kubebuilder", func() {
161
154
}
162
155
163
156
GenerateV3 (kbc , "v1beta1" )
164
- Run (kbc , sat )
157
+ Run (kbc )
165
158
})
166
159
})
167
160
})
168
161
})
169
162
170
163
// Run runs a set of e2e tests for a scaffolded project defined by a TestContext.
171
- func Run (kbc * utils.TestContext , sat bool ) {
164
+ func Run (kbc * utils.TestContext ) {
172
165
var controllerPodName string
173
166
var err error
174
167
@@ -233,10 +226,6 @@ func Run(kbc *utils.TestContext, sat bool) {
233
226
fmt .Sprintf ("--serviceaccount=%s:%s" , kbc .Kubectl .Namespace , kbc .Kubectl .ServiceAccount ))
234
227
ExpectWithOffset (1 , err ).NotTo (HaveOccurred ())
235
228
236
- if sat {
237
- ServiceAccountToken (kbc )
238
- }
239
-
240
229
_ = curlMetrics (kbc )
241
230
242
231
By ("validating that cert-manager has provisioned the certificate Secret" )
@@ -347,21 +336,14 @@ func Run(kbc *utils.TestContext, sat bool) {
347
336
func curlMetrics (kbc * utils.TestContext ) string {
348
337
By ("reading the metrics token" )
349
338
// Filter token query by service account in case more than one exists in a namespace.
350
- // TODO: Parsing a token this way is not ideal or best practice and should not be used.
351
- // Instead, a TokenRequest should be created to get a token to use for this step.
352
- query := fmt .Sprintf (`{.items[?(@.metadata.annotations.kubernetes\.io/service-account\.name=="%s")].data.token}` ,
353
- kbc .Kubectl .ServiceAccount ,
354
- )
355
- b64Token , err := kbc .Kubectl .Get (true , "secrets" , "-o=jsonpath=" + query )
356
- ExpectWithOffset (2 , err ).NotTo (HaveOccurred ())
357
- token , err := base64 .StdEncoding .DecodeString (strings .TrimSpace (b64Token ))
339
+ token , err := ServiceAccountToken (kbc )
358
340
ExpectWithOffset (2 , err ).NotTo (HaveOccurred ())
359
341
ExpectWithOffset (2 , len (token )).To (BeNumerically (">" , 0 ))
360
342
361
343
By ("creating a curl pod" )
362
344
cmdOpts := []string {
363
345
"run" , "curl" , "--image=curlimages/curl:7.68.0" , "--restart=OnFailure" , "--" ,
364
- "curl" , "-v" , "-k" , "-H" , fmt .Sprintf (`Authorization: Bearer %s` , token ),
346
+ "curl" , "-v" , "-k" , "-H" , fmt .Sprintf (`Authorization: Bearer %s` , strings . TrimSpace ( token ) ),
365
347
fmt .Sprintf ("https://e2e-%s-controller-manager-metrics-service.%s.svc:8443/metrics" ,
366
348
kbc .TestSuffix , kbc .Kubectl .Namespace ),
367
349
}
@@ -398,43 +380,42 @@ func curlMetrics(kbc *utils.TestContext) string {
398
380
return metricsOutput
399
381
}
400
382
401
- // TODO: Remove this when and other related functions when
402
- // tests have been changed to use a better implementation.
403
- // ServiceAccountToken creates the ServiceAccount token Secret.
404
- // This is to be used when Kubernetes cluster version is >= 1.24.
405
- // In k8s 1.24+ a ServiceAccount token Secret is no longer
406
- // automatically generated
407
- func ServiceAccountToken (kbc * utils.TestContext ) {
408
- // As of Kubernetes 1.24 a ServiceAccount no longer has a ServiceAccount token
409
- // secret autogenerated. We have to create it manually here
383
+ // ServiceAccountToken provides a helper function that can provide you with a service account
384
+ // token that you can use to interact with the service. This function leverages the k8s'
385
+ // TokenRequest API in raw format in order to make it generic for all version of the k8s that
386
+ // is currently being supported in kubebuilder test infra.
387
+ // TokenRequest API returns the token in raw JWT format itself. There is no conversion required.
388
+ func ServiceAccountToken (kbc * utils.TestContext ) (out string , err error ) {
410
389
By ("Creating the ServiceAccount token" )
411
- secretFile , err := createServiceAccountToken (kbc .Kubectl .ServiceAccount , kbc .Dir )
412
- Expect (err ).NotTo (HaveOccurred ())
413
- Eventually (func () error {
414
- _ , err = kbc .Kubectl .Apply (true , "-f" , secretFile )
415
- return err
416
- }, time .Minute , time .Second ).Should (Succeed ())
417
- }
418
-
419
- var saSecretTemplate = `---
420
- apiVersion: v1
421
- kind: Secret
422
- type: kubernetes.io/service-account-token
423
- metadata:
424
- name: %s
425
- annotations:
426
- kubernetes.io/service-account.name: "%s"
427
- `
428
-
429
- // createServiceAccountToken writes a service account token secret to a file.
430
- // It returns a string to the file or an error if it fails to write the file
431
- func createServiceAccountToken (name string , dir string ) (string , error ) {
432
- secretName := name + "-secret"
433
- fileName := dir + "/" + secretName + ".yaml"
434
- err := os .WriteFile (fileName , []byte (fmt .Sprintf (saSecretTemplate , secretName , name )), 0777 )
390
+ secretName := fmt .Sprintf ("%s-token-request" , kbc .Kubectl .ServiceAccount )
391
+ tokenRequestFile := filepath .Join (kbc .Dir , secretName )
392
+ err = os .WriteFile (tokenRequestFile , []byte (tokenRequestRawString ), os .FileMode (0755 ))
435
393
if err != nil {
436
- return "" , err
394
+ return out , err
437
395
}
396
+ var rawJson string
397
+ Eventually (func () error {
398
+ // Output of this is already a valid JWT token. No need to covert this from base64 to string format
399
+ rawJson , err = kbc .Kubectl .Command (
400
+ "create" ,
401
+ "--raw" , fmt .Sprintf (
402
+ "/api/v1/namespaces/%s/serviceaccounts/%s/token" ,
403
+ kbc .Kubectl .Namespace ,
404
+ kbc .Kubectl .ServiceAccount ,
405
+ ),
406
+ "-f" , tokenRequestFile ,
407
+ )
408
+ if err != nil {
409
+ return err
410
+ }
411
+ var token tokenRequest
412
+ err = json .Unmarshal ([]byte (rawJson ), & token )
413
+ if err != nil {
414
+ return err
415
+ }
416
+ out = token .Status .Token
417
+ return nil
418
+ }, time .Minute , time .Second ).Should (Succeed ())
438
419
439
- return fileName , nil
420
+ return out , err
440
421
}
0 commit comments