@@ -45,6 +45,7 @@ import (
4545 "sigs.k8s.io/controller-runtime/pkg/healthz"
4646 "sigs.k8s.io/controller-runtime/pkg/log/zap"
4747 "sigs.k8s.io/controller-runtime/pkg/manager"
48+ "sigs.k8s.io/controller-runtime/pkg/metrics/server"
4849
4950 infrav1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
5051 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/controllers"
@@ -69,12 +70,26 @@ const (
6970 defaultMaxConcurrentReconciles = 10
7071)
7172
73+ type options struct {
74+ enableLeaderElection bool
75+ healthProbeAddr string
76+ maxConcurrentReconciles int
77+
78+ rateLimiterBaseDelay time.Duration
79+ rateLimiterMaxDelay time.Duration
80+ rateLimiterBucketSize int
81+ rateLimiterQPS int
82+
83+ managerOptions capiflags.ManagerOptions
84+ zapOptions zap.Options
85+ }
86+
7287type managerConfig struct {
7388 enableLeaderElection bool
74- probeAddr string
89+ healthProbeAddr string
7590 concurrentReconcilesNutanixCluster int
7691 concurrentReconcilesNutanixMachine int
77- managerOptions capiflags. ManagerOptions
92+ metricsServerOpts server. Options
7893
7994 logger logr.Logger
8095 restConfig * rest.Config
@@ -126,42 +141,82 @@ func validateRateLimiterConfig(baseDelay, maxDelay time.Duration, bucketSize, qp
126141 return nil
127142}
128143
129- func parseFlags (config * managerConfig ) {
130- capiflags .AddManagerOptions (pflag .CommandLine , & config .managerOptions )
131- pflag .StringVar (& config .probeAddr , "health-probe-bind-address" , ":8081" , "The address the probe endpoint binds to." )
132- pflag .BoolVar (& config .enableLeaderElection , "leader-elect" , false ,
144+ func initializeFlags () * options {
145+ opts := & options {}
146+
147+ // Add the controller-runtime flags to the standard library FlagSet.
148+ ctrl .RegisterFlags (flag .CommandLine )
149+
150+ // Add the Cluster API flags to the pflag FlagSet.
151+ capiflags .AddManagerOptions (pflag .CommandLine , & opts .managerOptions )
152+
153+ // Add zap flags to the standard libary FlagSet.
154+ opts .zapOptions .BindFlags (flag .CommandLine )
155+
156+ // Add our own flags to the pflag FlagSet.
157+ pflag .StringVar (& opts .healthProbeAddr , "health-probe-bind-address" , ":8081" , "The address the probe endpoint binds to." )
158+ pflag .BoolVar (& opts .enableLeaderElection , "leader-elect" , false ,
133159 "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager." )
134- var maxConcurrentReconciles int
135- pflag .IntVar (& maxConcurrentReconciles , "max-concurrent-reconciles" , defaultMaxConcurrentReconciles ,
160+
161+ pflag .IntVar (& opts . maxConcurrentReconciles , "max-concurrent-reconciles" , defaultMaxConcurrentReconciles ,
136162 "The maximum number of allowed, concurrent reconciles." )
137163
138- var baseDelay , maxDelay time.Duration
139- var bucketSize , qps int
140- pflag .DurationVar (& baseDelay , "rate-limiter-base-delay" , 500 * time .Millisecond , "The base delay for the rate limiter." )
141- pflag .DurationVar (& maxDelay , "rate-limiter-max-delay" , 15 * time .Minute , "The maximum delay for the rate limiter." )
142- pflag .IntVar (& bucketSize , "rate-limiter-bucket-size" , 100 , "The bucket size for the rate limiter." )
143- pflag .IntVar (& qps , "rate-limiter-qps" , 10 , "The QPS for the rate limiter." )
164+ pflag .DurationVar (& opts .rateLimiterBaseDelay , "rate-limiter-base-delay" , 500 * time .Millisecond , "The base delay for the rate limiter." )
165+ pflag .DurationVar (& opts .rateLimiterMaxDelay , "rate-limiter-max-delay" , 15 * time .Minute , "The maximum delay for the rate limiter." )
166+ pflag .IntVar (& opts .rateLimiterBucketSize , "rate-limiter-bucket-size" , 100 , "The bucket size for the rate limiter." )
167+ pflag .IntVar (& opts .rateLimiterQPS , "rate-limiter-qps" , 10 , "The QPS for the rate limiter." )
144168
145- opts := zap.Options {
146- TimeEncoder : zapcore .RFC3339TimeEncoder ,
147- }
148- opts .BindFlags (flag .CommandLine )
149-
150- logger := zap .New (zap .UseFlagOptions (& opts ))
151- ctrl .SetLogger (logger )
169+ // At this point, we should be done adding flags to the standard library FlagSet, flag.CommandLine.
170+ // So we can include the flags that third-party libraries, e.g. controller-runtime, and zap,
171+ // have added to the standard library FlagSet, we merge it into the pflag FlagSet.
152172 pflag .CommandLine .AddGoFlagSet (flag .CommandLine )
173+
174+ // Parse flags.
153175 pflag .Parse ()
154176
155- config .concurrentReconcilesNutanixCluster = maxConcurrentReconciles
156- config .concurrentReconcilesNutanixMachine = maxConcurrentReconciles
177+ return opts
178+ }
179+
180+ func initializeConfig (opts * options ) (* managerConfig , error ) {
181+ config := & managerConfig {
182+ enableLeaderElection : opts .enableLeaderElection ,
183+ healthProbeAddr : opts .healthProbeAddr ,
184+ }
157185
158- rateLimiter , err := compositeRateLimiter ( baseDelay , maxDelay , bucketSize , qps )
186+ _ , metricsServerOpts , err := capiflags . GetManagerOptions ( opts . managerOptions )
159187 if err != nil {
160- config .logger .Error (err , "unable to create composite rate limiter" )
161- os .Exit (1 )
188+ return nil , fmt .Errorf ("unable to get metrics server options: %w" , err )
189+ }
190+ if metricsServerOpts == nil {
191+ return nil , errors .New ("parsed manager options are nil" )
162192 }
193+ config .metricsServerOpts = * metricsServerOpts
194+
195+ config .concurrentReconcilesNutanixCluster = opts .maxConcurrentReconciles
196+ config .concurrentReconcilesNutanixMachine = opts .maxConcurrentReconciles
163197
198+ rateLimiter , err := compositeRateLimiter (opts .rateLimiterBaseDelay , opts .rateLimiterMaxDelay , opts .rateLimiterBucketSize , opts .rateLimiterQPS )
199+ if err != nil {
200+ return nil , fmt .Errorf ("unable to create composite rate limiter: %w" , err )
201+ }
164202 config .rateLimiter = rateLimiter
203+
204+ zapOptions := opts .zapOptions
205+ zapOptions .TimeEncoder = zapcore .RFC3339TimeEncoder
206+ config .logger = zap .New (zap .UseFlagOptions (& zapOptions ))
207+
208+ // Configure controller-runtime logger before using calling any controller-runtime functions.
209+ // Otherwise, the user will not see warnings and errors logged by these functions.
210+ ctrl .SetLogger (config .logger )
211+
212+ // Before calling GetConfigOrDie, we have parsed flags, because the function reads value of
213+ // the--kubeconfig flag.
214+ config .restConfig , err = ctrl .GetConfig ()
215+ if err != nil {
216+ return nil , fmt .Errorf ("failed to load kubeconfig: %w" , err )
217+ }
218+
219+ return config , nil
165220}
166221
167222func setupLogger () logr.Logger {
@@ -276,19 +331,10 @@ func runManager(ctx context.Context, mgr manager.Manager, config *managerConfig)
276331}
277332
278333func initializeManager (config * managerConfig ) (manager.Manager , error ) {
279- _ , metricsOpts , err := capiflags .GetManagerOptions (config .managerOptions )
280- if err != nil {
281- return nil , fmt .Errorf ("unable to get manager options: %w" , err )
282- }
283-
284- if metricsOpts == nil {
285- return nil , errors .New ("parsed manager options are nil" )
286- }
287-
288334 mgr , err := ctrl .NewManager (config .restConfig , ctrl.Options {
289335 Scheme : scheme ,
290- Metrics : * metricsOpts ,
291- HealthProbeBindAddress : config .probeAddr ,
336+ Metrics : config . metricsServerOpts ,
337+ HealthProbeBindAddress : config .healthProbeAddr ,
292338 LeaderElection : config .enableLeaderElection ,
293339 LeaderElectionID : "f265110d.cluster.x-k8s.io" ,
294340 })
@@ -306,16 +352,17 @@ func initializeManager(config *managerConfig) (manager.Manager, error) {
306352func main () {
307353 logger := setupLogger ()
308354
309- config := & managerConfig {}
310- parseFlags (config )
355+ logger .Info ("Initializing Nutanix Cluster API Infrastructure Provider" , "Git Hash" , gitCommitHash )
311356
312- // Flags must be parsed before calling GetConfigOrDie, because
313- // it reads the value of the--kubeconfig flag.
314- config .restConfig = ctrl .GetConfigOrDie ()
357+ opts := initializeFlags ()
358+ // After this point, we must not add flags to either the pflag, or the standard library FlagSets.
315359
316- config .logger = logger
360+ config , err := initializeConfig (opts )
361+ if err != nil {
362+ logger .Error (err , "unable to configure manager" )
363+ os .Exit (1 )
364+ }
317365
318- logger .Info ("Initializing Nutanix Cluster API Infrastructure Provider" , "Git Hash" , gitCommitHash )
319366 mgr , err := initializeManager (config )
320367 if err != nil {
321368 logger .Error (err , "unable to create manager" )
0 commit comments