@@ -3,6 +3,8 @@ package serviceaccounts
33import (
44 "context"
55 "fmt"
6+ "reflect"
7+ "strings"
68 "time"
79
810 operatorv1 "github.com/openshift/api/operator/v1"
@@ -11,13 +13,15 @@ import (
1113 operatorinformerv1 "github.com/openshift/client-go/operator/informers/externalversions/operator/v1"
1214 operatorlistersv1 "github.com/openshift/client-go/operator/listers/operator/v1"
1315
16+ "github.com/openshift/console-operator/bindata"
1417 "github.com/openshift/console-operator/pkg/api"
1518 "github.com/openshift/console-operator/pkg/console/controllers/util"
1619 "github.com/openshift/console-operator/pkg/console/status"
17- serviceaccountssub "github.com/openshift/console-operator/pkg/console/subresource/serviceaccount "
20+ subresourceutil "github.com/openshift/console-operator/pkg/console/subresource/util "
1821 "github.com/openshift/library-go/pkg/controller/factory"
1922 "github.com/openshift/library-go/pkg/operator/events"
2023 "github.com/openshift/library-go/pkg/operator/resource/resourceapply"
24+ "github.com/openshift/library-go/pkg/operator/resource/resourceread"
2125 "github.com/openshift/library-go/pkg/operator/v1helpers"
2226
2327 corev1 "k8s.io/api/core/v1"
@@ -31,6 +35,7 @@ import (
3135
3236type ServiceAccountSyncController struct {
3337 serviceAccountName string
38+ conditionType string
3439 operatorClient v1helpers.OperatorClient
3540 // configs
3641 consoleOperatorLister operatorlistersv1.ConsoleLister
@@ -54,13 +59,12 @@ func NewServiceAccountSyncController(
5459 serviceAccountName string ,
5560 // controllerName,
5661 controllerName string ,
57- // controllerSuffix
58- controllerSuffix string ,
5962) factory.Controller {
6063 configV1Informers := configInformer .Config ().V1 ()
6164
6265 ctrl := & ServiceAccountSyncController {
6366 serviceAccountName : serviceAccountName ,
67+ conditionType : fmt .Sprintf ("%sServiceAccountSync" , controllerName ),
6468 // configs
6569 operatorClient : operatorClient ,
6670 consoleOperatorLister : operatorConfigInformer .Lister (),
@@ -81,32 +85,32 @@ func NewServiceAccountSyncController(
8185 serviceAccountNameFilter ,
8286 serviceAccountInformer .Informer (),
8387 ).ResyncEvery (time .Minute ).WithSync (ctrl .Sync ).
84- ToController (controllerName , recorder .WithComponentSuffix (controllerSuffix ))
88+ ToController (fmt . Sprintf ( "%sServiceAccountController" , strings . Title ( controllerName )) , recorder .WithComponentSuffix (fmt . Sprintf ( "%s-service-account-controller" , controllerName ) ))
8589}
8690
8791func (c * ServiceAccountSyncController ) Sync (ctx context.Context , controllerContext factory.SyncContext ) error {
8892 operatorConfig , err := c .consoleOperatorLister .Get (api .ConfigResourceName )
8993 if err != nil {
90- return err
94+ return fmt . Errorf ( "failed to get console operator config %s: %w" , api . ConfigResourceName , err )
9195 }
9296 operatorConfigCopy := operatorConfig .DeepCopy ()
9397
9498 switch operatorConfigCopy .Spec .ManagementState {
9599 case operatorv1 .Managed :
96- klog .V (4 ).Infoln ("console is in a managed state: syncing service account " )
100+ klog .V (4 ).Infoln ("console is in a managed state: syncing serviceaccount " )
97101 case operatorv1 .Unmanaged :
98- klog .V (4 ).Infoln ("console is in an unmanaged state: skipping service account sync" )
102+ klog .V (4 ).Infoln ("console is in an unmanaged state: skipping serviceaccount sync" )
99103 return nil
100104 case operatorv1 .Removed :
101- klog .V (4 ).Infoln ("console is in a removed state: removing synced service account " )
105+ klog .V (4 ).Infoln ("console is in a removed state: removing synced serviceaccount " )
102106 return c .removeServiceAccount (ctx )
103107 default :
104108 return fmt .Errorf ("unknown state: %v" , operatorConfigCopy .Spec .ManagementState )
105109 }
106110 statusHandler := status .NewStatusHandler (c .operatorClient )
107111
108- _ , _ , serviceAccountErr := c .SyncServiceAccount (ctx , operatorConfigCopy , controllerContext )
109- statusHandler .AddConditions (status .HandleProgressingOrDegraded ("ServiceAccountSync" , "FailedApply" , serviceAccountErr ))
112+ serviceAccountErr := c .SyncServiceAccount (ctx , operatorConfigCopy , controllerContext )
113+ statusHandler .AddConditions (status .HandleProgressingOrDegraded (c . conditionType , "FailedApply" , serviceAccountErr ))
110114 if serviceAccountErr != nil {
111115 return statusHandler .FlushAndReturn (serviceAccountErr )
112116 }
@@ -122,25 +126,52 @@ func (c *ServiceAccountSyncController) removeServiceAccount(ctx context.Context)
122126 return err
123127}
124128
125- func (c * ServiceAccountSyncController ) SyncServiceAccount (ctx context.Context , operatorConfigCopy * operatorv1.Console , controllerContext factory.SyncContext ) (* corev1.ServiceAccount , bool , error ) {
126- requiredServiceAccount , err := serviceaccountssub .DefaultServiceAccountFactory (c .serviceAccountName , operatorConfigCopy )
129+ func (c * ServiceAccountSyncController ) SyncServiceAccount (ctx context.Context , operatorConfigCopy * operatorv1.Console , controllerContext factory.SyncContext ) error {
130+ serviceAccount , err := c .DefaultServiceAccount (operatorConfigCopy )
131+
127132 if err != nil {
128- return nil , false , err
133+ return err
129134 }
130135
131- // if the object has one or more ownerRef objects, then we must
132- // ensure that their controller attribute is set to false.
133- // Only one ownerRef.controller == true .
134- // https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/#owner-references-in-object-specifications
135-
136- for oR := range requiredServiceAccount .OwnerReferences {
137- falseBool := false
138- requiredServiceAccount .OwnerReferences [oR ].Controller = & falseBool
136+ // check for service account existence
137+
138+ existingServiceAccount , err := c .serviceAccountClient .ServiceAccounts (serviceAccount .Namespace ).Get (ctx , serviceAccount .Name , metav1.GetOptions {})
139+
140+ if err == nil {
141+ for _ , oR := range existingServiceAccount .OwnerReferences {
142+ // mark ownerref for deletion. we cannot have multiple owner refs
143+ // https://github.com/openshift/library-go/blob/master/pkg/operator/resource/resourcemerge/object_merger.go#L214-L219
144+ if reflect .DeepEqual (oR , * subresourceutil .OwnerRefFrom (operatorConfigCopy )) {
145+ continue // we want to keep this controller=true
146+ }
147+ removalRef := oR .DeepCopy ()
148+ removalRef .UID = removalRef .UID + "-"
149+ serviceAccount .OwnerReferences = append (serviceAccount .OwnerReferences , * removalRef )
150+ }
151+ } else if ! apierrors .IsNotFound (err ) {
152+ return fmt .Errorf ("failed to get existing service account %s: %w" , c .serviceAccountName , err )
139153 }
140154
141- return resourceapply .ApplyServiceAccount (ctx ,
155+ _ , _ , err = resourceapply .ApplyServiceAccount (ctx ,
142156 c .serviceAccountClient ,
143157 controllerContext .Recorder (),
144- requiredServiceAccount ,
158+ serviceAccount ,
159+ )
160+
161+ if err != nil {
162+ return fmt .Errorf ("failed to apply service account %s: %w" , c .serviceAccountName , err )
163+ }
164+
165+ return nil
166+ }
167+
168+ func (c * ServiceAccountSyncController ) DefaultServiceAccount (cr * operatorv1.Console ) (* corev1.ServiceAccount , error ) {
169+ serviceAccount := resourceread .ReadServiceAccountV1OrDie (
170+ bindata .MustAsset (fmt .Sprintf ("assets/serviceaccounts/%s-sa.yaml" , c .serviceAccountName )),
145171 )
172+ if serviceAccount .Name == "" {
173+ return nil , fmt .Errorf ("No service account found for name %v ." , c .serviceAccountName )
174+ }
175+ serviceAccount .SetOwnerReferences ([]metav1.OwnerReference {* subresourceutil .OwnerRefFrom (cr )})
176+ return serviceAccount , nil
146177}
0 commit comments