@@ -10,8 +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
+ "k8s.io/apimachinery/pkg/util/sets"
13
14
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
14
15
apirequest "k8s.io/apiserver/pkg/endpoints/request"
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"
15
19
kapi "k8s.io/kubernetes/pkg/api"
16
20
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
17
21
"k8s.io/kubernetes/pkg/serviceaccount"
@@ -21,7 +25,6 @@ import (
21
25
oauthapi "github.com/openshift/origin/pkg/oauth/apis/oauth"
22
26
"github.com/openshift/origin/pkg/oauth/registry/oauthclient"
23
27
routeapi "github.com/openshift/origin/pkg/route/apis/route"
24
- "k8s.io/apimachinery/pkg/util/sets"
25
28
)
26
29
27
30
const (
@@ -58,9 +61,10 @@ var legacyRouteGroupKind = routeapi.LegacySchemeGroupVersion.WithKind(routeKind)
58
61
// var ingressGroupKind = routeapi.SchemeGroupVersion.WithKind(IngressKind).GroupKind()
59
62
60
63
type saOAuthClientAdapter struct {
61
- saClient kcoreclient.ServiceAccountsGetter
62
- secretClient kcoreclient.SecretsGetter
63
- routeClient osclient.RoutesNamespacer
64
+ saClient kcoreclient.ServiceAccountsGetter
65
+ secretClient kcoreclient.SecretsGetter
66
+ eventRecorder record.EventRecorder
67
+ routeClient osclient.RoutesNamespacer
64
68
// TODO add ingress support
65
69
//ingressClient ??
66
70
@@ -186,11 +190,14 @@ func (uri *redirectURI) merge(m *model) {
186
190
187
191
var _ oauthclient.Getter = & saOAuthClientAdapter {}
188
192
189
- func NewServiceAccountOAuthClientGetter (saClient kcoreclient.ServiceAccountsGetter , secretClient kcoreclient.SecretsGetter , routeClient osclient.RoutesNamespacer , delegate oauthclient.Getter , grantMethod oauthapi.GrantHandlerType ) oauthclient.Getter {
190
- return & saOAuthClientAdapter {saClient : saClient , secretClient : secretClient , routeClient : routeClient , delegate : delegate , grantMethod : grantMethod , decoder : kapi .Codecs .UniversalDecoder ()}
193
+ func NewServiceAccountOAuthClientGetter (saClient kcoreclient.ServiceAccountsGetter , secretClient kcoreclient.SecretsGetter , eventClient corev1.EventInterface , routeClient osclient.RoutesNamespacer , delegate oauthclient.Getter , grantMethod oauthapi.GrantHandlerType ) oauthclient.Getter {
194
+ eventBroadcaster := record .NewBroadcaster ()
195
+ eventBroadcaster .StartRecordingToSink (& corev1.EventSinkImpl {Interface : eventClient })
196
+ recorder := eventBroadcaster .NewRecorder (kapi .Scheme , clientv1.EventSource {Component : "service-account-oauth-client-getter" })
197
+ return & saOAuthClientAdapter {saClient : saClient , secretClient : secretClient , eventRecorder : recorder , routeClient : routeClient , delegate : delegate , grantMethod : grantMethod , decoder : kapi .Codecs .UniversalDecoder ()}
191
198
}
192
199
193
- func (a * saOAuthClientAdapter ) GetClient (ctx apirequest.Context , name string , options * metav1.GetOptions ) (* oauthapi.OAuthClient , error ) {
200
+ func (a * saOAuthClientAdapter ) GetClient (ctx apirequest.Context , name string , options * metav1.GetOptions ) (saClient * oauthapi.OAuthClient , err error ) {
194
201
saNamespace , saName , err := apiserverserviceaccount .SplitUsername (name )
195
202
if err != nil {
196
203
return a .delegate .GetClient (ctx , name , options )
@@ -201,30 +208,44 @@ func (a *saOAuthClientAdapter) GetClient(ctx apirequest.Context, name string, op
201
208
return nil , err
202
209
}
203
210
211
+ failEvents := []string {}
212
+ var failReason string
213
+ // Create a warning event upon failure
214
+ defer func () {
215
+ if err != nil && len (failEvents ) > 0 && len (failReason ) > 0 {
216
+ a .eventRecorder .Eventf (sa , kapi .EventTypeWarning , failReason , "%s" , strings .Join (failEvents , "," ))
217
+ }
218
+ }()
219
+
204
220
redirectURIs := []string {}
205
- if modelsMap := parseModelsMap (sa .Annotations , a .decoder ); len (modelsMap ) > 0 {
221
+ if modelsMap := parseModelsMap (sa .Annotations , a .decoder , & failEvents ); len (modelsMap ) > 0 {
206
222
if uris := a .extractRedirectURIs (modelsMap , saNamespace ); len (uris ) > 0 {
207
223
redirectURIs = append (redirectURIs , uris .extractValidRedirectURIStrings ()... )
208
224
}
209
225
}
210
226
if len (redirectURIs ) == 0 {
211
- return nil , fmt .Errorf (
212
- "%v has no redirectURIs; set %v<some-value>=<redirect> or create a dynamic URI using %v<some-value>=<reference>" ,
227
+ err = fmt .Errorf ("%v has no redirectURIs; set %v<some-value>=<redirect> or create a dynamic URI using %v<some-value>=<reference>" ,
213
228
name , OAuthRedirectModelAnnotationURIPrefix , OAuthRedirectModelAnnotationReferencePrefix ,
214
229
)
230
+ failReason = "NoSAOAuthRedirectURIs"
231
+ failEvents = append (failEvents , err .Error ())
232
+ return nil , err
215
233
}
216
234
217
235
tokens , err := a .getServiceAccountTokens (sa )
218
236
if err != nil {
219
237
return nil , err
220
238
}
221
239
if len (tokens ) == 0 {
222
- return nil , fmt .Errorf ("%v has no tokens" , name )
240
+ err = fmt .Errorf ("%v has no tokens" , name )
241
+ failReason = "NoSAOAuthTokens"
242
+ failEvents = append (failEvents , err .Error ())
243
+ return nil , err
223
244
}
224
245
225
246
saWantsChallenges , _ := strconv .ParseBool (sa .Annotations [OAuthWantChallengesAnnotationPrefix ])
226
247
227
- saClient : = & oauthapi.OAuthClient {
248
+ saClient = & oauthapi.OAuthClient {
228
249
ObjectMeta : metav1.ObjectMeta {Name : name },
229
250
ScopeRestrictions : getScopeRestrictionsFor (saNamespace , saName ),
230
251
AdditionalSecrets : tokens ,
@@ -243,7 +264,7 @@ func (a *saOAuthClientAdapter) GetClient(ctx apirequest.Context, name string, op
243
264
// parseModelsMap builds a map of model name to model using a service account's annotations.
244
265
// The model name is only used for building the map (it ties together the uri and reference annotations)
245
266
// and serves no functional purpose other than making testing easier.
246
- func parseModelsMap (annotations map [string ]string , decoder runtime.Decoder ) map [string ]model {
267
+ func parseModelsMap (annotations map [string ]string , decoder runtime.Decoder , fails * [] string ) map [string ]model {
247
268
models := map [string ]model {}
248
269
for key , value := range annotations {
249
270
prefix , name , ok := parseModelPrefixName (key )
@@ -255,11 +276,15 @@ func parseModelsMap(annotations map[string]string, decoder runtime.Decoder) map[
255
276
case OAuthRedirectModelAnnotationURIPrefix :
256
277
if u , err := url .Parse (value ); err == nil {
257
278
m .updateFromURI (u )
279
+ } else {
280
+ * fails = append (* fails , fmt .Sprintf ("failed to parse SA annotation %q: %s" , prefix , err .Error ()))
258
281
}
259
282
case OAuthRedirectModelAnnotationReferencePrefix :
260
283
r := & oauthapi.OAuthRedirectReference {}
261
284
if err := runtime .DecodeInto (decoder , []byte (value ), r ); err == nil {
262
285
m .updateFromReference (& r .Reference )
286
+ } else {
287
+ * fails = append (* fails , fmt .Sprintf ("failed to decode SA annotation %q: %s" , prefix , err .Error ()))
263
288
}
264
289
}
265
290
models [name ] = m
0 commit comments