Skip to content

Commit 4301e6e

Browse files
author
Per Goncalves da Silva
committed
Update applier to use BundleConfig
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 442335e commit 4301e6e

File tree

2 files changed

+195
-2
lines changed

2 files changed

+195
-2
lines changed

internal/operator-controller/applier/helm.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package applier
33
import (
44
"bytes"
55
"context"
6+
"encoding/json"
67
"errors"
78
"fmt"
89
"io"
@@ -207,7 +208,8 @@ func (h *Helm) buildHelmChart(bundleFS fs.FS, ext *ocv1.ClusterExtension) (*char
207208
if h.BundleToHelmChartConverter == nil {
208209
return nil, errors.New("BundleToHelmChartConverter is nil")
209210
}
210-
watchNamespace, err := GetWatchNamespace(ext)
211+
212+
bundleConfig, err := GetBundleConfig(ext)
211213
if err != nil {
212214
return nil, err
213215
}
@@ -222,7 +224,7 @@ func (h *Helm) buildHelmChart(bundleFS fs.FS, ext *ocv1.ClusterExtension) (*char
222224
}
223225
}
224226

225-
return h.BundleToHelmChartConverter.ToHelmChart(source.FromFS(bundleFS), ext.Spec.Namespace, watchNamespace)
227+
return h.BundleToHelmChartConverter.ToHelmChart(source.FromFS(bundleFS), ext.Spec.Namespace, bundleConfig.WatchNamespace)
226228
}
227229

228230
func (h *Helm) renderClientOnlyRelease(ctx context.Context, ext *ocv1.ClusterExtension, chrt *chart.Chart, values chartutil.Values, post postrender.PostRenderer) (*release.Release, error) {
@@ -339,3 +341,33 @@ func ruleDescription(ns string, rule rbacv1.PolicyRule) string {
339341
}
340342
return sb.String()
341343
}
344+
345+
// TODO: BundleConfig and its handling will move to the renderer in a follow-up PR. This is here temporarily so we can make
346+
//
347+
// forward progress with the config story and already lay the API foundations for it while having some minimal functionality
348+
type BundleConfig struct {
349+
WatchNamespace string `json:"watchNamespace,omitempty"`
350+
}
351+
352+
// GetBundleConfig returns a BundleConfig based on the cluster extension config contained in the cluster extension spec.
353+
// It will include the watchNamespace configured through the annotation if the single-/own namespace feature is on.
354+
// Though, its value will be overridden by the contents of the cluster extension config in the spec.
355+
func GetBundleConfig(ext *ocv1.ClusterExtension) (BundleConfig, error) {
356+
watchNamespace, err := GetWatchNamespace(ext)
357+
if err != nil {
358+
return BundleConfig{}, err
359+
}
360+
cfg := BundleConfig{
361+
WatchNamespace: watchNamespace,
362+
}
363+
364+
if features.OperatorControllerFeatureGate.Enabled(features.ClusterExtensionConfigSupport) {
365+
if ext.Spec.Config != nil && ext.Spec.Config.Inline != nil {
366+
cfg = BundleConfig{}
367+
if err := json.Unmarshal(ext.Spec.Config.Inline.Raw, &cfg); err != nil {
368+
return BundleConfig{}, fmt.Errorf("invalid bundle configuration: %w", err)
369+
}
370+
}
371+
}
372+
return cfg, nil
373+
}

internal/operator-controller/applier/helm_test.go

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"helm.sh/helm/v3/pkg/storage/driver"
1717
corev1 "k8s.io/api/core/v1"
1818
rbacv1 "k8s.io/api/rbac/v1"
19+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1920
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2021
featuregatetesting "k8s.io/component-base/featuregate/testing"
2122
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -621,6 +622,166 @@ func TestApply_RegistryV1ToChartConverterIntegration(t *testing.T) {
621622
})
622623
}
623624

