Skip to content

Commit 14e1789

Browse files
author
Per Goncalves da Silva
committed
Compute target namespace defaults
Signed-off-by: Per Goncalves da Silva <pegoncal@redhat.com>
1 parent 182a0a6 commit 14e1789

File tree

2 files changed

+161
-30
lines changed

2 files changed

+161
-30
lines changed

internal/operator-controller/rukpak/render/render.go

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"errors"
55
"fmt"
66

7-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7+
corev1 "k8s.io/api/core/v1"
88
"k8s.io/apimachinery/pkg/util/sets"
99
"sigs.k8s.io/controller-runtime/pkg/client"
1010

@@ -74,9 +74,6 @@ func (o *Options) apply(opts ...Option) *Options {
7474

7575
func (o *Options) validate(rv1 *bundle.RegistryV1) (*Options, []error) {
7676
var errs []error
77-
if len(o.TargetNamespaces) == 0 {
78-
errs = append(errs, errors.New("at least one target namespace must be specified"))
79-
}
8077
if o.UniqueNameGenerator == nil {
8178
errs = append(errs, errors.New("unique name generator must be specified"))
8279
}
@@ -121,7 +118,7 @@ func (r BundleRenderer) Render(rv1 bundle.RegistryV1, installNamespace string, o
121118
genOpts, errs := (&Options{
122119
// default options
123120
InstallNamespace: installNamespace,
124-
TargetNamespaces: []string{metav1.NamespaceAll},
121+
TargetNamespaces: defaultTargetNamespacesForBundle(&rv1, installNamespace),
125122
UniqueNameGenerator: DefaultUniqueNameGenerator,
126123
CertificateProvider: nil,
127124
}).apply(opts...).validate(&rv1)
@@ -147,31 +144,52 @@ func DefaultUniqueNameGenerator(base string, o interface{}) (string, error) {
147144
}
148145

149146
func validateTargetNamespaces(rv1 *bundle.RegistryV1, installNamespace string, targetNamespaces []string) error {
150-
supportedInstallModes := sets.New[string]()
151-
for _, im := range rv1.CSV.Spec.InstallModes {
152-
if im.Supported {
153-
supportedInstallModes.Insert(string(im.Type))
154-
}
155-
}
147+
supportedInstallModes := getSupportedInstallModesSet(rv1)
156148

157149
set := sets.New[string](targetNamespaces...)
158150
switch {
159-
case set.Len() == 0 || (set.Len() == 1 && set.Has("")):
160-
if supportedInstallModes.Has(string(v1alpha1.InstallModeTypeAllNamespaces)) {
151+
case set.Len() == 0:
152+
return errors.New("at least one target namespace must be specified")
153+
case set.Len() == 1 && set.Has(""):
154+
if supportedInstallModes.Has(v1alpha1.InstallModeTypeAllNamespaces) {
161155
return nil
162156
}
163157
return fmt.Errorf("supported install modes %v do not support targeting all namespaces", sets.List(supportedInstallModes))
164158
case set.Len() == 1 && !set.Has(""):
165-
if supportedInstallModes.Has(string(v1alpha1.InstallModeTypeSingleNamespace)) {
159+
if supportedInstallModes.Has(v1alpha1.InstallModeTypeSingleNamespace) {
166160
return nil
167161
}
168-
if supportedInstallModes.Has(string(v1alpha1.InstallModeTypeOwnNamespace)) && targetNamespaces[0] == installNamespace {
162+
if supportedInstallModes.Has(v1alpha1.InstallModeTypeOwnNamespace) && targetNamespaces[0] == installNamespace {
169163
return nil
170164
}
171165
default:
172-
if supportedInstallModes.Has(string(v1alpha1.InstallModeTypeMultiNamespace)) && !set.Has("") {
166+
if supportedInstallModes.Has(v1alpha1.InstallModeTypeMultiNamespace) && !set.Has("") {
173167
return nil
174168
}
175169
}
176-
return fmt.Errorf("supported install modes %v do not support target namespaces %v", sets.List[string](supportedInstallModes), targetNamespaces)
170+
return fmt.Errorf("supported install modes %v do not support target namespaces %v", sets.List[v1alpha1.InstallModeType](supportedInstallModes), targetNamespaces)
171+
}
172+
173+
func defaultTargetNamespacesForBundle(rv1 *bundle.RegistryV1, installNamespace string) []string {
174+
supportedInstallModes := getSupportedInstallModesSet(rv1)
175+
176+
if supportedInstallModes.Has(v1alpha1.InstallModeTypeAllNamespaces) {
177+
return []string{corev1.NamespaceAll}
178+
}
179+
180+
if supportedInstallModes.Has(v1alpha1.InstallModeTypeOwnNamespace) {
181+
return []string{installNamespace}
182+
}
183+
184+
return nil
185+
}
186+
187+
func getSupportedInstallModesSet(rv1 *bundle.RegistryV1) sets.Set[v1alpha1.InstallModeType] {
188+
supportedInstallModes := sets.New[v1alpha1.InstallModeType]()
189+
for _, im := range rv1.CSV.Spec.InstallModes {
190+
if im.Supported {
191+
supportedInstallModes.Insert(im.Type)
192+
}
193+
}
194+
return supportedInstallModes
177195
}

internal/operator-controller/rukpak/render/render_test.go

Lines changed: 126 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,136 @@ func Test_BundleRenderer_ValidatesBundle(t *testing.T) {
4242
require.Contains(t, err.Error(), "this bundle is invalid")
4343
}
4444

45-
func Test_BundleRenderer_CreatesCorrectDefaultOptions(t *testing.T) {
46-
expectedInstallNamespace := "install-namespace"
47-
expectedTargetNamespaces := []string{""}
48-
expectedUniqueNameGenerator := render.DefaultUniqueNameGenerator
45+
func Test_BundleRenderer_CreatesCorrectRenderOptions_WithDefaults(t *testing.T) {
46+
const (
47+
expectedInstallNamespace = "install-namespace"
48+
)
4949

50-
renderer := render.BundleRenderer{
51-
ResourceGenerators: []render.ResourceGenerator{
52-
func(rv1 *bundle.RegistryV1, opts render.Options) ([]client.Object, error) {
50+
for _, tc := range []struct {
51+
name string
52+
csv v1alpha1.ClusterServiceVersion
53+
validate func(t *testing.T, opts render.Options)
54+
expectedErrMsgFragment string
55+
}{
56+
{
57+
name: "sets install-namespace correctly",
58+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces)),
59+
validate: func(t *testing.T, opts render.Options) {
5360
require.Equal(t, expectedInstallNamespace, opts.InstallNamespace)
54-
require.Equal(t, expectedTargetNamespaces, opts.TargetNamespaces)
55-
require.Equal(t, reflect.ValueOf(expectedUniqueNameGenerator).Pointer(), reflect.ValueOf(render.DefaultUniqueNameGenerator).Pointer(), "options has unexpected default unique name generator")
56-
return nil, nil
5761
},
62+
}, {
63+
name: "uses DefaultUniqueNameGenerator by default",
64+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces)),
65+
validate: func(t *testing.T, opts render.Options) {
66+
require.Equal(t, reflect.ValueOf(render.DefaultUniqueNameGenerator).Pointer(), reflect.ValueOf(opts.UniqueNameGenerator).Pointer(), "options has unexpected default unique name generator")
67+
},
68+
}, {
69+
name: "sets target namespaces to [corev1.NamespaceAll] by default if bundle supports install modes [AllNamespaces]",
70+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces)),
71+
validate: func(t *testing.T, opts render.Options) {
72+
require.Equal(t, []string{corev1.NamespaceAll}, opts.TargetNamespaces)
73+
},
74+
}, {
75+
name: "sets target namespaces to [corev1.NamespaceAll] by default if bundle supports install modes [AllNamespaces, SingleNamespace]",
76+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces, v1alpha1.InstallModeTypeSingleNamespace)),
77+
validate: func(t *testing.T, opts render.Options) {
78+
require.Equal(t, []string{corev1.NamespaceAll}, opts.TargetNamespaces)
79+
},
80+
}, {
81+
name: "sets target namespaces to [corev1.NamespaceAll] by default if bundle supports install modes [AllNamespaces, OwnNamespace]",
82+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces, v1alpha1.InstallModeTypeOwnNamespace)),
83+
validate: func(t *testing.T, opts render.Options) {
84+
require.Equal(t, []string{corev1.NamespaceAll}, opts.TargetNamespaces)
85+
},
86+
}, {
87+
name: "sets target namespaces to [corev1.NamespaceAll] by default if bundle supports install modes [AllNamespaces, MultiNamespace]",
88+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces, v1alpha1.InstallModeTypeMultiNamespace)),
89+
validate: func(t *testing.T, opts render.Options) {
90+
require.Equal(t, []string{corev1.NamespaceAll}, opts.TargetNamespaces)
91+
},
92+
}, {
93+
name: "sets target namespaces to [corev1.NamespaceAll] by default if bundle supports install modes [AllNamespaces, OwnNamespace, SingleNamespace]",
94+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces, v1alpha1.InstallModeTypeOwnNamespace, v1alpha1.InstallModeTypeSingleNamespace)),
95+
validate: func(t *testing.T, opts render.Options) {
96+
require.Equal(t, []string{corev1.NamespaceAll}, opts.TargetNamespaces)
97+
},
98+
}, {
99+
name: "sets target namespaces to [corev1.NamespaceAll] by default if bundle supports install modes [AllNamespaces, OwnNamespace, MultiNamespace]",
100+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces, v1alpha1.InstallModeTypeOwnNamespace, v1alpha1.InstallModeTypeMultiNamespace)),
101+
validate: func(t *testing.T, opts render.Options) {
102+
require.Equal(t, []string{corev1.NamespaceAll}, opts.TargetNamespaces)
103+
},
104+
}, {
105+
name: "sets target namespaces to [corev1.NamespaceAll] by default if bundle supports install modes [AllNamespaces, SingleNamespace, MultiNamespace]",
106+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces, v1alpha1.InstallModeTypeSingleNamespace, v1alpha1.InstallModeTypeMultiNamespace)),
107+
validate: func(t *testing.T, opts render.Options) {
108+
require.Equal(t, []string{corev1.NamespaceAll}, opts.TargetNamespaces)
109+
},
110+
}, {
111+
name: "sets target namespaces to [corev1.NamespaceAll] by default if bundle supports install modes [AllNamespaces, SingleNamespace, OwnNamespace, MultiNamespace]",
112+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces, v1alpha1.InstallModeTypeSingleNamespace, v1alpha1.InstallModeTypeOwnNamespace, v1alpha1.InstallModeTypeMultiNamespace)),
113+
validate: func(t *testing.T, opts render.Options) {
114+
require.Equal(t, []string{corev1.NamespaceAll}, opts.TargetNamespaces)
115+
},
116+
}, {
117+
name: "sets target namespaces to [install-namespace] by default if bundle supports install modes [OwnNamespace]",
118+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeOwnNamespace)),
119+
validate: func(t *testing.T, opts render.Options) {
120+
require.Equal(t, []string{expectedInstallNamespace}, opts.TargetNamespaces)
121+
},
122+
}, {
123+
name: "sets target namespaces to [install-namespace] by default if bundle supports install modes [OwnNamespace, SingleNamespace]",
124+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeOwnNamespace, v1alpha1.InstallModeTypeSingleNamespace)),
125+
validate: func(t *testing.T, opts render.Options) {
126+
require.Equal(t, []string{expectedInstallNamespace}, opts.TargetNamespaces)
127+
},
128+
}, {
129+
name: "sets target namespaces to [install-namespace] by default if bundle supports install modes [OwnNamespace, MultiNamespace]",
130+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeOwnNamespace, v1alpha1.InstallModeTypeMultiNamespace)),
131+
validate: func(t *testing.T, opts render.Options) {
132+
require.Equal(t, []string{expectedInstallNamespace}, opts.TargetNamespaces)
133+
},
134+
}, {
135+
name: "sets target namespaces to [install-namespace] by default if bundle supports install modes [OwnNamespace, SingleNamespace, MultiNamespace]",
136+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeOwnNamespace, v1alpha1.InstallModeTypeSingleNamespace, v1alpha1.InstallModeTypeMultiNamespace)),
137+
validate: func(t *testing.T, opts render.Options) {
138+
require.Equal(t, []string{expectedInstallNamespace}, opts.TargetNamespaces)
139+
},
140+
}, {
141+
name: "returns error if target namespaces is not set bundle supports install modes [SingleNamespace]",
142+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeSingleNamespace)),
143+
expectedErrMsgFragment: "at least one target namespace must be specified",
144+
}, {
145+
name: "returns error if target namespaces is not set bundle supports install modes [MultiNamespace]",
146+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeSingleNamespace)),
147+
expectedErrMsgFragment: "at least one target namespace must be specified",
148+
}, {
149+
name: "returns error if target namespaces is not set bundle supports install modes [SingleNamespace, MultiNamespace]",
150+
csv: MakeCSV(WithInstallModeSupportFor(v1alpha1.InstallModeTypeSingleNamespace)),
151+
expectedErrMsgFragment: "at least one target namespace must be specified",
58152
},
59-
}
153+
} {
154+
t.Run(tc.name, func(t *testing.T) {
155+
renderer := render.BundleRenderer{
156+
ResourceGenerators: []render.ResourceGenerator{
157+
func(rv1 *bundle.RegistryV1, opts render.Options) ([]client.Object, error) {
158+
tc.validate(t, opts)
159+
return nil, nil
160+
},
161+
},
162+
}
60163

61-
_, _ = renderer.Render(bundle.RegistryV1{}, expectedInstallNamespace)
164+
_, err := renderer.Render(bundle.RegistryV1{
165+
CSV: tc.csv,
166+
}, expectedInstallNamespace)
167+
if tc.expectedErrMsgFragment == "" {
168+
require.NoError(t, err)
169+
} else {
170+
require.Error(t, err)
171+
require.Contains(t, err.Error(), tc.expectedErrMsgFragment)
172+
}
173+
})
174+
}
62175
}
63176

64177
func Test_BundleRenderer_ValidatesRenderOptions(t *testing.T) {
@@ -76,7 +189,7 @@ func Test_BundleRenderer_ValidatesRenderOptions(t *testing.T) {
76189
opts: []render.Option{
77190
render.WithTargetNamespaces(),
78191
},
79-
err: errors.New("invalid option(s): at least one target namespace must be specified"),
192+
err: errors.New("invalid option(s): invalid target namespaces []: at least one target namespace must be specified"),
80193
}, {
81194
name: "rejects nil unique name generator",
82195
installNamespace: "install-namespace",

0 commit comments

Comments
 (0)