@@ -27,17 +27,19 @@ import (
2727 "testing"
2828 "time"
2929
30- "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
31- "k8s.io/kubernetes/test/integration/framework"
32- "k8s.io/kubernetes/test/utils/ktesting"
33-
3430 authv1 "k8s.io/api/authentication/v1"
3531 corev1 "k8s.io/api/core/v1"
3632 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33+ "k8s.io/apimachinery/pkg/util/wait"
3734 utilfeature "k8s.io/apiserver/pkg/util/feature"
35+ "k8s.io/client-go/kubernetes"
3836 featuregatetesting "k8s.io/component-base/featuregate/testing"
37+ "k8s.io/component-base/metrics/testutil"
38+ "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
3939 "k8s.io/kubernetes/pkg/features"
4040 v1alpha1testing "k8s.io/kubernetes/pkg/serviceaccount/externaljwt/plugin/testing/v1alpha1"
41+ "k8s.io/kubernetes/test/integration/framework"
42+ "k8s.io/kubernetes/test/utils/ktesting"
4143)
4244
4345func TestExternalJWTSigningAndAuth (t * testing.T ) {
@@ -94,29 +96,29 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
9496
9597 testCases := []struct {
9698 desc string
97- preTestSignerUpdate func ()
98- preValidationSignerUpdate func ()
99+ preTestSignerUpdate func (t * testing. T )
100+ preValidationSignerUpdate func (t * testing. T )
99101 wantTokenReqErr error
100102 shouldPassAuth bool
101103 }{
102104 {
103105 desc : "signing key supported." ,
104- preTestSignerUpdate : func () { /*no-op*/ },
105- preValidationSignerUpdate : func () { /*no-op*/ },
106+ preTestSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
107+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
106108 shouldPassAuth : true ,
107109 },
108110 {
109111 desc : "signing key not among supported set" ,
110- preTestSignerUpdate : func () {
112+ preTestSignerUpdate : func (t * testing. T ) {
111113 mockSigner .SigningKey = key1
112114 mockSigner .SigningKeyID = "updated-kid-1"
113115 },
114- preValidationSignerUpdate : func () { /*no-op*/ },
116+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
115117 shouldPassAuth : false ,
116118 },
117119 {
118120 desc : "signing key corresponds to public key that is excluded from OIDC" ,
119- preTestSignerUpdate : func () {
121+ preTestSignerUpdate : func (t * testing. T ) {
120122 mockSigner .SigningKey = key1
121123 mockSigner .SigningKeyID = "updated-kid-1"
122124
@@ -130,56 +132,57 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
130132 }
131133 mockSigner .SetSupportedKeys (cpy )
132134 },
133- preValidationSignerUpdate : func () { /*no-op*/ },
135+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
134136 wantTokenReqErr : fmt .Errorf ("failed to generate token: while validating header: key used for signing JWT (kid: updated-kid-1) is excluded from OIDC discovery docs" ),
135137 },
136138 {
137139 desc : "different signing and supported keys with same id" ,
138- preTestSignerUpdate : func () {
140+ preTestSignerUpdate : func (t * testing. T ) {
139141 mockSigner .SigningKey = key1
140142 },
141- preValidationSignerUpdate : func () { /*no-op*/ },
143+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
142144 shouldPassAuth : false ,
143145 },
144146 {
145147 desc : "token gen failure with un-supported Alg type" ,
146- preTestSignerUpdate : func () {
148+ preTestSignerUpdate : func (t * testing. T ) {
147149 mockSigner .SigningAlg = "ABC"
148150 },
149- preValidationSignerUpdate : func () { /*no-op*/ },
151+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
150152 wantTokenReqErr : fmt .Errorf ("failed to generate token: while validating header: bad signing algorithm \" ABC\" " ),
151153 },
152154 {
153155 desc : "token gen failure with un-supported token type" ,
154- preTestSignerUpdate : func () {
156+ preTestSignerUpdate : func (t * testing. T ) {
155157 mockSigner .TokenType = "ABC"
156158 },
157- preValidationSignerUpdate : func () { /*no-op*/ },
159+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
158160 wantTokenReqErr : fmt .Errorf ("failed to generate token: while validating header: bad type" ),
159161 },
160162 {
161163 desc : "change of supported keys not picked immediately" ,
162- preTestSignerUpdate : func () {
164+ preTestSignerUpdate : func (t * testing. T ) {
163165 mockSigner .SigningKey = key1
164166 },
165- preValidationSignerUpdate : func () {
167+ preValidationSignerUpdate : func (_ * testing. T ) {
166168 mockSigner .SetSupportedKeys (map [string ]v1alpha1testing.KeyT {})
167169 },
168170 shouldPassAuth : false ,
169171 },
170172 {
171173 desc : "change of supported keys picked up after periodic sync" ,
172- preTestSignerUpdate : func () {
174+ preTestSignerUpdate : func (t * testing. T ) {
173175 mockSigner .SigningKey = key1
174176 },
175- preValidationSignerUpdate : func () {
177+ preValidationSignerUpdate : func (t * testing.T ) {
178+ t .Helper ()
176179 cpy := make (map [string ]v1alpha1testing.KeyT )
177180 for key , value := range mockSigner .GetSupportedKeys () {
178181 cpy [key ] = value
179182 }
180183 cpy ["kid-1" ] = v1alpha1testing.KeyT {Key : pubKey1Bytes }
181184 mockSigner .SetSupportedKeys (cpy )
182- mockSigner . WaitForSupportedKeysFetch ( )
185+ waitForDataTimestamp ( t , client , time . Now () )
183186 },
184187 shouldPassAuth : true ,
185188 },
@@ -195,7 +198,7 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
195198 mockSigner .WaitForSupportedKeysFetch ()
196199
197200 // Adjust parameters on mock signer for the test.
198- tc .preTestSignerUpdate ()
201+ tc .preTestSignerUpdate (t )
199202
200203 // Request a token for ns-1:sa-1.
201204 tokenExpirationSec := int64 (2 * 60 * 60 ) // 2h
@@ -214,7 +217,7 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
214217 }
215218
216219 // Adjust parameters on mock signer for the test.
217- tc .preValidationSignerUpdate ()
220+ tc .preValidationSignerUpdate (t )
218221
219222 // Try Validating the token.
220223 tokenReviewResult , err := client .AuthenticationV1 ().TokenReviews ().Create (ctx , & authv1.TokenReview {
@@ -235,6 +238,36 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
235238 }
236239}
237240
241+ func waitForDataTimestamp (t * testing.T , client kubernetes.Interface , minimumDataTimestamp time.Time ) {
242+ t .Helper ()
243+ minimumSample := float64 (minimumDataTimestamp .UnixNano ()) / float64 (1000000000 )
244+ t .Logf ("waiting for >=%f" , minimumSample )
245+ err := wait .PollImmediate (time .Second , wait .ForeverTestTimeout , func () (bool , error ) {
246+ rawMetrics , err := client .CoreV1 ().RESTClient ().Get ().AbsPath ("/metrics" ).DoRaw (context .TODO ())
247+ if err != nil {
248+ return false , err
249+ }
250+ metrics := testutil .NewMetrics ()
251+ if err := testutil .ParseMetrics (string (rawMetrics ), & metrics ); err != nil {
252+ return false , err
253+ }
254+ samples , ok := metrics ["apiserver_externaljwt_fetch_keys_data_timestamp" ]
255+ if ! ok || len (samples ) == 0 {
256+ t .Log ("no samples found for apiserver_externaljwt_fetch_keys_data_timestamp, retrying..." )
257+ return false , nil
258+ }
259+ if minimumSample > float64 (samples [0 ].Value ) {
260+ t .Logf ("apiserver_externaljwt_fetch_keys_data_timestamp at %f, waiting until >=%f..." , samples [0 ].Value , minimumSample )
261+ return false , nil
262+ }
263+ t .Logf ("saw %f" , samples [0 ].Value )
264+ return true , nil
265+ })
266+ if err != nil {
267+ t .Fatal (err )
268+ }
269+ }
270+
238271func TestDelayedStartForSigner (t * testing.T ) {
239272 // Enable feature gate for external JWT signer.
240273 featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .ExternalServiceAccountTokenSigner , true )
0 commit comments