Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions internal/featuregates/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,38 +38,46 @@ type Mapper struct {
featureGates gateMapFunc
}

func enableFeature(v *helmvalues.HelmValues, addList, removeList, feature string) error {
var errs []error
errs = append(errs, v.RemoveListValue(removeList, feature))
errs = append(errs, v.AddListValue(addList, feature))
return errors.Join(errs...)
}
func enableCatalogdFeature(v *helmvalues.HelmValues, enabled bool, feature string) error {
if enabled {
return enableFeature(v, helmvalues.EnableCatalogd, helmvalues.DisableCatalogd, feature)
}
return enableFeature(v, helmvalues.DisableCatalogd, helmvalues.EnableCatalogd, feature)
}

func enableOperatorControllerFeature(v *helmvalues.HelmValues, enabled bool, feature string) error {
if enabled {
return enableFeature(v, helmvalues.EnableOperatorController, helmvalues.DisableOperatorController, feature)
}
return enableFeature(v, helmvalues.DisableOperatorController, helmvalues.EnableOperatorController, feature)
}

func NewMapper() *Mapper {
// Add your downstream to upstream mapping here

featureGates := gateMapFunc{
// features.FeatureGateNewOLMMyDownstreamFeature: functon that returns a list of enabled and disabled gates
features.FeatureGateNewOLMPreflightPermissionChecks: func(v *helmvalues.HelmValues, enabled bool) error {
if enabled {
return v.AddListValue(helmvalues.EnableOperatorController, PreflightPermissions)
}
return v.AddListValue(helmvalues.DisableOperatorController, PreflightPermissions)
return enableOperatorControllerFeature(v, enabled, PreflightPermissions)
},
features.FeatureGateNewOLMOwnSingleNamespace: func(v *helmvalues.HelmValues, enabled bool) error {
if enabled {
return v.AddListValue(helmvalues.EnableOperatorController, SingleOwnNamespaceInstallSupport)
}
return v.AddListValue(helmvalues.DisableOperatorController, SingleOwnNamespaceInstallSupport)
return enableOperatorControllerFeature(v, enabled, SingleOwnNamespaceInstallSupport)
},
features.FeatureGateNewOLMWebhookProviderOpenshiftServiceCA: func(v *helmvalues.HelmValues, enabled bool) error {
var errs []error
if enabled {
errs = append(errs, v.AddListValue(helmvalues.EnableOperatorController, WebhookProviderOpenshiftServiceCA))
} else {
errs = append(errs, v.AddListValue(helmvalues.DisableOperatorController, WebhookProviderOpenshiftServiceCA))
}
errs = append(errs, v.AddListValue(helmvalues.DisableOperatorController, WebhookProviderCertManager))
errs = append(errs, enableOperatorControllerFeature(v, enabled, WebhookProviderOpenshiftServiceCA))
// Always disable WebhookProviderCertManager
errs = append(errs, enableOperatorControllerFeature(v, false, WebhookProviderCertManager))
return errors.Join(errs...)
},
features.FeatureGateNewOLMCatalogdAPIV1Metas: func(v *helmvalues.HelmValues, enabled bool) error {
if enabled {
return v.AddListValue(helmvalues.EnableCatalogd, APIV1MetasHandler)
}
return v.AddListValue(helmvalues.DisableCatalogd, APIV1MetasHandler)
return enableCatalogdFeature(v, enabled, APIV1MetasHandler)
},
}

Expand Down
314 changes: 314 additions & 0 deletions internal/featuregates/mapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,317 @@ func TestMapper_Constants(t *testing.T) {
t.Error("APIV1MetasHandler and PreflightPermissions should be different")
}
}

func TestEnableFeature(t *testing.T) {
tests := []struct {
name string
addList string
removeList string
feature string
initialVals map[string]interface{}
expectedVals map[string]interface{}
}{
{
name: "enable feature in empty values",
addList: helmvalues.EnableOperatorController,
removeList: helmvalues.DisableOperatorController,
feature: PreflightPermissions,
initialVals: make(map[string]interface{}),
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"enabled": []interface{}{PreflightPermissions},
},
},
},
},
},
{
name: "enable feature and remove from disabled list",
addList: helmvalues.EnableOperatorController,
removeList: helmvalues.DisableOperatorController,
feature: PreflightPermissions,
initialVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{PreflightPermissions},
},
},
},
},
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{},
"enabled": []interface{}{PreflightPermissions},
},
},
},
},
},
{
name: "enable catalogd feature",
addList: helmvalues.EnableCatalogd,
removeList: helmvalues.DisableCatalogd,
feature: APIV1MetasHandler,
initialVals: map[string]interface{}{
"options": map[string]interface{}{
"catalogd": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{APIV1MetasHandler},
},
},
},
},
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"catalogd": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{},
"enabled": []interface{}{APIV1MetasHandler},
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hv := helmvalues.NewHelmValues()
hv.GetValues()
for k, v := range tt.initialVals {
hv.GetValues()[k] = v
}