625+
func Test_GetBundleConfig_NoFeatureGates(t *testing.T) {
626+
// without any feature gates enabled such SingleOwnNamespace or ClusterExtensionConfig support
627+
// the returned config should not consider any configuration in the spec or annotations
628+
cfg, err := applier.GetBundleConfig(&ocv1.ClusterExtension{
629+
ObjectMeta: metav1.ObjectMeta{
630+
Annotations: map[string]string{
631+
"olm.operatorframework.io/watch-namespace": "watch-namespace",
632+
},
633+
},
634+
Spec: ocv1.ClusterExtensionSpec{
635+
Config: &ocv1.ClusterExtensionConfig{
636+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
637+
Inline: &apiextensionsv1.JSON{
638+
Raw: []byte(`{"watchNamespace":"watch-namespace"}`),
639+
},
640+
},
641+
},
642+
})
643+
require.NoError(t, err)
644+
require.Equal(t, applier.BundleConfig{}, cfg)
645+
}
646+
647+
func Test_GetBundleConfig_SingleOwnNamespaceInstallSupport_Enabled(t *testing.T) {
648+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.SingleOwnNamespaceInstallSupport, true)
649+
cfg, err := applier.GetBundleConfig(&ocv1.ClusterExtension{
650+
ObjectMeta: metav1.ObjectMeta{
651+
Annotations: map[string]string{
652+
"olm.operatorframework.io/watch-namespace": "annotation-namespace",
653+
},
654+
},
655+
Spec: ocv1.ClusterExtensionSpec{
656+
Config: &ocv1.ClusterExtensionConfig{
657+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
658+
Inline: &apiextensionsv1.JSON{
659+
Raw: []byte(`{"watchNamespace":"watch-namespace"}`),
660+
},
661+
},
662+
},
663+
})
664+
require.NoError(t, err)
665+
require.Equal(t, applier.BundleConfig{
666+
WatchNamespace: "annotation-namespace",
667+
}, cfg)
668+
}
669+
670+
func Test_GetBundleConfig_ClusterExtensionConfigSupport_Enabled(t *testing.T) {
671+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ClusterExtensionConfigSupport, true)
672+
cfg, err := applier.GetBundleConfig(&ocv1.ClusterExtension{
673+
ObjectMeta: metav1.ObjectMeta{
674+
Annotations: map[string]string{
675+
"olm.operatorframework.io/watch-namespace": "annotation-namespace",
676+
},
677+
},
678+
Spec: ocv1.ClusterExtensionSpec{
679+
Config: &ocv1.ClusterExtensionConfig{
680+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
681+
Inline: &apiextensionsv1.JSON{
682+
Raw: []byte(`{"watchNamespace":"config-namespace"}`),
683+
},
684+
},
685+
},
686+
})
687+
require.NoError(t, err)
688+
require.Equal(t, applier.BundleConfig{
689+
WatchNamespace: "config-namespace",
690+
}, cfg)
691+
}
692+
693+
func Test_GetBundleConfig_ClusterExtensionConfigSupport_Errors(t *testing.T) {
694+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ClusterExtensionConfigSupport, true)
695+
cfg, err := applier.GetBundleConfig(&ocv1.ClusterExtension{
696+
ObjectMeta: metav1.ObjectMeta{
697+
Annotations: map[string]string{
698+
"olm.operatorframework.io/watch-namespace": "annotation-namespace",
699+
},
700+
},
701+
Spec: ocv1.ClusterExtensionSpec{
702+
Config: &ocv1.ClusterExtensionConfig{
703+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
704+
Inline: &apiextensionsv1.JSON{
705+
Raw: []byte(`this is not a json`),
706+
},
707+
},
708+
},
709+
})
710+
require.Error(t, err)
711+
require.Equal(t, applier.BundleConfig{}, cfg)
712+
}
713+
714+
func Test_GetBundleConfig_ClusterExtensionConfigSupport_And_SingleOwnNamespaceInstallSupport_Enabled(t *testing.T) {
715+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.SingleOwnNamespaceInstallSupport, true)
716+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ClusterExtensionConfigSupport, true)
717+
718+
for _, tt := range []struct {
719+
name string
720+
ce *ocv1.ClusterExtension
721+
expectedConfig applier.BundleConfig
722+
}{
723+
{
724+
name: "take annotation value if config is undefined",
725+
ce: &ocv1.ClusterExtension{
726+
ObjectMeta: metav1.ObjectMeta{
727+
Annotations: map[string]string{
728+
"olm.operatorframework.io/watch-namespace": "annotation-namespace",
729+
},
730+
},
731+
},
732+
expectedConfig: applier.BundleConfig{
733+
WatchNamespace: "annotation-namespace",
734+
},
735+
}, {
736+
name: "take config value if config is defined",
737+
ce: &ocv1.ClusterExtension{
738+
ObjectMeta: metav1.ObjectMeta{
739+
Annotations: map[string]string{
740+
"olm.operatorframework.io/watch-namespace": "annotation-namespace",
741+
},
742+
},
743+
Spec: ocv1.ClusterExtensionSpec{
744+
Config: &ocv1.ClusterExtensionConfig{
745+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
746+
Inline: &apiextensionsv1.JSON{
747+
Raw: []byte(`{"watchNamespace":"config-namespace"}`),
748+
},
749+
},
750+
},
751+
},
752+
expectedConfig: applier.BundleConfig{
753+
WatchNamespace: "config-namespace",
754+
},
755+
}, {
756+
name: "take config value if config is defined but empty",
757+
ce: &ocv1.ClusterExtension{
758+
ObjectMeta: metav1.ObjectMeta{
759+
Annotations: map[string]string{
760+
"olm.operatorframework.io/watch-namespace": "annotation-namespace",
761+
},
762+
},
763+
Spec: ocv1.ClusterExtensionSpec{
764+
Config: &ocv1.ClusterExtensionConfig{
765+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
766+
Inline: &apiextensionsv1.JSON{
767+
Raw: []byte(`{}`),
768+
},
769+
},
770+
},
771+
},
772+
expectedConfig: applier.BundleConfig{
773+
WatchNamespace: "",
774+
},
775+
},
776+
} {
777+
t.Run(tt.name, func(t *testing.T) {
778+
cfg, err := applier.GetBundleConfig(tt.ce)
779+
require.NoError(t, err)
780+
require.Equal(t, tt.expectedConfig, cfg)
781+
})
782+
}
783+
}
784+
624785
type fakeBundleToHelmChartConverter struct {
625786
fn func(source.BundleSource, string, string) (*chart.Chart, error)
626787
}

0 commit comments

Comments
 (0)