Skip to content

Commit fbd2e65

Browse files
perdasilvaPer Goncalves da Silva
andauthored
Fix install mode support check (#2238)
Signed-off-by: Per Goncalves da Silva <[email protected]> Co-authored-by: Per Goncalves da Silva <[email protected]>
1 parent 5f37a67 commit fbd2e65

File tree

3 files changed

+112
-20
lines changed

3 files changed

+112
-20
lines changed

cmd/operator-controller/main.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,9 +655,10 @@ func setupHelm(
655655
ActionClientGetter: acg,
656656
Preflights: preflights,
657657
HelmChartProvider: &applier.RegistryV1HelmChartProvider{
658-
BundleRenderer: registryv1.Renderer,
659-
CertificateProvider: certProvider,
660-
IsWebhookSupportEnabled: certProvider != nil,
658+
BundleRenderer: registryv1.Renderer,
659+
CertificateProvider: certProvider,
660+
IsWebhookSupportEnabled: certProvider != nil,
661+
IsSingleOwnNamespaceEnabled: features.OperatorControllerFeatureGate.Enabled(features.SingleOwnNamespaceInstallSupport),
661662
},
662663
HelmReleaseToObjectsConverter: &applier.HelmReleaseToObjectsConverter{},
663664
PreAuthorizer: preAuth,

internal/operator-controller/applier/provider.go

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@ import (
66
"fmt"
77

88
"helm.sh/helm/v3/pkg/chart"
9+
"k8s.io/apimachinery/pkg/util/sets"
10+
11+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
912

1013
ocv1 "github.com/operator-framework/operator-controller/api/v1"
1114
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/bundle/source"
1215
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render"
1316
)
1417

1518
type RegistryV1HelmChartProvider struct {
16-
BundleRenderer render.BundleRenderer
17-
CertificateProvider render.CertificateProvider
18-
IsWebhookSupportEnabled bool
19+
BundleRenderer render.BundleRenderer
20+
CertificateProvider render.CertificateProvider
21+
IsWebhookSupportEnabled bool
22+
IsSingleOwnNamespaceEnabled bool
1923
}
2024

2125
func (r *RegistryV1HelmChartProvider) Get(bundle source.BundleSource, ext *ocv1.ClusterExtension) (*chart.Chart, error) {
@@ -24,18 +28,6 @@ func (r *RegistryV1HelmChartProvider) Get(bundle source.BundleSource, ext *ocv1.
2428
return nil, err
2529
}
2630

27-
watchNamespace, err := GetWatchNamespace(ext)
28-
if err != nil {
29-
return nil, err
30-
}
31-
32-
opts := []render.Option{
33-
render.WithCertificateProvider(r.CertificateProvider),
34-
}
35-
if watchNamespace != "" {
36-
opts = append(opts, render.WithTargetNamespaces(watchNamespace))
37-
}
38-
3931
if len(rv1.CSV.Spec.APIServiceDefinitions.Owned) > 0 {
4032
return nil, fmt.Errorf("unsupported bundle: apiServiceDefintions are not supported")
4133
}
@@ -48,8 +40,35 @@ func (r *RegistryV1HelmChartProvider) Get(bundle source.BundleSource, ext *ocv1.
4840
}
4941
}
5042

51-
if r.CertificateProvider == nil && len(rv1.CSV.Spec.WebhookDefinitions) > 0 {
52-
return nil, fmt.Errorf("unsupported bundle: webhookDefinitions are not supported")
43+
installModes := sets.New(rv1.CSV.Spec.InstallModes...)
44+
if !r.IsSingleOwnNamespaceEnabled && !installModes.Has(v1alpha1.InstallMode{Type: v1alpha1.InstallModeTypeAllNamespaces, Supported: true}) {
45+
return nil, fmt.Errorf("unsupported bundle: bundle does not support AllNamespaces install mode")
46+
}
47+
48+
if !installModes.HasAny(
49+
v1alpha1.InstallMode{Type: v1alpha1.InstallModeTypeAllNamespaces, Supported: true},
50+
v1alpha1.InstallMode{Type: v1alpha1.InstallModeTypeSingleNamespace, Supported: true},
51+
v1alpha1.InstallMode{Type: v1alpha1.InstallModeTypeOwnNamespace, Supported: true},
52+
) {
53+
return nil, fmt.Errorf("unsupported bundle: bundle must support at least one of [AllNamespaces SingleNamespace OwnNamespace] install modes")
54+
}
55+
56+
opts := []render.Option{
57+
render.WithCertificateProvider(r.CertificateProvider),
58+
}
59+
60+
// TODO: in a follow up PR we'll split this into two components:
61+
// 1. takes a bundle + cluster extension => manifests
62+
// 2. takes a bundle + cluster extension => chart (which will use the component in 1. under the hood)
63+
// GetWatchNamespace will move under the component in 1. and also be reused by the component that
64+
// takes bundle + cluster extension => revision
65+
watchNamespace, err := GetWatchNamespace(ext)
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
if watchNamespace != "" {
71+
opts = append(opts, render.WithTargetNamespaces(watchNamespace))
5372
}
5473

5574
objs, err := r.BundleRenderer.Render(rv1, ext.Spec.Namespace, opts...)

internal/operator-controller/applier/provider_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,78 @@ func Test_RegistryV1HelmChartProvider_Get_NoAPIServiceDefinitions(t *testing.T)
8585
require.Contains(t, err.Error(), "unsupported bundle: apiServiceDefintions are not supported")
8686
}
8787

88+
func Test_RegistryV1HelmChartProvider_Get_SingleOwnNamespace(t *testing.T) {
89+
t.Run("rejects bundles without AllNamespaces install mode support if SingleOwnNamespace is not enabled", func(t *testing.T) {
90+
provider := applier.RegistryV1HelmChartProvider{}
91+
92+
b := source.FromBundle(
93+
bundle.RegistryV1{
94+
CSV: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeOwnNamespace)),
95+
},
96+
)
97+
98+
ext := &ocv1.ClusterExtension{
99+
Spec: ocv1.ClusterExtensionSpec{
100+
Namespace: "install-namespace",
101+
},
102+
}
103+
104+
_, err := provider.Get(b, ext)
105+
require.Error(t, err)
106+
require.Contains(t, err.Error(), "unsupported bundle: bundle does not support AllNamespaces install mode")
107+
})
108+
t.Run("accepts bundles with SingleNamespace install mode support if SingleOwnNamespace is enabled", func(t *testing.T) {
109+
// TODO: this will be removed in a follow-up PR that will refactor GetWatchNamespace's location
110+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.SingleOwnNamespaceInstallSupport, true)
111+
provider := applier.RegistryV1HelmChartProvider{
112+
IsSingleOwnNamespaceEnabled: true,
113+
}
114+
115+
b := source.FromBundle(
116+
bundle.RegistryV1{
117+
CSV: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeSingleNamespace)),
118+
},
119+
)
120+
121+
ext := &ocv1.ClusterExtension{
122+
Spec: ocv1.ClusterExtensionSpec{
123+
Namespace: "install-namespace",
124+
Config: &ocv1.ClusterExtensionConfig{
125+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
126+
Inline: &apiextensionsv1.JSON{
127+
Raw: []byte(`{"watchNamespace": "some-namespace"}`),
128+
},
129+
},
130+
},
131+
}
132+
133+
_, err := provider.Get(b, ext)
134+
require.NoError(t, err)
135+
})
136+
t.Run("accepts bundles with OwnNamespace install mode support if SingleOwnNamespace is enabled", func(t *testing.T) {
137+
// TODO: this will be removed in a follow-up PR that will refactor GetWatchNamespace's location
138+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.SingleOwnNamespaceInstallSupport, true)
139+
provider := applier.RegistryV1HelmChartProvider{
140+
IsSingleOwnNamespaceEnabled: true,
141+
}
142+
143+
b := source.FromBundle(
144+
bundle.RegistryV1{
145+
CSV: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeOwnNamespace)),
146+
},
147+
)
148+
149+
ext := &ocv1.ClusterExtension{
150+
Spec: ocv1.ClusterExtensionSpec{
151+
Namespace: "install-namespace",
152+
},
153+
}
154+
155+
_, err := provider.Get(b, ext)
156+
require.NoError(t, err)
157+
})
158+
}
159+
88160
func Test_RegistryV1HelmChartProvider_Get_NoWebhooksWithoutCertProvider(t *testing.T) {
89161
provider := applier.RegistryV1HelmChartProvider{
90162
IsWebhookSupportEnabled: true,

0 commit comments

Comments
 (0)