@@ -10,8 +10,12 @@ import (
1010 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1111 "k8s.io/apimachinery/pkg/runtime"
1212 "k8s.io/apimachinery/pkg/runtime/schema"
13+ "k8s.io/apimachinery/pkg/util/sets"
1314 apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
1415 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"
1519 kapi "k8s.io/kubernetes/pkg/api"
1620 kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
1721 "k8s.io/kubernetes/pkg/serviceaccount"
@@ -21,7 +25,6 @@ import (
2125 oauthapi "github.com/openshift/origin/pkg/oauth/apis/oauth"
2226 "github.com/openshift/origin/pkg/oauth/registry/oauthclient"
2327 routeapi "github.com/openshift/origin/pkg/route/apis/route"
24- "k8s.io/apimachinery/pkg/util/sets"
2528)
2629
2730const (
@@ -58,9 +61,10 @@ var legacyRouteGroupKind = routeapi.LegacySchemeGroupVersion.WithKind(routeKind)
5861// var ingressGroupKind = routeapi.SchemeGroupVersion.WithKind(IngressKind).GroupKind()
5962
6063type 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
6468 // TODO add ingress support
6569 //ingressClient ??
6670
@@ -186,11 +190,14 @@ func (uri *redirectURI) merge(m *model) {
186190
187191var _ oauthclient.Getter = & saOAuthClientAdapter {}
188192
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 ()}
191198}
192199
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 ) {
194201 saNamespace , saName , err := apiserverserviceaccount .SplitUsername (name )
195202 if err != nil {
196203 return a .delegate .GetClient (ctx , name , options )
@@ -201,30 +208,44 @@ func (a *saOAuthClientAdapter) GetClient(ctx apirequest.Context, name string, op
201208 return nil , err
202209 }
203210
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+
204220 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 {
206222 if uris := a .extractRedirectURIs (modelsMap , saNamespace ); len (uris ) > 0 {
207223 redirectURIs = append (redirectURIs , uris .extractValidRedirectURIStrings ()... )
208224 }
209225 }
210226 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>" ,
213228 name , OAuthRedirectModelAnnotationURIPrefix , OAuthRedirectModelAnnotationReferencePrefix ,
214229 )
230+ failReason = "NoSAOAuthRedirectURIs"
231+ failEvents = append (failEvents , err .Error ())
232+ return nil , err
215233 }
216234
217235 tokens , err := a .getServiceAccountTokens (sa )
218236 if err != nil {
219237 return nil , err
220238 }
221239 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
223244 }
224245
225246 saWantsChallenges , _ := strconv .ParseBool (sa .Annotations [OAuthWantChallengesAnnotationPrefix ])
226247
227- saClient : = & oauthapi.OAuthClient {
248+ saClient = & oauthapi.OAuthClient {
228249 ObjectMeta : metav1.ObjectMeta {Name : name },
229250 ScopeRestrictions : getScopeRestrictionsFor (saNamespace , saName ),
230251 AdditionalSecrets : tokens ,
@@ -243,7 +264,7 @@ func (a *saOAuthClientAdapter) GetClient(ctx apirequest.Context, name string, op
243264// parseModelsMap builds a map of model name to model using a service account's annotations.
244265// The model name is only used for building the map (it ties together the uri and reference annotations)
245266// 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 {
247268 models := map [string ]model {}
248269 for key , value := range annotations {
249270 prefix , name , ok := parseModelPrefixName (key )
@@ -255,11 +276,15 @@ func parseModelsMap(annotations map[string]string, decoder runtime.Decoder) map[
255276 case OAuthRedirectModelAnnotationURIPrefix :
256277 if u , err := url .Parse (value ); err == nil {
257278 m .updateFromURI (u )
279+ } else {
280+ * fails = append (* fails , fmt .Sprintf ("failed to parse SA annotation %q: %s" , prefix , err .Error ()))
258281 }
259282 case OAuthRedirectModelAnnotationReferencePrefix :
260283 r := & oauthapi.OAuthRedirectReference {}
261284 if err := runtime .DecodeInto (decoder , []byte (value ), r ); err == nil {
262285 m .updateFromReference (& r .Reference )
286+ } else {
287+ * fails = append (* fails , fmt .Sprintf ("failed to decode SA annotation %q: %s" , prefix , err .Error ()))
263288 }
264289 }
265290 models [name ] = m
0 commit comments