@@ -3,6 +3,7 @@ package serviceaccounts
33import (
44 "context"
55 "fmt"
6+ "strings"
67 "time"
78
89 operatorv1 "github.com/openshift/api/operator/v1"
@@ -11,16 +12,16 @@ import (
1112 operatorinformerv1 "github.com/openshift/client-go/operator/informers/externalversions/operator/v1"
1213 operatorlistersv1 "github.com/openshift/client-go/operator/listers/operator/v1"
1314
15+ "github.com/openshift/console-operator/bindata"
1416 "github.com/openshift/console-operator/pkg/api"
1517 "github.com/openshift/console-operator/pkg/console/controllers/util"
1618 "github.com/openshift/console-operator/pkg/console/status"
17- serviceaccountssub "github.com/openshift/console-operator/pkg/console/subresource/serviceaccount"
1819 "github.com/openshift/library-go/pkg/controller/factory"
1920 "github.com/openshift/library-go/pkg/operator/events"
2021 "github.com/openshift/library-go/pkg/operator/resource/resourceapply"
22+ "github.com/openshift/library-go/pkg/operator/resource/resourceread"
2123 "github.com/openshift/library-go/pkg/operator/v1helpers"
2224
23- corev1 "k8s.io/api/core/v1"
2425 apierrors "k8s.io/apimachinery/pkg/api/errors"
2526 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2627 coreinformersv1 "k8s.io/client-go/informers/core/v1"
@@ -31,6 +32,7 @@ import (
3132
3233type ServiceAccountSyncController struct {
3334 serviceAccountName string
35+ conditionType string
3436 operatorClient v1helpers.OperatorClient
3537 // configs
3638 consoleOperatorLister operatorlistersv1.ConsoleLister
@@ -54,13 +56,12 @@ func NewServiceAccountSyncController(
5456 serviceAccountName string ,
5557 // controllerName,
5658 controllerName string ,
57- // controllerSuffix
58- controllerSuffix string ,
5959) factory.Controller {
6060 configV1Informers := configInformer .Config ().V1 ()
6161
6262 ctrl := & ServiceAccountSyncController {
6363 serviceAccountName : serviceAccountName ,
64+ conditionType : fmt .Sprintf ("%sServiceAccountSync" , controllerName ),
6465 // configs
6566 operatorClient : operatorClient ,
6667 consoleOperatorLister : operatorConfigInformer .Lister (),
@@ -81,32 +82,35 @@ func NewServiceAccountSyncController(
8182 serviceAccountNameFilter ,
8283 serviceAccountInformer .Informer (),
8384 ).ResyncEvery (time .Minute ).WithSync (ctrl .Sync ).
84- ToController (controllerName , recorder .WithComponentSuffix (controllerSuffix ))
85+ ToController (fmt . Sprintf ( "%sServiceAccountController" , strings . Title ( controllerName )) , recorder .WithComponentSuffix (fmt . Sprintf ( "%s-service-account-controller" , controllerName ) ))
8586}
8687
8788func (c * ServiceAccountSyncController ) Sync (ctx context.Context , controllerContext factory.SyncContext ) error {
8889 operatorConfig , err := c .consoleOperatorLister .Get (api .ConfigResourceName )
8990 if err != nil {
90- return err
91+ return fmt . Errorf ( "failed to get console operator config %s: %w" , api . ConfigResourceName , err )
9192 }
9293 operatorConfigCopy := operatorConfig .DeepCopy ()
9394
9495 switch operatorConfigCopy .Spec .ManagementState {
9596 case operatorv1 .Managed :
96- klog .V (4 ).Infoln ("console is in a managed state: syncing service account " )
97+ klog .V (4 ).Infoln ("console is in a managed state: syncing serviceaccount " )
9798 case operatorv1 .Unmanaged :
98- klog .V (4 ).Infoln ("console is in an unmanaged state: skipping service account sync" )
99+ klog .V (4 ).Infoln ("console is in an unmanaged state: skipping serviceaccount sync" )
99100 return nil
100101 case operatorv1 .Removed :
101- klog .V (4 ).Infoln ("console is in a removed state: removing synced service account" )
102- return c .removeServiceAccount (ctx )
102+ klog .V (4 ).Infoln ("console is in a removed state: removing synced serviceaccount" )
103+ statusHandler := status .NewStatusHandler (c .operatorClient )
104+ removeErr := c .removeServiceAccount (ctx )
105+ statusHandler .AddConditions (status .HandleProgressingOrDegraded (c .conditionType , "FailedRemove" , removeErr ))
106+ return statusHandler .FlushAndReturn (removeErr )
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,44 @@ 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 )
127- if err != nil {
128- return nil , false , err
129+ func (c * ServiceAccountSyncController ) SyncServiceAccount (ctx context.Context , operatorConfigCopy * operatorv1.Console , controllerContext factory.SyncContext ) error {
130+ serviceAccount := resourceread .ReadServiceAccountV1OrDie (
131+ bindata .MustAsset (fmt .Sprintf ("assets/serviceaccounts/%s-sa.yaml" , c .serviceAccountName )),
132+ )
133+ if serviceAccount .Name == "" {
134+ return fmt .Errorf ("No service account found for name %v ." , c .serviceAccountName )
129135 }
130136
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+ // Fetch the live SA to get its actual ownerRefs (e.g. ClusterVersion/version
138+ // set by CVO from the old manifests/06-sa.yaml, or any previously set
139+ // Console/cluster ref). We need these on the *required* object so that
140+ // MergeOwnerRefs will update them — it only modifies refs that appear in
141+ // required (matched by Name+Kind+APIVersion.Group).
142+ existing , err := c .serviceAccountClient .ServiceAccounts (api .OpenShiftConsoleNamespace ).Get (ctx , c .serviceAccountName , metav1.GetOptions {})
143+ if err != nil && ! apierrors .IsNotFound (err ) {
144+ return fmt .Errorf ("failed to get service account %s: %w" , c .serviceAccountName , err )
145+ }
146+ if err == nil {
147+ // Clear controller:true from all existing ownerRefs to satisfy the
148+ // Kubernetes invariant that only one ownerRef may have controller:true.
149+ // https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/
137150 falseBool := false
138- requiredServiceAccount .OwnerReferences [oR ].Controller = & falseBool
151+ ownerRefs := existing .DeepCopy ().GetOwnerReferences ()
152+ for i := range ownerRefs {
153+ ownerRefs [i ].Controller = & falseBool
154+ }
155+ serviceAccount .SetOwnerReferences (ownerRefs )
139156 }
140157
141- return resourceapply .ApplyServiceAccount (ctx ,
158+ _ , _ , err = resourceapply .ApplyServiceAccount (ctx ,
142159 c .serviceAccountClient ,
143160 controllerContext .Recorder (),
144- requiredServiceAccount ,
161+ serviceAccount ,
145162 )
163+
164+ if err != nil {
165+ return fmt .Errorf ("failed to apply service account %s: %w" , c .serviceAccountName , err )
166+ }
167+
168+ return nil
146169}
0 commit comments