Skip to content

Commit b5e7fbe

Browse files
authored
Improve feature gate handling in config and runtime (#162)
Improved the handling of feature gates in the `config` and `runtime` packages by updating the validation logic to properly handle errors when overriding feature gates. This patch also renams the `ReadOnly` featuregate to `ReadOnlyResources` to better describe its purpose. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 844d1e2 commit b5e7fbe

File tree

4 files changed

+22
-13
lines changed

4 files changed

+22
-13
lines changed

pkg/config/config.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,10 @@ func (cfg *Config) Validate(options ...Option) error {
340340
if err != nil {
341341
return fmt.Errorf("invalid value for flag '%s': %v", flagFeatureGates, err)
342342
}
343-
cfg.FeatureGates = featuregate.GetFeatureGatesWithOverrides(featureGatesMap)
343+
cfg.FeatureGates, err = featuregate.GetFeatureGatesWithOverrides(featureGatesMap)
344+
if err != nil {
345+
return fmt.Errorf("error overriding feature gates: %v", err)
346+
}
344347

345348
return nil
346349
}

pkg/featuregate/features.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
// optionally overridden.
1717
package featuregate
1818

19+
import "fmt"
20+
1921
const (
20-
ReadOnly = "ReadOnly"
21-
22+
// ReadOnlyResources is a feature gate for enabling ReadOnly resources annotation.
23+
ReadOnlyResources = "ReadOnlyResources"
24+
2225
// TeamLevelCARM is a feature gate for enabling CARM for team-level resources.
2326
TeamLevelCARM = "TeamLevelCARM"
2427

@@ -29,10 +32,9 @@ const (
2932
// defaultACKFeatureGates is a map of feature names to Feature structs
3033
// representing the default feature gates for ACK controllers.
3134
var defaultACKFeatureGates = FeatureGates{
32-
// Set feature gates here
33-
ReadOnly: {Stage: Alpha, Enabled: false},
34-
TeamLevelCARM: {Stage: Alpha, Enabled: false},
35-
ServiceLevelCARM: {Stage: Alpha, Enabled: false},
35+
ReadOnlyResources: {Stage: Alpha, Enabled: false},
36+
TeamLevelCARM: {Stage: Alpha, Enabled: false},
37+
ServiceLevelCARM: {Stage: Alpha, Enabled: false},
3638
}
3739

3840
// FeatureStage represents the development stage of a feature.
@@ -102,13 +104,15 @@ func GetDefaultFeatureGates() FeatureGates {
102104

103105
// GetFeatureGatesWithOverrides returns a new FeatureGates instance with the default features,
104106
// but with the provided overrides applied. This allows for runtime configuration of feature gates.
105-
func GetFeatureGatesWithOverrides(featureGateOverrides map[string]bool) FeatureGates {
107+
func GetFeatureGatesWithOverrides(featureGateOverrides map[string]bool) (FeatureGates, error) {
106108
gates := GetDefaultFeatureGates()
107109
for name, enabled := range featureGateOverrides {
108110
if feature, ok := gates[name]; ok {
109111
feature.Enabled = enabled
110112
gates[name] = feature
113+
} else {
114+
return nil, fmt.Errorf("unknown feature gate: %v", name)
111115
}
112116
}
113-
return gates
117+
return gates, nil
114118
}

pkg/featuregate/features_test.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ package featuregate
1515

1616
import (
1717
"testing"
18+
19+
"github.com/stretchr/testify/require"
1820
)
1921

2022
func TestIsEnabled(t *testing.T) {
@@ -108,10 +110,10 @@ func TestGetFeatureGatesWithOverrides(t *testing.T) {
108110
overrides := map[string]bool{
109111
"feature1": true,
110112
"feature2": false,
111-
"feature4": true, // This should be ignored as it's not in defaultFeatureGates
112113
}
113114

114-
gates := GetFeatureGatesWithOverrides(overrides)
115+
gates, err := GetFeatureGatesWithOverrides(overrides)
116+
require.Nil(t, err)
115117

116118
tests := []struct {
117119
name string

pkg/runtime/reconciler.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ func (r *resourceReconciler) reconcile(
313313
if r.getDeletionPolicy(res) == ackv1alpha1.DeletionPolicyDelete &&
314314
// If the ReadOnly feature gate is enabled, and the resource is read-only,
315315
// we don't delete the resource.
316-
!(r.cfg.FeatureGates.IsEnabled(featuregate.ReadOnly) && IsReadOnly(res)) {
316+
!(r.cfg.FeatureGates.IsEnabled(featuregate.ReadOnlyResources) && IsReadOnly(res)) {
317317
// Resolve references before deleting the resource.
318318
// Ignore any errors while resolving the references
319319
resolved, _, _ := rm.ResolveReferences(ctx, r.apiReader, res)
@@ -360,7 +360,7 @@ func (r *resourceReconciler) Sync(
360360
isAdopted := IsAdopted(desired)
361361
rlog.WithValues("is_adopted", isAdopted)
362362

363-
if r.cfg.FeatureGates.IsEnabled(featuregate.ReadOnly) {
363+
if r.cfg.FeatureGates.IsEnabled(featuregate.ReadOnlyResources) {
364364
isReadOnly := IsReadOnly(desired)
365365
rlog.WithValues("is_read_only", isReadOnly)
366366

0 commit comments

Comments
 (0)