From a532f2f345fe711cc5bcd89f46adabd8440b992c Mon Sep 17 00:00:00 2001 From: arush sharma Date: Tue, 1 Apr 2025 08:59:00 -0700 Subject: [PATCH 1/2] add reconcile reources flag --- pkg/config/config.go | 71 +++++++++++++++++++++++++++++++ pkg/runtime/service_controller.go | 27 +++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 3e4a17c..c44ce6b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -64,6 +64,7 @@ const ( flagReconcileDefaultMaxConcurrency = "reconcile-default-max-concurrent-syncs" flagReconcileResourceMaxConcurrency = "reconcile-resource-max-concurrent-syncs" flagFeatureGates = "feature-gates" + flagReconcileResources = "reconcile-resources" envVarAWSRegion = "AWS_REGION" ) @@ -104,6 +105,7 @@ type Config struct { ReconcileResourceResyncSeconds []string ReconcileDefaultMaxConcurrency int ReconcileResourceMaxConcurrency []string + ReconcileResources string // TODO(a-hilaly): migrate to k8s.io/component-base and implement a proper parser for feature gates. FeatureGates featuregate.FeatureGates featureGatesRaw string @@ -250,6 +252,11 @@ func (cfg *Config) BindFlags() { "Valid keys are feature names and valid values are 'true' or 'false'."+ "Available features: "+strings.Join(featuregate.GetDefaultFeatureGates().GetFeatureNames(), ", "), ) + flag.StringVar( + &cfg.ReconcileResources, flagReconcileResources, + "", + "A comma-separated list of resource kinds to reconcile. If unspecified, all resources will be reconciled.", + ) } // SetupLogger initializes the logger used in the service controller @@ -389,6 +396,12 @@ func (cfg *Config) validateReconcileConfigResources(supportedGVKs []schema.Group return fmt.Errorf("invalid value for flag '%s': %v", flagReconcileResourceMaxConcurrency, err) } } + + // Also validate the resource filter settings + if err := cfg.validateReconcileResources(supportedGVKs); err != nil { + return err + } + return nil } @@ -564,3 +577,61 @@ func parseFeatureGates(featureGatesRaw string) (map[string]bool, error) { return featureGatesMap, nil } + +// GetReconcileResources returns a slice of resource kinds that should be reconciled. +func (cfg *Config) GetReconcileResources() ([]string, error) { + return parseReconcileResourcesString(cfg.ReconcileResources) +} + +// parseReconcileResourcesString parses the reconcileResources flag and returns a slice +// of resource kinds to reconcile. +func parseReconcileResourcesString(resources string) ([]string, error) { + resources = strings.TrimSpace(resources) + if resources == "" { + return nil, nil + } + + visited := make(map[string]bool) + resourceKinds := []string{} + + for _, kind := range strings.Split(resources, ",") { + kind = strings.TrimSpace(kind) + if kind == "" { + return nil, fmt.Errorf("invalid resource kind: empty kind") + } + if _, ok := visited[kind]; ok { + return nil, fmt.Errorf("duplicate resource kind '%s'", kind) + } + visited[kind] = true + resourceKinds = append(resourceKinds, kind) + } + return resourceKinds, nil +} + +// validateReconcileResources validates that the specified resource kinds are supported by the controller. +func (cfg *Config) validateReconcileResources(supportedGVKs []schema.GroupVersionKind) error { + resources, err := cfg.GetReconcileResources() + if err != nil { + return fmt.Errorf("invalid value for flag '%s': %v", flagReconcileResources, err) + } + if len(resources) == 0 { + return nil + } + + validResourceKinds := make([]string, 0, len(supportedGVKs)) + for _, gvk := range supportedGVKs { + validResourceKinds = append(validResourceKinds, gvk.Kind) + } + + for _, resource := range resources { + if !ackutil.InStrings(resource, validResourceKinds) { + return fmt.Errorf( + "invalid value for flag '%s': resource kind '%s' is not supported by this controller. Valid resource kinds are: %s", + flagReconcileResources, + resource, + strings.Join(validResourceKinds, ", "), + ) + } + } + return nil +} diff --git a/pkg/runtime/service_controller.go b/pkg/runtime/service_controller.go index 9276ab5..2d2a331 100644 --- a/pkg/runtime/service_controller.go +++ b/pkg/runtime/service_controller.go @@ -34,6 +34,7 @@ import ( ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" ackrtcache "github.com/aws-controllers-k8s/runtime/pkg/runtime/cache" acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + ackutil "github.com/aws-controllers-k8s/runtime/pkg/util" ) const ( @@ -271,7 +272,31 @@ func (c *serviceController) BindControllerManager(mgr ctrlrt.Manager, cfg ackcfg c.fieldExportReconciler = rec } - for _, rmf := range c.rmFactories { + // Get the list of resources to reconcile from the config + reconcileResources, err := cfg.GetReconcileResources() + if err != nil { + return fmt.Errorf("error parsing reconcile resources: %v", err) + } + + // Filter the resource manager factories + filteredRMFs := c.rmFactories + if len(reconcileResources) > 0 { + + filteredRMFs = make(map[string]acktypes.AWSResourceManagerFactory) + for key, rmf := range c.rmFactories { + rd := rmf.ResourceDescriptor() + resourceKind := rd.GroupVersionKind().Kind + + if ackutil.InStrings(resourceKind, reconcileResources) { + filteredRMFs[key] = rmf + c.log.Info("including reconciler for resource kind", "kind", resourceKind) + } else { + c.log.Info("excluding reconciler for resource kind", "kind", resourceKind, "reason", "not in reconcile-resources flag") + } + } + } + + for _, rmf := range filteredRMFs { rec := NewReconciler(c, rmf, c.log, cfg, c.metrics, cache) if err := rec.BindControllerManager(mgr); err != nil { return err From 9f6103ef6263c5f8599ac05495dd0152a47cb015 Mon Sep 17 00:00:00 2001 From: Arush Sharma Date: Tue, 8 Apr 2025 17:32:14 -0700 Subject: [PATCH 2/2] no resource message --- pkg/config/config.go | 13 ++++--------- pkg/runtime/service_controller.go | 4 +++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index c44ce6b..edca53f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -398,7 +398,7 @@ func (cfg *Config) validateReconcileConfigResources(supportedGVKs []schema.Group } // Also validate the resource filter settings - if err := cfg.validateReconcileResources(supportedGVKs); err != nil { + if err := cfg.validateReconcileResources(validResourceNames); err != nil { return err } @@ -609,7 +609,7 @@ func parseReconcileResourcesString(resources string) ([]string, error) { } // validateReconcileResources validates that the specified resource kinds are supported by the controller. -func (cfg *Config) validateReconcileResources(supportedGVKs []schema.GroupVersionKind) error { +func (cfg *Config) validateReconcileResources(validResourceNames []string) error { resources, err := cfg.GetReconcileResources() if err != nil { return fmt.Errorf("invalid value for flag '%s': %v", flagReconcileResources, err) @@ -618,18 +618,13 @@ func (cfg *Config) validateReconcileResources(supportedGVKs []schema.GroupVersio return nil } - validResourceKinds := make([]string, 0, len(supportedGVKs)) - for _, gvk := range supportedGVKs { - validResourceKinds = append(validResourceKinds, gvk.Kind) - } - for _, resource := range resources { - if !ackutil.InStrings(resource, validResourceKinds) { + if !ackutil.InStrings(resource, validResourceNames) { return fmt.Errorf( "invalid value for flag '%s': resource kind '%s' is not supported by this controller. Valid resource kinds are: %s", flagReconcileResources, resource, - strings.Join(validResourceKinds, ", "), + strings.Join(validResourceNames, ", "), ) } } diff --git a/pkg/runtime/service_controller.go b/pkg/runtime/service_controller.go index 2d2a331..7488c12 100644 --- a/pkg/runtime/service_controller.go +++ b/pkg/runtime/service_controller.go @@ -278,10 +278,12 @@ func (c *serviceController) BindControllerManager(mgr ctrlrt.Manager, cfg ackcfg return fmt.Errorf("error parsing reconcile resources: %v", err) } + if len(reconcileResources) == 0 { + c.log.Info("No resources? Did they all go on vacation? Defaulting to reconciling all resources.") + } // Filter the resource manager factories filteredRMFs := c.rmFactories if len(reconcileResources) > 0 { - filteredRMFs = make(map[string]acktypes.AWSResourceManagerFactory) for key, rmf := range c.rmFactories { rd := rmf.ResourceDescriptor()