Skip to content

Commit 93518ff

Browse files
author
Per Goncalves da Silva
committed
Update applier to take watchNamespace configuration from the extension
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 211786d commit 93518ff

File tree

3 files changed

+143
-34
lines changed

3 files changed

+143
-34
lines changed

internal/operator-controller/applier/helm_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package applier_test
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"io"
78
"os"
89
"testing"
@@ -16,6 +17,7 @@ import (
1617
"helm.sh/helm/v3/pkg/storage/driver"
1718
corev1 "k8s.io/api/core/v1"
1819
rbacv1 "k8s.io/api/rbac/v1"
20+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1921
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2022
featuregatetesting "k8s.io/component-base/featuregate/testing"
2123
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -567,8 +569,13 @@ func TestApply_InstallationWithSingleOwnNamespaceInstallSupportEnabled(t *testin
567569
testExt := &ocv1.ClusterExtension{
568570
ObjectMeta: metav1.ObjectMeta{
569571
Name: "testExt",
570-
Annotations: map[string]string{
571-
applier.AnnotationClusterExtensionWatchNamespace: expectedWatchNamespace,
572+
},
573+
Spec: ocv1.ClusterExtensionSpec{
574+
Config: &ocv1.ClusterExtensionConfig{
575+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
576+
Inline: &apiextensionsv1.JSON{
577+
Raw: []byte(fmt.Sprintf(`{"watchNamespace":"%s"}`, expectedWatchNamespace)),
578+
},
572579
},
573580
},
574581
}
Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package applier
22

33
import (
4+
"encoding/json"
45
"fmt"
56

6-
corev1 "k8s.io/api/core/v1"
77
"k8s.io/apimachinery/pkg/util/validation"
88

99
ocv1 "github.com/operator-framework/operator-controller/api/v1"
@@ -19,14 +19,28 @@ const (
1919
// for registry+v1 bundles. This will go away once the ClusterExtension API is updated to include
2020
// (opaque) runtime configuration.
2121
func GetWatchNamespace(ext *ocv1.ClusterExtension) (string, error) {
22-
if features.OperatorControllerFeatureGate.Enabled(features.SingleOwnNamespaceInstallSupport) {
23-
if ext != nil && ext.Annotations[AnnotationClusterExtensionWatchNamespace] != "" {
24-
watchNamespace := ext.Annotations[AnnotationClusterExtensionWatchNamespace]
25-
if errs := validation.IsDNS1123Subdomain(watchNamespace); len(errs) > 0 {
26-
return "", fmt.Errorf("invalid watch namespace '%s': namespace must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character", watchNamespace)
27-
}
28-
return ext.Annotations[AnnotationClusterExtensionWatchNamespace], nil
22+
if !features.OperatorControllerFeatureGate.Enabled(features.SingleOwnNamespaceInstallSupport) {
23+
return "", nil
24+
}
25+
26+
var watchNamespace string
27+
if ext.Spec.Config != nil && ext.Spec.Config.Inline != nil {
28+
cfg := struct {
29+
WatchNamespace string `json:"watchNamespace"`
30+
}{}
31+
if err := json.Unmarshal(ext.Spec.Config.Inline.Raw, &cfg); err != nil {
32+
return "", fmt.Errorf("invalid bundle configuration: %w", err)
2933
}
34+
watchNamespace = cfg.WatchNamespace
35+
} else if _, ok := ext.Annotations[AnnotationClusterExtensionWatchNamespace]; ok {
36+
watchNamespace = ext.Annotations[AnnotationClusterExtensionWatchNamespace]
37+
} else {
38+
return "", nil
3039
}
31-
return corev1.NamespaceAll, nil
40+
41+
if errs := validation.IsDNS1123Subdomain(watchNamespace); len(errs) > 0 {
42+
return "", fmt.Errorf("invalid watch namespace '%s': namespace must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character", watchNamespace)
43+
}
44+
45+
return watchNamespace, nil
3246
}

internal/operator-controller/applier/watchnamespace_test.go

Lines changed: 111 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,31 @@ import (
55

66
"github.com/stretchr/testify/require"
77
corev1 "k8s.io/api/core/v1"
8+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
featuregatetesting "k8s.io/component-base/featuregate/testing"
1011

11-
v1 "github.com/operator-framework/operator-controller/api/v1"
12+
ocv1 "github.com/operator-framework/operator-controller/api/v1"
1213
"github.com/operator-framework/operator-controller/internal/operator-controller/applier"
1314
"github.com/operator-framework/operator-controller/internal/operator-controller/features"
1415
)
1516

1617
func TestGetWatchNamespacesWhenFeatureGateIsDisabled(t *testing.T) {
17-
watchNamespace, err := applier.GetWatchNamespace(&v1.ClusterExtension{
18+
watchNamespace, err := applier.GetWatchNamespace(&ocv1.ClusterExtension{
1819
ObjectMeta: metav1.ObjectMeta{
1920
Name: "extension",
20-
Annotations: map[string]string{
21-
"olm.operatorframework.io/watch-namespace": "watch-namespace",
21+
},
22+
Spec: ocv1.ClusterExtensionSpec{
23+
Config: &ocv1.ClusterExtensionConfig{
24+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
25+
Inline: &apiextensionsv1.JSON{
26+
Raw: []byte(`{"watchNamespace":"watch-namespace"}`),
27+
},
2228
},
2329
},
24-
Spec: v1.ClusterExtensionSpec{},
2530
})
2631
require.NoError(t, err)
27-
t.Log("Check watchNamespace is '' even if the annotation is set")
32+
t.Log("Check watchNamespace is '' even if the configuration is set")
2833
require.Equal(t, corev1.NamespaceAll, watchNamespace)
2934
}
3035

@@ -34,57 +39,140 @@ func TestGetWatchNamespace(t *testing.T) {
3439
for _, tt := range []struct {
3540
name string
3641
want string
37-
csv *v1.ClusterExtension
42+
csv *ocv1.ClusterExtension
3843
expectError bool
3944
}{
4045
{
41-
name: "cluster extension does not have watch namespace annotation",
46+
name: "cluster extension does not configure a watch namespace",
4247
want: corev1.NamespaceAll,
43-
csv: &v1.ClusterExtension{
48+
csv: &ocv1.ClusterExtension{
4449
ObjectMeta: metav1.ObjectMeta{
4550
Name: "extension",
4651
Annotations: nil,
4752
},
48-
Spec: v1.ClusterExtensionSpec{},
53+
Spec: ocv1.ClusterExtensionSpec{},
54+
},
55+
expectError: false,
56+
}, {
57+
name: "cluster extension configures a watch namespace",
58+
want: "watch-namespace",
59+
csv: &ocv1.ClusterExtension{
60+
ObjectMeta: metav1.ObjectMeta{
61+
Name: "extension",
62+
},
63+
Spec: ocv1.ClusterExtensionSpec{
64+
Config: &ocv1.ClusterExtensionConfig{
65+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
66+
Inline: &apiextensionsv1.JSON{
67+
Raw: []byte(`{"watchNamespace":"watch-namespace"}`),
68+
},
69+
},
70+
},
4971
},
5072
expectError: false,
5173
}, {
52-
name: "cluster extension has valid namespace annotation",
74+
name: "cluster extension configures a watch namespace through annotation",
5375
want: "watch-namespace",
54-
csv: &v1.ClusterExtension{
76+
csv: &ocv1.ClusterExtension{
5577
ObjectMeta: metav1.ObjectMeta{
5678
Name: "extension",
5779
Annotations: map[string]string{
5880
"olm.operatorframework.io/watch-namespace": "watch-namespace",
5981
},
6082
},
61-
Spec: v1.ClusterExtensionSpec{},
6283
},
6384
expectError: false,
6485
}, {
65-
name: "cluster extension has invalid namespace annotation: multiple watch namespaces",
66-
want: "",
67-
csv: &v1.ClusterExtension{
86+
name: "cluster extension configures a watch namespace through annotation with invalid ns",
87+
csv: &ocv1.ClusterExtension{
6888
ObjectMeta: metav1.ObjectMeta{
6989
Name: "extension",
7090
Annotations: map[string]string{
71-
"olm.operatorframework.io/watch-namespace": "watch-namespace,watch-namespace2,watch-namespace3",
91+
"olm.operatorframework.io/watch-namespace": "watch-namespace-",
7292
},
7393
},
74-
Spec: v1.ClusterExtensionSpec{},
7594
},
7695
expectError: true,
7796
}, {
78-
name: "cluster extension has invalid namespace annotation: invalid name",
79-
want: "",
80-
csv: &v1.ClusterExtension{
97+
name: "cluster extension configures a watch namespace through annotation with empty ns",
98+
csv: &ocv1.ClusterExtension{
8199
ObjectMeta: metav1.ObjectMeta{
82100
Name: "extension",
83101
Annotations: map[string]string{
84-
"olm.operatorframework.io/watch-namespace": "watch-namespace-",
102+
"olm.operatorframework.io/watch-namespace": "",
103+
},
104+
},
105+
},
106+
expectError: true,
107+
}, {
108+
name: "cluster extension configures a watch namespace through annotation and config (take config)",
109+
want: "watch-namespace",
110+
csv: &ocv1.ClusterExtension{
111+
ObjectMeta: metav1.ObjectMeta{
112+
Name: "extension",
113+
Annotations: map[string]string{
114+
"olm.operatorframework.io/watch-namespace": "dont-use-this-watch-namespace",
115+
},
116+
},
117+
Spec: ocv1.ClusterExtensionSpec{
118+
Config: &ocv1.ClusterExtensionConfig{
119+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
120+
Inline: &apiextensionsv1.JSON{
121+
Raw: []byte(`{"watchNamespace":"watch-namespace"}`),
122+
},
123+
},
124+
},
125+
},
126+
expectError: false,
127+
}, {
128+
name: "cluster extension configures an invalid watchNamespace: multiple watch namespaces",
129+
want: "",
130+
csv: &ocv1.ClusterExtension{
131+
ObjectMeta: metav1.ObjectMeta{
132+
Name: "extension",
133+
},
134+
Spec: ocv1.ClusterExtensionSpec{
135+
Config: &ocv1.ClusterExtensionConfig{
136+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
137+
Inline: &apiextensionsv1.JSON{
138+
Raw: []byte(`{"watchNamespace":"watch-namespace,watch-namespace2,watch-namespace3"}`),
139+
},
140+
},
141+
},
142+
},
143+
expectError: true,
144+
}, {
145+
name: "cluster extension configures an invalid watchNamespace: invalid name",
146+
want: "",
147+
csv: &ocv1.ClusterExtension{
148+
ObjectMeta: metav1.ObjectMeta{
149+
Name: "extension",
150+
},
151+
Spec: ocv1.ClusterExtensionSpec{
152+
Config: &ocv1.ClusterExtensionConfig{
153+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
154+
Inline: &apiextensionsv1.JSON{
155+
Raw: []byte(`{"watchNamespace":"watch-namespace-"}`),
156+
},
157+
},
158+
},
159+
},
160+
expectError: true,
161+
}, {
162+
name: "cluster extension configures an invalid watchNamespace: invalid json",
163+
want: "",
164+
csv: &ocv1.ClusterExtension{
165+
ObjectMeta: metav1.ObjectMeta{
166+
Name: "extension",
167+
},
168+
Spec: ocv1.ClusterExtensionSpec{
169+
Config: &ocv1.ClusterExtensionConfig{
170+
ConfigType: ocv1.ClusterExtensionConfigTypeInline,
171+
Inline: &apiextensionsv1.JSON{
172+
Raw: []byte(`invalid json`),
173+
},
85174
},
86175
},
87-
Spec: v1.ClusterExtensionSpec{},
88176
},
89177
expectError: true,
90178
},

0 commit comments

Comments
 (0)