@@ -2,165 +2,31 @@ package csidriveroperator
22
33import (
44 "bytes"
5- "context"
65 "fmt"
76 "strconv"
87 "strings"
98 "time"
109
1110 appsv1 "k8s.io/api/apps/v1"
12- "k8s.io/client-go/kubernetes"
13- "k8s.io/klog/v2"
1411
1512 configv1 "github.com/openshift/api/config/v1"
1613 operatorv1 "github.com/openshift/api/operator/v1"
1714 configv1listers "github.com/openshift/client-go/config/listers/config/v1"
15+ "github.com/openshift/cluster-storage-operator/assets"
16+ "github.com/openshift/cluster-storage-operator/pkg/csoclients"
17+ "github.com/openshift/cluster-storage-operator/pkg/operator/configobservation/util"
18+ "github.com/openshift/cluster-storage-operator/pkg/operator/csidriveroperator/csioperatorclient"
1819 "github.com/openshift/library-go/pkg/controller/factory"
1920 "github.com/openshift/library-go/pkg/operator/deploymentcontroller"
2021 "github.com/openshift/library-go/pkg/operator/events"
2122 "github.com/openshift/library-go/pkg/operator/loglevel"
22- "github.com/openshift/library-go/pkg/operator/resource/resourceapply"
23- "github.com/openshift/library-go/pkg/operator/resource/resourcemerge"
2423 "github.com/openshift/library-go/pkg/operator/status"
25- "github.com/openshift/library-go/pkg/operator/v1helpers"
26-
27- "github.com/openshift/cluster-storage-operator/pkg/csoclients"
28- "github.com/openshift/cluster-storage-operator/pkg/operator/configobservation/util"
29- "github.com/openshift/cluster-storage-operator/pkg/operator/csidriveroperator/csioperatorclient"
30- csoutils "github.com/openshift/cluster-storage-operator/pkg/utils"
3124)
3225
3326const (
3427 deploymentControllerName = "CSIDriverOperatorDeployment"
3528)
3629
37- type CommonCSIDeploymentController struct {
38- name string
39- operatorClient v1helpers.OperatorClient
40- commonClients * csoclients.Clients
41- csiOperatorConfig csioperatorclient.CSIOperatorConfig
42- kubeClient kubernetes.Interface
43- versionGetter status.VersionGetter
44- targetVersion string
45- eventRecorder events.Recorder
46- infraLister configv1listers.InfrastructureLister
47- resyncInterval time.Duration
48- factory * factory.Factory
49- replacers []* strings.Replacer
50- manifestHooks []deploymentcontroller.ManifestHookFunc
51- deploymentHooks []deploymentcontroller.DeploymentHookFunc
52- }
53-
54- func (c * CommonCSIDeploymentController ) initController (factoryHookFunc func (* factory.Factory )) * factory.Factory {
55- f := factory .New ()
56- f = f .ResyncEvery (c .resyncInterval )
57- f = f .WithSyncDegradedOnError (c .operatorClient )
58- // Necessary to do initial Sync after the controller starts.
59- f = f .WithPostStartHooks (initalSync )
60- // Add informers to the factory now, but the actual event handlers
61- // are added later in CSIDriverOperatorDeploymentController.Run(),
62- // when we're 100% sure the controller is going to start (because it
63- // depends on the platform).
64- // If we added the event handlers now, all events would pile up in the
65- // controller queue, without anything reading it.
66- f = f .WithInformers (
67- c .commonClients .OperatorClient .Informer ())
68- factoryHookFunc (f )
69- return f
70- }
71-
72- func (c * CommonCSIDeploymentController ) preCheckSync (
73- ctx context.Context ,
74- syncCtx factory.SyncContext ) (bool , * operatorv1.OperatorStatus , * operatorv1.OperatorSpec , error ) {
75-
76- opSpec , opStatus , _ , err := c .operatorClient .GetOperatorState ()
77- if err != nil {
78- return false , opStatus , opSpec , err
79- }
80- if opSpec .ManagementState != operatorv1 .Managed {
81- return false , opStatus , opSpec , nil
82- }
83- return true , opStatus , opSpec , nil
84- }
85-
86- func (c * CommonCSIDeploymentController ) postSync (ctx context.Context , deployment * appsv1.Deployment ) error {
87- progressingCondition := operatorv1.OperatorCondition {
88- Type : c .name + operatorv1 .OperatorStatusTypeProgressing ,
89- Status : operatorv1 .ConditionFalse ,
90- }
91-
92- if ok , msg := isProgressing (deployment ); ok {
93- progressingCondition .Status = operatorv1 .ConditionTrue
94- progressingCondition .Message = msg
95- progressingCondition .Reason = "Deploying"
96- }
97-
98- updateStatusFn := func (newStatus * operatorv1.OperatorStatus ) error {
99- resourcemerge .SetDeploymentGeneration (& newStatus .Generations , deployment )
100- return nil
101- }
102-
103- _ , _ , err := v1helpers .UpdateStatus (
104- ctx ,
105- c .operatorClient ,
106- updateStatusFn ,
107- v1helpers .UpdateConditionFn (progressingCondition ),
108- )
109- return err
110- }
111-
112- func initCommonDeploymentParams (
113- client * csoclients.Clients ,
114- csiOperatorConfig csioperatorclient.CSIOperatorConfig ,
115- resyncInterval time.Duration ,
116- versionGetter status.VersionGetter ,
117- targetVersion string ,
118- eventRecorder events.Recorder ) CommonCSIDeploymentController {
119- c := CommonCSIDeploymentController {
120- name : csiOperatorConfig .ConditionPrefix ,
121- operatorClient : client .OperatorClient ,
122- kubeClient : client .KubeClient ,
123- csiOperatorConfig : csiOperatorConfig ,
124- commonClients : client ,
125- versionGetter : versionGetter ,
126- targetVersion : targetVersion ,
127- resyncInterval : resyncInterval ,
128- eventRecorder : eventRecorder .WithComponentSuffix (csiOperatorConfig .ConditionPrefix ),
129- infraLister : client .ConfigInformers .Config ().V1 ().Infrastructures ().Lister (),
130- }
131- c .manifestHooks = []deploymentcontroller.ManifestHookFunc {
132- c .getReplacerHook (),
133- c .getLogLevelHook (),
134- }
135- c .deploymentHooks = []deploymentcontroller.DeploymentHookFunc {
136- c .getProxyHook (),
137- }
138-
139- // Common replacers
140- c .replacers = []* strings.Replacer {sidecarReplacer }
141- if csiOperatorConfig .ImageReplacer != nil {
142- c .replacers = append (c .replacers , csiOperatorConfig .ImageReplacer )
143- }
144-
145- return c
146- }
147-
148- // This CSIDriverStarterController installs and syncs CSI driver operator Deployment.
149- // It replace ${LOG_LEVEL} in the Deployment with current log level.
150- // It replaces images in the Deployment using CSIOperatorConfig.ImageReplacer.
151- // It produces following Conditions:
152- // <CSI driver name>CSIDriverOperatorDeploymentProgressing
153- // <CSI driver name>CSIDriverOperatorDeploymentDegraded
154- // This controller doesn't set the Available condition to avoid prematurely cascading
155- // up to the clusteroperator CR a potential Available=false. On the other hand it
156- // does a better in making sure the Degraded condition is properly set if
157- // Deployment isn't healthy.
158- type CSIDriverOperatorDeploymentController struct {
159- CommonCSIDeploymentController
160- }
161-
162- var _ factory.Controller = & CSIDriverOperatorDeploymentController {}
163-
16430func NewCSIDriverOperatorDeploymentController (
16531 clients * csoclients.Clients ,
16632 csiOperatorConfig csioperatorclient.CSIOperatorConfig ,
@@ -169,28 +35,65 @@ func NewCSIDriverOperatorDeploymentController(
16935 eventRecorder events.Recorder ,
17036 resyncInterval time.Duration ,
17137) factory.Controller {
172- c := & CSIDriverOperatorDeploymentController {
173- CommonCSIDeploymentController : initCommonDeploymentParams (clients , csiOperatorConfig , resyncInterval , versionGetter , targetVersion , eventRecorder ),
38+
39+ deploymentBytes , err := assets .ReadFile (csiOperatorConfig .DeploymentAsset )
40+ if err != nil {
41+ panic (err )
42+ }
43+
44+ manifestHooks , deploymentHooks := getCommonHooks (getCommonReplacers (csiOperatorConfig ))
45+ deploymentHooks = append (deploymentHooks , getStandaloneNodeSelectorHook (clients .ConfigInformers .Config ().V1 ().Infrastructures ().Lister ()))
46+
47+ c , err := deploymentcontroller .NewDeploymentControllerBuilder (
48+ csiOperatorConfig .ConditionPrefix + deploymentControllerName ,
49+ deploymentBytes ,
50+ eventRecorder ,
51+ clients .OperatorClient ,
52+ clients .KubeClient ,
53+ clients .KubeInformers .InformersFor (csoclients .CSIOperatorNamespace ).Apps ().V1 ().Deployments (),
54+ ).WithConditions (
55+ // Explicitly disable Available condition to avoid prematurely cascading
56+ // up to the clusteroperator CR a potential Available=false.
57+ operatorv1 .OperatorStatusTypeProgressing ,
58+ operatorv1 .OperatorStatusTypeDegraded ,
59+ ).WithExtraInformers (
60+ clients .ConfigInformers .Config ().V1 ().Infrastructures ().Informer (),
61+ ).WithManifestHooks (
62+ manifestHooks ... ,
63+ ).WithDeploymentHooks (
64+ deploymentHooks ... ,
65+ ).WithPostStartHooks (
66+ initalSync ,
67+ ).ToController ()
68+ if err != nil {
69+ panic (err )
17470 }
175- f := c .initController (func (f * factory.Factory ) {
176- f .WithInformers (
177- c .commonClients .KubeInformers .InformersFor (csoclients .CSIOperatorNamespace ).Apps ().V1 ().Deployments ().Informer (),
178- c .commonClients .ConfigInformers .Config ().V1 ().Infrastructures ().Informer ())
179- })
71+ return c
72+ }
18073
181- // Standalone specific deployment hooks
182- c .deploymentHooks = append (c .deploymentHooks , c .getStandaloneNodeSelectorHook ())
74+ func getCommonReplacers (csiOperatorConfig csioperatorclient.CSIOperatorConfig ) []* strings.Replacer {
75+ replacers := []* strings.Replacer {sidecarReplacer }
76+ if csiOperatorConfig .ImageReplacer != nil {
77+ replacers = append (replacers , csiOperatorConfig .ImageReplacer )
78+ }
79+ return replacers
80+ }
18381
184- c .factory = f
185- return c
82+ func getCommonHooks (replacers []* strings.Replacer ) ([]deploymentcontroller.ManifestHookFunc , []deploymentcontroller.DeploymentHookFunc ) {
83+ return []deploymentcontroller.ManifestHookFunc {
84+ getReplacerHook (replacers ),
85+ getLogLevelHook (),
86+ }, []deploymentcontroller.DeploymentHookFunc {
87+ getProxyHook (),
88+ }
18689}
18790
188- func ( c * CommonCSIDeploymentController ) getReplacerHook ( ) deploymentcontroller.ManifestHookFunc {
91+ func getReplacerHook ( replacers [] * strings. Replacer ) deploymentcontroller.ManifestHookFunc {
18992 return func (spec * operatorv1.OperatorSpec , deploymentBytes []byte ) ([]byte , error ) {
19093 deploymentString := string (deploymentBytes )
19194
19295 // Replace images
193- for _ , replacer := range c . replacers {
96+ for _ , replacer := range replacers {
19497 // Replace images
19598 if replacer != nil {
19699 deploymentString = replacer .Replace (deploymentString )
@@ -201,23 +104,23 @@ func (c *CommonCSIDeploymentController) getReplacerHook() deploymentcontroller.M
201104 }
202105}
203106
204- func ( c * CommonCSIDeploymentController ) getLogLevelHook () deploymentcontroller.ManifestHookFunc {
107+ func getLogLevelHook () deploymentcontroller.ManifestHookFunc {
205108 return func (spec * operatorv1.OperatorSpec , deploymentBytes []byte ) ([]byte , error ) {
206109 logLevel := loglevel .LogLevelToVerbosity (spec .LogLevel )
207110 deploymentBytes = bytes .ReplaceAll (deploymentBytes , []byte ("${LOG_LEVEL}" ), []byte (strconv .Itoa (logLevel )))
208111 return deploymentBytes , nil
209112 }
210113}
211114
212- func ( c * CommonCSIDeploymentController ) getProxyHook () deploymentcontroller.DeploymentHookFunc {
115+ func getProxyHook () deploymentcontroller.DeploymentHookFunc {
213116 return func (spec * operatorv1.OperatorSpec , deployment * appsv1.Deployment ) error {
214117 return util .InjectObservedProxyInDeploymentContainers (deployment , spec )
215118 }
216119}
217120
218- func ( c * CSIDriverOperatorDeploymentController ) getStandaloneNodeSelectorHook () deploymentcontroller.DeploymentHookFunc {
121+ func getStandaloneNodeSelectorHook (infraLister configv1listers. InfrastructureLister ) deploymentcontroller.DeploymentHookFunc {
219122 return func (spec * operatorv1.OperatorSpec , deployment * appsv1.Deployment ) error {
220- infra , err := c . infraLister .Get (infraConfigName )
123+ infra , err := infraLister .Get (infraConfigName )
221124 if err != nil {
222125 return fmt .Errorf ("failed to get infrastructure resource: %w" , err )
223126 }
@@ -227,66 +130,3 @@ func (c *CSIDriverOperatorDeploymentController) getStandaloneNodeSelectorHook()
227130 return nil
228131 }
229132}
230-
231- func (c * CSIDriverOperatorDeploymentController ) Sync (ctx context.Context , syncCtx factory.SyncContext ) error {
232- klog .V (4 ).Infof ("CSIDriverOperatorDeploymentController sync started" )
233- defer klog .V (4 ).Infof ("CSIDriverOperatorDeploymentController sync finished" )
234-
235- runSync , opStatus , opSpec , err := c .preCheckSync (ctx , syncCtx )
236- if err != nil {
237- return err
238- }
239-
240- if ! runSync {
241- return nil
242- }
243-
244- required , err := csoutils .GetRequiredDeployment (c .csiOperatorConfig .DeploymentAsset , opSpec , c .manifestHooks , nil )
245- if err != nil {
246- return fmt .Errorf ("failed to generate required Deployment: %s" , err )
247- }
248-
249- requiredCopy := required .DeepCopy ()
250-
251- lastGeneration := resourcemerge .ExpectedDeploymentGeneration (requiredCopy , opStatus .Generations )
252- deployment , _ , err := resourceapply .ApplyDeployment (ctx , c .kubeClient .AppsV1 (), c .eventRecorder , requiredCopy , lastGeneration )
253- if err != nil {
254- return err
255- }
256-
257- err = c .postSync (ctx , deployment )
258- if err != nil {
259- return err
260- }
261- return checkDeploymentHealth (ctx , c .kubeClient .AppsV1 (), deployment )
262- }
263-
264- func (c * CSIDriverOperatorDeploymentController ) Run (ctx context.Context , workers int ) {
265- // This adds event handlers to informers.
266- ctrl := c .factory .WithSync (c .Sync ).ToController (c .Name (), c .eventRecorder )
267- ctrl .Run (ctx , workers )
268- }
269-
270- func (c * CSIDriverOperatorDeploymentController ) Name () string {
271- return c .name + deploymentControllerName
272- }
273-
274- // TODO: create a common function in library-go
275- func isProgressing (deployment * appsv1.Deployment ) (bool , string ) {
276- var deploymentExpectedReplicas int32
277- if deployment .Spec .Replicas != nil {
278- deploymentExpectedReplicas = * deployment .Spec .Replicas
279- }
280-
281- switch {
282- case deployment .Generation != deployment .Status .ObservedGeneration :
283- return true , "Waiting for Deployment to act on changes"
284- case deployment .Status .UnavailableReplicas > 0 :
285- return true , "Waiting for Deployment to deploy pods"
286- case deployment .Status .UpdatedReplicas < deploymentExpectedReplicas :
287- return true , "Waiting for Deployment to update pods"
288- case deployment .Status .AvailableReplicas < deploymentExpectedReplicas :
289- return true , "Waiting for Deployment to deploy pods"
290- }
291- return false , ""
292- }
0 commit comments