@@ -10,7 +10,12 @@ import (
10
10
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11
11
"k8s.io/apimachinery/pkg/runtime"
12
12
"k8s.io/apimachinery/pkg/runtime/schema"
13
+ utilerrors "k8s.io/apimachinery/pkg/util/errors"
14
+ "k8s.io/apimachinery/pkg/util/sets"
13
15
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
16
+ corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
17
+ clientv1 "k8s.io/client-go/pkg/api/v1"
18
+ "k8s.io/client-go/tools/record"
14
19
kapi "k8s.io/kubernetes/pkg/api"
15
20
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
16
21
"k8s.io/kubernetes/pkg/serviceaccount"
@@ -20,7 +25,6 @@ import (
20
25
"github.com/openshift/origin/pkg/oauth/registry/oauthclient"
21
26
routeapi "github.com/openshift/origin/pkg/route/apis/route"
22
27
routeclient "github.com/openshift/origin/pkg/route/generated/internalclientset/typed/route/internalversion"
23
- "k8s.io/apimachinery/pkg/util/sets"
24
28
)
25
29
26
30
const (
@@ -46,8 +50,8 @@ var modelPrefixes = []string{
46
50
// namesToObjMapperFunc is linked to a given GroupKind.
47
51
// Based on the namespace and names provided, it builds a map of resource name to redirect URIs.
48
52
// The redirect URIs represent the default values as specified by the resource.
49
- // These values can be overridden by user specified data.
50
- type namesToObjMapperFunc func (namespace string , names sets.String ) map [string ]redirectURIList
53
+ // These values can be overridden by user specified data. Errors returned are informative and non-fatal.
54
+ type namesToObjMapperFunc func (namespace string , names sets.String ) ( map [string ]redirectURIList , [] error )
51
55
52
56
var emptyGroupKind = schema.GroupKind {} // Used with static redirect URIs
53
57
var routeGroupKind = routeapi .SchemeGroupVersion .WithKind (routeKind ).GroupKind ()
@@ -57,9 +61,10 @@ var legacyRouteGroupKind = routeapi.LegacySchemeGroupVersion.WithKind(routeKind)
57
61
// var ingressGroupKind = routeapi.SchemeGroupVersion.WithKind(IngressKind).GroupKind()
58
62
59
63
type saOAuthClientAdapter struct {
60
- saClient kcoreclient.ServiceAccountsGetter
61
- secretClient kcoreclient.SecretsGetter
62
- routeClient routeclient.RoutesGetter
64
+ saClient kcoreclient.ServiceAccountsGetter
65
+ secretClient kcoreclient.SecretsGetter
66
+ eventRecorder record.EventRecorder
67
+ routeClient routeclient.RoutesGetter
63
68
// TODO add ingress support
64
69
//ingressClient ??
65
70
@@ -188,22 +193,27 @@ var _ oauthclient.Getter = &saOAuthClientAdapter{}
188
193
func NewServiceAccountOAuthClientGetter (
189
194
saClient kcoreclient.ServiceAccountsGetter ,
190
195
secretClient kcoreclient.SecretsGetter ,
196
+ eventClient corev1.EventInterface ,
191
197
routeClient routeclient.RoutesGetter ,
192
198
delegate oauthclient.Getter ,
193
199
grantMethod oauthapi.GrantHandlerType ,
194
200
) oauthclient.Getter {
195
-
201
+ eventBroadcaster := record .NewBroadcaster ()
202
+ eventBroadcaster .StartRecordingToSink (& corev1.EventSinkImpl {Interface : eventClient })
203
+ recorder := eventBroadcaster .NewRecorder (kapi .Scheme , clientv1.EventSource {Component : "service-account-oauth-client-getter" })
196
204
return & saOAuthClientAdapter {
197
- saClient : saClient ,
198
- secretClient : secretClient ,
199
- routeClient : routeClient ,
200
- delegate : delegate ,
201
- grantMethod : grantMethod ,
202
- decoder : kapi .Codecs .UniversalDecoder (),
205
+ saClient : saClient ,
206
+ secretClient : secretClient ,
207
+ eventRecorder : recorder ,
208
+ routeClient : routeClient ,
209
+ delegate : delegate ,
210
+ grantMethod : grantMethod ,
211
+ decoder : kapi .Codecs .UniversalDecoder (),
203
212
}
204
213
}
205
214
206
215
func (a * saOAuthClientAdapter ) Get (name string , options metav1.GetOptions ) (* oauthapi.OAuthClient , error ) {
216
+ var err error
207
217
saNamespace , saName , err := apiserverserviceaccount .SplitUsername (name )
208
218
if err != nil {
209
219
return a .delegate .Get (name , options )
@@ -214,25 +224,48 @@ func (a *saOAuthClientAdapter) Get(name string, options metav1.GetOptions) (*oau
214
224
return nil , err
215
225
}
216
226
227
+ var saErrors []error
228
+ var failReason string
229
+ // Create a warning event combining the collected annotation errors upon failure.
230
+ defer func () {
231
+ if err != nil && len (saErrors ) > 0 && len (failReason ) > 0 {
232
+ a .eventRecorder .Event (sa , kapi .EventTypeWarning , failReason , utilerrors .NewAggregate (saErrors ).Error ())
233
+ }
234
+ }()
235
+
217
236
redirectURIs := []string {}
218
- if modelsMap := parseModelsMap (sa .Annotations , a .decoder ); len (modelsMap ) > 0 {
219
- if uris := a .extractRedirectURIs (modelsMap , saNamespace ); len (uris ) > 0 {
237
+ modelsMap , errs := parseModelsMap (sa .Annotations , a .decoder )
238
+ if len (errs ) > 0 {
239
+ saErrors = append (saErrors , errs ... )
240
+ }
241
+
242
+ if len (modelsMap ) > 0 {
243
+ uris , extractErrors := a .extractRedirectURIs (modelsMap , saNamespace )
244
+ if len (uris ) > 0 {
220
245
redirectURIs = append (redirectURIs , uris .extractValidRedirectURIStrings ()... )
221
246
}
247
+ if len (extractErrors ) > 0 {
248
+ saErrors = append (saErrors , extractErrors ... )
249
+ }
222
250
}
223
251
if len (redirectURIs ) == 0 {
224
- return nil , fmt .Errorf (
225
- "%v has no redirectURIs; set %v<some-value>=<redirect> or create a dynamic URI using %v<some-value>=<reference>" ,
252
+ err = fmt .Errorf ("%v has no redirectURIs; set %v<some-value>=<redirect> or create a dynamic URI using %v<some-value>=<reference>" ,
226
253
name , OAuthRedirectModelAnnotationURIPrefix , OAuthRedirectModelAnnotationReferencePrefix ,
227
254
)
255
+ failReason = "NoSAOAuthRedirectURIs"
256
+ saErrors = append (saErrors , err )
257
+ return nil , err
228
258
}
229
259
230
260
tokens , err := a .getServiceAccountTokens (sa )
231
261
if err != nil {
232
262
return nil , err
233
263
}
234
264
if len (tokens ) == 0 {
235
- return nil , fmt .Errorf ("%v has no tokens" , name )
265
+ err = fmt .Errorf ("%v has no tokens" , name )
266
+ failReason = "NoSAOAuthTokens"
267
+ saErrors = append (saErrors , err )
268
+ return nil , err
236
269
}
237
270
238
271
saWantsChallenges , _ := strconv .ParseBool (sa .Annotations [OAuthWantChallengesAnnotationPrefix ])
@@ -255,9 +288,10 @@ func (a *saOAuthClientAdapter) Get(name string, options metav1.GetOptions) (*oau
255
288
256
289
// parseModelsMap builds a map of model name to model using a service account's annotations.
257
290
// The model name is only used for building the map (it ties together the uri and reference annotations)
258
- // and serves no functional purpose other than making testing easier.
259
- func parseModelsMap (annotations map [string ]string , decoder runtime.Decoder ) map [string ]model {
291
+ // and serves no functional purpose other than making testing easier. Errors returned are informative and non-fatal.
292
+ func parseModelsMap (annotations map [string ]string , decoder runtime.Decoder ) ( map [string ]model , [] error ) {
260
293
models := map [string ]model {}
294
+ parseErrors := []error {}
261
295
for key , value := range annotations {
262
296
prefix , name , ok := parseModelPrefixName (key )
263
297
if ! ok {
@@ -268,16 +302,20 @@ func parseModelsMap(annotations map[string]string, decoder runtime.Decoder) map[
268
302
case OAuthRedirectModelAnnotationURIPrefix :
269
303
if u , err := url .Parse (value ); err == nil {
270
304
m .updateFromURI (u )
305
+ } else {
306
+ parseErrors = append (parseErrors , err )
271
307
}
272
308
case OAuthRedirectModelAnnotationReferencePrefix :
273
309
r := & oauthapi.OAuthRedirectReference {}
274
310
if err := runtime .DecodeInto (decoder , []byte (value ), r ); err == nil {
275
311
m .updateFromReference (& r .Reference )
312
+ } else {
313
+ parseErrors = append (parseErrors , err )
276
314
}
277
315
}
278
316
models [name ] = m
279
317
}
280
- return models
318
+ return models , parseErrors
281
319
}
282
320
283
321
// parseModelPrefixName determines if the given key is a model prefix.
@@ -292,9 +330,10 @@ func parseModelPrefixName(key string) (string, string, bool) {
292
330
}
293
331
294
332
// extractRedirectURIs builds redirect URIs using the given models and namespace.
295
- // The returned redirect URIs may contain duplicates and invalid entries.
296
- func (a * saOAuthClientAdapter ) extractRedirectURIs (modelsMap map [string ]model , namespace string ) redirectURIList {
333
+ // The returned redirect URIs may contain duplicates and invalid entries. Errors returned are informative and non-fatal.
334
+ func (a * saOAuthClientAdapter ) extractRedirectURIs (modelsMap map [string ]model , namespace string ) ( redirectURIList , [] error ) {
297
335
var data redirectURIList
336
+ routeErrors := []error {}
298
337
groupKindModelListMapper := map [schema.GroupKind ]modelList {} // map of GroupKind to all models belonging to it
299
338
groupKindModelToURI := map [schema.GroupKind ]namesToObjMapperFunc {
300
339
routeGroupKind : a .redirectURIsFromRoutes ,
@@ -318,27 +357,37 @@ func (a *saOAuthClientAdapter) extractRedirectURIs(modelsMap map[string]model, n
318
357
319
358
for gk , models := range groupKindModelListMapper {
320
359
if names := models .getNames (); names .Len () > 0 {
321
- if objMapper := groupKindModelToURI [gk ](namespace , names ); len (objMapper ) > 0 {
360
+ objMapper , errs := groupKindModelToURI [gk ](namespace , names )
361
+ if len (objMapper ) > 0 {
322
362
data = append (data , models .getRedirectURIs (objMapper )... )
323
363
}
364
+ if len (errs ) > 0 {
365
+ routeErrors = append (routeErrors , errs ... )
366
+ }
324
367
}
325
368
}
326
369
327
- return data
370
+ return data , routeErrors
328
371
}
329
372
330
373
// redirectURIsFromRoutes is the namesToObjMapperFunc specific to Routes.
331
374
// Returns a map of route name to redirect URIs that contain the default data as specified by the route's ingresses.
332
- func (a * saOAuthClientAdapter ) redirectURIsFromRoutes (namespace string , osRouteNames sets.String ) map [string ]redirectURIList {
375
+ // Errors returned are informative and non-fatal.
376
+ func (a * saOAuthClientAdapter ) redirectURIsFromRoutes (namespace string , osRouteNames sets.String ) (map [string ]redirectURIList , []error ) {
333
377
var routes []routeapi.Route
378
+ routeErrors := []error {}
334
379
routeInterface := a .routeClient .Routes (namespace )
335
380
if osRouteNames .Len () > 1 {
336
381
if r , err := routeInterface .List (metav1.ListOptions {}); err == nil {
337
382
routes = r .Items
383
+ } else {
384
+ routeErrors = append (routeErrors , err )
338
385
}
339
386
} else {
340
387
if r , err := routeInterface .Get (osRouteNames .List ()[0 ], metav1.GetOptions {}); err == nil {
341
388
routes = append (routes , * r )
389
+ } else {
390
+ routeErrors = append (routeErrors , err )
342
391
}
343
392
}
344
393
routeMap := map [string ]redirectURIList {}
@@ -347,7 +396,7 @@ func (a *saOAuthClientAdapter) redirectURIsFromRoutes(namespace string, osRouteN
347
396
routeMap [route .Name ] = redirectURIsFromRoute (& route )
348
397
}
349
398
}
350
- return routeMap
399
+ return routeMap , routeErrors
351
400
}
352
401
353
402
// redirectURIsFromRoute returns a list of redirect URIs that contain the default data as specified by the given route's ingresses.
0 commit comments