Skip to content

Commit 1b4058a

Browse files
Per Goncalves da Silvaperdasilva
authored andcommitted
Get extension watch namespace from annotation
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 746f8b4 commit 1b4058a

File tree

3 files changed

+120
-2
lines changed

3 files changed

+120
-2
lines changed

internal/operator-controller/applier/helm.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"helm.sh/helm/v3/pkg/postrender"
1616
"helm.sh/helm/v3/pkg/release"
1717
"helm.sh/helm/v3/pkg/storage/driver"
18-
corev1 "k8s.io/api/core/v1"
1918
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2019
apimachyaml "k8s.io/apimachinery/pkg/util/yaml"
2120
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -79,7 +78,11 @@ func shouldSkipPreflight(ctx context.Context, preflight Preflight, ext *ocv1.Clu
7978
}
8079

8180
func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExtension, objectLabels map[string]string, storageLabels map[string]string) ([]client.Object, string, error) {
82-
chrt, err := convert.RegistryV1ToHelmChart(ctx, contentFS, ext.Spec.Namespace, []string{corev1.NamespaceAll})
81+
watchNamespace, err := GetWatchNamespace(ext)
82+
if err != nil {
83+
return nil, "", err
84+
}
85+
chrt, err := convert.RegistryV1ToHelmChart(ctx, contentFS, ext.Spec.Namespace, []string{watchNamespace})
8386
if err != nil {
8487
return nil, "", err
8588
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package applier
2+
3+
import (
4+
"fmt"
5+
6+
corev1 "k8s.io/api/core/v1"
7+
"k8s.io/apimachinery/pkg/util/validation"
8+
9+
ocv1 "github.com/operator-framework/operator-controller/api/v1"
10+
"github.com/operator-framework/operator-controller/internal/operator-controller/features"
11+
)
12+
13+
const (
14+
AnnotationClusterExtensionWatchNamespace = "olm.operatorframework.io/watch-namespace"
15+
)
16+
17+
// GetWatchNamespace determines the watch namespace the ClusterExtension should use
18+
// Note: this is a temporary artifice to enable gated use of single/own namespace install modes
19+
// for registry+v1 bundles. This will go away once the ClusterExtension API is updated to include
20+
// (opaque) runtime configuration.
21+
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
29+
}
30+
}
31+
return corev1.NamespaceAll, nil
32+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package applier_test
2+
3+
import (
4+
"github.com/operator-framework/operator-controller/internal/operator-controller/applier"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
corev1 "k8s.io/api/core/v1"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
featuregatetesting "k8s.io/component-base/featuregate/testing"
11+
12+
v1 "github.com/operator-framework/operator-controller/api/v1"
13+
"github.com/operator-framework/operator-controller/internal/operator-controller/features"
14+
)
15+
16+
func TestGetWatchNamespace(t *testing.T) {
17+
featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.SingleOwnNamespaceInstallSupport, true)
18+
19+
for _, tt := range []struct {
20+
name string
21+
want string
22+
csv *v1.ClusterExtension
23+
expectError bool
24+
}{
25+
{
26+
name: "cluster extension does not have watch namespace annotation",
27+
want: corev1.NamespaceAll,
28+
csv: &v1.ClusterExtension{
29+
ObjectMeta: metav1.ObjectMeta{
30+
Name: "extension",
31+
Annotations: nil,
32+
},
33+
Spec: v1.ClusterExtensionSpec{},
34+
},
35+
expectError: false,
36+
}, {
37+
name: "cluster extension has valid namespace annotation",
38+
want: "watch-namespace",
39+
csv: &v1.ClusterExtension{
40+
ObjectMeta: metav1.ObjectMeta{
41+
Name: "extension",
42+
Annotations: map[string]string{
43+
"olm.operatorframework.io/watch-namespace": "watch-namespace",
44+
},
45+
},
46+
Spec: v1.ClusterExtensionSpec{},
47+
},
48+
expectError: false,
49+
}, {
50+
name: "cluster extension has invalid namespace annotation: multiple watch namespaces",
51+
want: "",
52+
csv: &v1.ClusterExtension{
53+
ObjectMeta: metav1.ObjectMeta{
54+
Name: "extension",
55+
Annotations: map[string]string{
56+
"olm.operatorframework.io/watch-namespace": "watch-namespace,watch-namespace2,watch-namespace3",
57+
},
58+
},
59+
Spec: v1.ClusterExtensionSpec{},
60+
},
61+
expectError: true,
62+
}, {
63+
name: "cluster extension has invalid namespace annotation: invalid name",
64+
want: "",
65+
csv: &v1.ClusterExtension{
66+
ObjectMeta: metav1.ObjectMeta{
67+
Name: "extension",
68+
Annotations: map[string]string{
69+
"olm.operatorframework.io/watch-namespace": "watch-namespace-",
70+
},
71+
},
72+
Spec: v1.ClusterExtensionSpec{},
73+
},
74+
expectError: true,
75+
},
76+
} {
77+
t.Run(tt.name, func(t *testing.T) {
78+
got, err := applier.GetWatchNamespace(tt.csv)
79+
require.Equal(t, tt.want, got)
80+
require.Equal(t, tt.expectError, err != nil)
81+
})
82+
}
83+
}

0 commit comments

Comments
 (0)