From 456dff3f39f923644181b3a8175517efca64a344 Mon Sep 17 00:00:00 2001 From: Scott Andrews Date: Tue, 3 May 2022 12:25:18 -0400 Subject: [PATCH] Allow WithConfig to create dynamic configs WithConfig#Config is now a function that has access to the context and the current config. A custom config can be created for a specific parent resource. Signed-off-by: Scott Andrews --- README.md | 18 ++++++++++-------- reconcilers/reconcilers.go | 22 ++++++++++++++++------ reconcilers/reconcilers_test.go | 4 +++- reconcilers/reconcilers_validate_test.go | 21 ++++++++------------- 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index bb9e544..f6bd63f 100644 --- a/README.md +++ b/README.md @@ -264,20 +264,22 @@ func FunctionReconciler(c reconcilers.Config) *reconcilers.ParentReconciler { `WithConfig` can be used to change the REST Config backing the clients. This could be to make requests to the same cluster with a user defined service account, or target an entirely different Kubernetes cluster. ```go -func SwapRESTConfig(c reconciler.Config, rc *rest.Config) (*reconcilers.SubReconciler, error) { - cl, err := clusters.New(rc) - if err != nil { - return nil, err - } - +func SwapRESTConfig(rc *rest.Config) *reconcilers.SubReconciler { return &reconcilers.WithConfig{ Reconciler: reconcilers.Sequence{ LookupReferenceDataReconciler(), DoSomethingChildReconciler(), }, - Config: c.WithCluster(cl), - }, nil + Config: func(ctx context.Context, c reconciler.Config) (reconciler.Config, error ) { + // the rest config could also be stashed from a lookup in a SyncReconciler based on a dynamic value + cl, err := clusters.New(rc) + if err != nil { + return reconciler.Config{}, err + } + return c.WithCluster(cl), nil + } + } } ``` diff --git a/reconcilers/reconcilers.go b/reconcilers/reconcilers.go index 1acdeb5..b008cc6 100644 --- a/reconcilers/reconcilers.go +++ b/reconcilers/reconcilers.go @@ -56,7 +56,7 @@ func (c Config) IsEmpty() bool { return c == Config{} } -// WithConfig extends the config to access a new cluster. +// WithCluster extends the config to access a new cluster. func (c Config) WithCluster(cluster cluster.Cluster) Config { return Config{ Client: cluster.GetClient(), @@ -1109,8 +1109,10 @@ func (r *CastParent) cast(ctx context.Context, parent client.Object) (context.Co // The specified config can be accessed with `RetrieveConfig(ctx)`, the original config used to // load the parent resource can be accessed with `RetrieveParentConfig(ctx)`. type WithConfig struct { - // Config to use for this portion of the reconciler hierarchy - Config Config + // Config to use for this portion of the reconciler hierarchy. This method is called during + // setup and during reconciliation, if context is needed, it should be available durring both + // phases. + Config func(context.Context, Config) (Config, error) // Reconciler is called for each reconciler request with the parent // resource being reconciled. Typically a Sequence is used to compose @@ -1122,13 +1124,17 @@ func (r *WithConfig) SetupWithManager(ctx context.Context, mgr ctrl.Manager, bld if err := r.validate(ctx); err != nil { return err } - ctx = StashConfig(ctx, r.Config) + c, err := r.Config(ctx, RetrieveConfig(ctx)) + if err != nil { + return err + } + ctx = StashConfig(ctx, c) return r.Reconciler.SetupWithManager(ctx, mgr, bldr) } func (r *WithConfig) validate(ctx context.Context) error { // validate Config value - if r.Config.IsEmpty() { + if r.Config == nil { return fmt.Errorf("Config must be defined") } @@ -1141,7 +1147,11 @@ func (r *WithConfig) validate(ctx context.Context) error { } func (r *WithConfig) Reconcile(ctx context.Context, parent client.Object) (ctrl.Result, error) { - ctx = StashConfig(ctx, r.Config) + c, err := r.Config(ctx, RetrieveConfig(ctx)) + if err != nil { + return ctrl.Result{}, err + } + ctx = StashConfig(ctx, c) return r.Reconciler.Reconcile(ctx, parent) } diff --git a/reconcilers/reconcilers_test.go b/reconcilers/reconcilers_test.go index c1b33a0..0ca68cc 100644 --- a/reconcilers/reconcilers_test.go +++ b/reconcilers/reconcilers_test.go @@ -1429,7 +1429,9 @@ func TestWithConfig(t *testing.T) { } return &reconcilers.WithConfig{ - Config: c, + Config: func(ctx context.Context, _ reconcilers.Config) (reconcilers.Config, error) { + return c, nil + }, Reconciler: &reconcilers.SyncReconciler{ Sync: func(ctx context.Context, parent *resources.TestResource) error { ac := reconcilers.RetrieveConfig(ctx) diff --git a/reconcilers/reconcilers_validate_test.go b/reconcilers/reconcilers_validate_test.go index b4a802d..1c707f6 100644 --- a/reconcilers/reconcilers_validate_test.go +++ b/reconcilers/reconcilers_validate_test.go @@ -758,23 +758,17 @@ func TestWithConfig_validate(t *testing.T) { name: "valid", parent: &corev1.ConfigMap{}, reconciler: &WithConfig{ - Config: config, - Reconciler: &SyncReconciler{ - Sync: func(ctx context.Context, parent *corev1.Secret) error { - return nil - }, + Reconciler: &Sequence{}, + Config: func(ctx context.Context, c Config) (Config, error) { + return config, nil }, }, }, { - name: "missing type", + name: "missing config", parent: &corev1.ConfigMap{}, reconciler: &WithConfig{ - Reconciler: &SyncReconciler{ - Sync: func(ctx context.Context, parent *corev1.Secret) error { - return nil - }, - }, + Reconciler: &Sequence{}, }, shouldErr: "Config must be defined", }, @@ -782,8 +776,9 @@ func TestWithConfig_validate(t *testing.T) { name: "missing reconciler", parent: &corev1.ConfigMap{}, reconciler: &WithConfig{ - Config: config, - Reconciler: nil, + Config: func(ctx context.Context, c Config) (Config, error) { + return config, nil + }, }, shouldErr: "Reconciler must be defined", },