err := enableFeature(hv, tt.addList, tt.removeList, tt.feature)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

actual := hv.GetValues()
if !reflect.DeepEqual(actual, tt.expectedVals) {
t.Errorf("Expected values %v, got %v", tt.expectedVals, actual)
}
})
}
}

func TestEnableOperatorControllerFeature(t *testing.T) {
tests := []struct {
name string
enabled bool
feature string
initialVals map[string]interface{}
expectedVals map[string]interface{}
}{
{
name: "enable feature",
enabled: true,
feature: PreflightPermissions,
initialVals: make(map[string]interface{}),
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"enabled": []interface{}{PreflightPermissions},
},
},
},
},
},
{
name: "disable feature",
enabled: false,
feature: PreflightPermissions,
initialVals: make(map[string]interface{}),
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{PreflightPermissions},
},
},
},
},
},
{
name: "enable feature removes from disabled",
enabled: true,
feature: SingleOwnNamespaceInstallSupport,
initialVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{SingleOwnNamespaceInstallSupport},
},
},
},
},
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{},
"enabled": []interface{}{SingleOwnNamespaceInstallSupport},
},
},
},
},
},
{
name: "disable feature removes from enabled",
enabled: false,
feature: SingleOwnNamespaceInstallSupport,
initialVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"enabled": []interface{}{SingleOwnNamespaceInstallSupport},
},
},
},
},
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"operatorController": map[string]interface{}{
"features": map[string]interface{}{
"enabled": []interface{}{},
"disabled": []interface{}{SingleOwnNamespaceInstallSupport},
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hv := helmvalues.NewHelmValues()
for k, v := range tt.initialVals {
hv.GetValues()[k] = v
}

err := enableOperatorControllerFeature(hv, tt.enabled, tt.feature)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

actual := hv.GetValues()
if !reflect.DeepEqual(actual, tt.expectedVals) {
t.Errorf("Expected values %v, got %v", tt.expectedVals, actual)
}
})
}
}

func TestEnableCatalogdFeature(t *testing.T) {
tests := []struct {
name string
enabled bool
feature string
initialVals map[string]interface{}
expectedVals map[string]interface{}
}{
{
name: "enable catalogd feature",
enabled: true,
feature: APIV1MetasHandler,
initialVals: make(map[string]interface{}),
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"catalogd": map[string]interface{}{
"features": map[string]interface{}{
"enabled": []interface{}{APIV1MetasHandler},
},
},
},
},
},
{
name: "disable catalogd feature",
enabled: false,
feature: APIV1MetasHandler,
initialVals: make(map[string]interface{}),
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"catalogd": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{APIV1MetasHandler},
},
},
},
},
},
{
name: "enable catalogd feature removes from disabled",
enabled: true,
feature: APIV1MetasHandler,
initialVals: map[string]interface{}{
"options": map[string]interface{}{
"catalogd": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{APIV1MetasHandler},
},
},
},
},
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"catalogd": map[string]interface{}{
"features": map[string]interface{}{
"disabled": []interface{}{},
"enabled": []interface{}{APIV1MetasHandler},
},
},
},
},
},
{
name: "disable catalogd feature removes from enabled",
enabled: false,
feature: APIV1MetasHandler,
initialVals: map[string]interface{}{
"options": map[string]interface{}{
"catalogd": map[string]interface{}{
"features": map[string]interface{}{
"enabled": []interface{}{APIV1MetasHandler},
},
},
},
},
expectedVals: map[string]interface{}{
"options": map[string]interface{}{
"catalogd": map[string]interface{}{
"features": map[string]interface{}{
"enabled": []interface{}{},
"disabled": []interface{}{APIV1MetasHandler},
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hv := helmvalues.NewHelmValues()
for k, v := range tt.initialVals {
hv.GetValues()[k] = v
}

err := enableCatalogdFeature(hv, tt.enabled, tt.feature)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

actual := hv.GetValues()
if !reflect.DeepEqual(actual, tt.expectedVals) {
t.Errorf("Expected values %v, got %v", tt.expectedVals, actual)
}
})
}
}
2 changes: 1 addition & 1 deletion pkg/controller/featuregates_hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import (
// upstreamFeatureGates builds a set of helm values for the downsteeam feature-gates that are
// mapped to upstream feature-gates
func upstreamFeatureGates(
values *helmvalues.HelmValues,
clusterGatesConfig featuregates.FeatureGate,
downstreamGates []configv1.FeatureGateName,
downstreamToUpstreamFunc func(configv1.FeatureGateName) func(*helmvalues.HelmValues, bool) error,
) (*helmvalues.HelmValues, error) {
errs := make([]error, 0, len(downstreamGates))
values := helmvalues.NewHelmValues()

for _, downstreamGate := range downstreamGates {
f := downstreamToUpstreamFunc(downstreamGate)
Expand Down
Loading