From 9befb90c1496815d5b86109bf3dfd8fb97aa0dae Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Tue, 30 Apr 2024 13:29:27 -0400 Subject: [PATCH] ClusterExtension: add installNamespace, remove watchNamespaces Signed-off-by: Joe Lanford --- api/v1alpha1/clusterextension_types.go | 10 +- api/v1alpha1/zz_generated.deepcopy.go | 7 +- ...peratorframework.io_clusterextensions.yaml | 16 +- go.mod | 8 +- go.sum | 35 ++-- .../clusterextension_admission_test.go | 59 ++++++- .../clusterextension_controller.go | 6 +- .../clusterextension_controller_test.go | 154 +++++++++++------- ...terextension_registryv1_validation_test.go | 6 +- test/e2e/cluster_extension_admission_test.go | 15 +- test/e2e/cluster_extension_install_test.go | 24 ++- .../extension_developer_test.go | 6 +- .../core.rukpak.io_bundledeployments.yaml | 38 +++-- 13 files changed, 244 insertions(+), 140 deletions(-) diff --git a/api/v1alpha1/clusterextension_types.go b/api/v1alpha1/clusterextension_types.go index 0d7f0b83d..cd87db021 100644 --- a/api/v1alpha1/clusterextension_types.go +++ b/api/v1alpha1/clusterextension_types.go @@ -66,11 +66,13 @@ type ClusterExtensionSpec struct { // Defines the policy for how to handle upgrade constraints UpgradeConstraintPolicy UpgradeConstraintPolicy `json:"upgradeConstraintPolicy,omitempty"` - //+kubebuilder:Optional + //+kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + //+kubebuilder:validation:MaxLength:=63 // - // watchNamespaces indicates which namespaces the extension should watch. - // This feature is currently supported only with RegistryV1 bundles. - WatchNamespaces []string `json:"watchNamespaces,omitempty"` + // installNamespace is the namespace where the bundle should be installed. However, note that + // the bundle may contain resources that are cluster-scoped or that are + // installed in a different namespace. This namespace is expected to exist. + InstallNamespace string `json:"installNamespace"` } const ( diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index cef0eb870..bc1276b2f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -45,7 +45,7 @@ func (in *ClusterExtension) DeepCopyInto(out *ClusterExtension) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) } @@ -102,11 +102,6 @@ func (in *ClusterExtensionList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterExtensionSpec) DeepCopyInto(out *ClusterExtensionSpec) { *out = *in - if in.WatchNamespaces != nil { - in, out := &in.WatchNamespaces, &out.WatchNamespaces - *out = make([]string, len(*in)) - copy(*out, *in) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterExtensionSpec. diff --git a/config/crd/bases/olm.operatorframework.io_clusterextensions.yaml b/config/crd/bases/olm.operatorframework.io_clusterextensions.yaml index bafec1096..2b0ebb960 100644 --- a/config/crd/bases/olm.operatorframework.io_clusterextensions.yaml +++ b/config/crd/bases/olm.operatorframework.io_clusterextensions.yaml @@ -44,6 +44,14 @@ spec: maxLength: 48 pattern: ^[a-z0-9]+([\.-][a-z0-9]+)*$ type: string + installNamespace: + description: |- + installNamespace is the namespace where the bundle should be installed. However, note that + the bundle may contain resources that are cluster-scoped or that are + installed in a different namespace. This namespace is expected to exist. + maxLength: 63 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string packageName: maxLength: 48 pattern: ^[a-z0-9]+(-[a-z0-9]+)*$ @@ -66,14 +74,8 @@ spec: maxLength: 64 pattern: ^(\s*(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|[x|X|\*])(\.(0|[1-9]\d*|x|X|\*]))?(\.(0|[1-9]\d*|x|X|\*))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)((?:\s+|,\s*|\s*\|\|\s*)(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|x|X|\*])(\.(0|[1-9]\d*|x|X|\*))?(\.(0|[1-9]\d*|x|X|\*]))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)*$ type: string - watchNamespaces: - description: |- - watchNamespaces indicates which namespaces the extension should watch. - This feature is currently supported only with RegistryV1 bundles. - items: - type: string - type: array required: + - installNamespace - packageName type: object status: diff --git a/go.mod b/go.mod index cdd9525be..e4442fbe7 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/operator-framework/catalogd v0.12.0 github.com/operator-framework/operator-registry v1.40.0 - github.com/operator-framework/rukpak v0.19.0 + github.com/operator-framework/rukpak v0.20.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 github.com/vmware-tanzu/carvel-kapp-controller v0.51.0 @@ -37,7 +37,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect - github.com/go-git/go-git/v5 v5.11.0 // indirect + github.com/go-git/go-git/v5 v5.12.0 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect @@ -62,9 +62,9 @@ require ( github.com/operator-framework/api v0.23.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_golang v1.19.0 // indirect github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/common v0.47.0 // indirect + github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/go.sum b/go.sum index e74f88266..f665c6c2d 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -41,7 +41,8 @@ github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHa github.com/go-openapi/swag v0.22.10 h1:4y86NVn7Z2yYd6pfS4Z+Nyh3aAUL3Nul+LMbhFKy0gA= github.com/go-openapi/swag v0.22.10/go.mod h1:Cnn8BYtRlx6BNE3DPN86f/xkapGIcLWzh3CLEb4C1jI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -61,8 +62,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20230907193218-d3ddc7976beb h1:LCMfzVg3sflxTs4UvuP4D8CkoZnfHLe2qzqgDn/4OHs= -github.com/google/pprof v0.0.0-20230907193218-d3ddc7976beb/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= @@ -95,28 +96,28 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= -github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= -github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= +github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/operator-framework/api v0.23.0 h1:kHymOwcHBpBVujT49SKOCd4EVG7Odwj4wl3NbOR2LLA= github.com/operator-framework/api v0.23.0/go.mod h1:oKcFOz+Xc1UhMi2Pzcp6qsO7wjS4r+yP7EQprQBXrfM= github.com/operator-framework/catalogd v0.12.0 h1:Cww+CyowkfTFugB9ZjUDpKvumh2vPe/TjCUpMHDmVBM= github.com/operator-framework/catalogd v0.12.0/go.mod h1:4lryGtBTVOdqlKR0MaVYnlsSOc7HiagVRVo3J4uIo7E= github.com/operator-framework/operator-registry v1.40.0 h1:CaYNE4F/jzahpC7UCILItaIHmB5/oE0sS066nK+5Glw= github.com/operator-framework/operator-registry v1.40.0/go.mod h1:D2YxapkfRDgjqNTO9d3h3v0DeREbV+8utCLG52zrOy4= -github.com/operator-framework/rukpak v0.19.0 h1:8cW43z4jsvARlsmj2eum5bAsZEvSxqDwfMW3dSq1zq8= -github.com/operator-framework/rukpak v0.19.0/go.mod h1:yRJe6JRwgae4s/tnzEDCsNvdT+t4eDARdtfoJMLYiP4= +github.com/operator-framework/rukpak v0.20.0 h1:BqF1nIlocyYLMmv6CvlbtB9QTwSMrEfTzhA+H3+do3c= +github.com/operator-framework/rukpak v0.20.0/go.mod h1:WAyS3DXZ19pLg/324PEoudWZmaRlYZ6i4j4NV3/T/mI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -195,8 +196,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/controllers/clusterextension_admission_test.go b/internal/controllers/clusterextension_admission_test.go index 28e2bc967..16629c410 100644 --- a/internal/controllers/clusterextension_admission_test.go +++ b/internal/controllers/clusterextension_admission_test.go @@ -2,6 +2,7 @@ package controllers_test import ( "context" + "strings" "testing" "github.com/stretchr/testify/require" @@ -42,7 +43,8 @@ func TestClusterExtensionAdmissionPackageName(t *testing.T) { t.Parallel() cl := newClient(t) err := cl.Create(context.Background(), buildClusterExtension(ocv1alpha1.ClusterExtensionSpec{ - PackageName: tc.pkgName, + PackageName: tc.pkgName, + InstallNamespace: "default", })) if tc.errMsg == "" { require.NoError(t, err, "unexpected error for package name %q: %w", tc.pkgName, err) @@ -129,8 +131,9 @@ func TestClusterExtensionAdmissionVersion(t *testing.T) { t.Parallel() cl := newClient(t) err := cl.Create(context.Background(), buildClusterExtension(ocv1alpha1.ClusterExtensionSpec{ - PackageName: "package", - Version: tc.version, + PackageName: "package", + Version: tc.version, + InstallNamespace: "default", })) if tc.errMsg == "" { require.NoError(t, err, "unexpected error for version %q: %w", tc.version, err) @@ -173,8 +176,9 @@ func TestClusterExtensionAdmissionChannel(t *testing.T) { t.Parallel() cl := newClient(t) err := cl.Create(context.Background(), buildClusterExtension(ocv1alpha1.ClusterExtensionSpec{ - PackageName: "package", - Channel: tc.channelName, + PackageName: "package", + Channel: tc.channelName, + InstallNamespace: "default", })) if tc.errMsg == "" { require.NoError(t, err, "unexpected error for channel %q: %w", tc.channelName, err) @@ -186,6 +190,51 @@ func TestClusterExtensionAdmissionChannel(t *testing.T) { } } +func TestClusterExtensionAdmissionInstallNamespace(t *testing.T) { + tooLongError := "spec.installNamespace: Too long: may not be longer than 63" + regexMismatchError := "spec.installNamespace in body should match" + + testCases := []struct { + name string + installNamespace string + errMsg string + }{ + {"just alphanumeric", "justalphanumberic1", ""}, + {"hypen-separated", "hyphenated-name", ""}, + {"no install namespace", "", regexMismatchError}, + {"dot-separated", "dotted.name", regexMismatchError}, + {"longest valid install namespace", strings.Repeat("x", 63), ""}, + {"too long install namespace name", strings.Repeat("x", 64), tooLongError}, + {"spaces", "spaces spaces", regexMismatchError}, + {"capitalized", "Capitalized", regexMismatchError}, + {"camel case", "camelCase", regexMismatchError}, + {"invalid characters", "many/invalid$characters+in_name", regexMismatchError}, + {"starts with hyphen", "-start-with-hyphen", regexMismatchError}, + {"ends with hyphen", "end-with-hyphen-", regexMismatchError}, + {"starts with period", ".start-with-period", regexMismatchError}, + {"ends with period", "end-with-period.", regexMismatchError}, + } + + t.Parallel() + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + cl := newClient(t) + err := cl.Create(context.Background(), buildClusterExtension(ocv1alpha1.ClusterExtensionSpec{ + PackageName: "package", + InstallNamespace: tc.installNamespace, + })) + if tc.errMsg == "" { + require.NoError(t, err, "unexpected error for installNamespace %q: %w", tc.installNamespace, err) + } else { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errMsg) + } + }) + } +} + func buildClusterExtension(spec ocv1alpha1.ClusterExtensionSpec) *ocv1alpha1.ClusterExtension { return &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{ diff --git a/internal/controllers/clusterextension_controller.go b/internal/controllers/clusterextension_controller.go index b7b38d44d..d42ada45d 100644 --- a/internal/controllers/clusterextension_controller.go +++ b/internal/controllers/clusterextension_controller.go @@ -441,7 +441,7 @@ func (r *ClusterExtensionReconciler) GenerateExpectedBundleDeployment(o ocv1alph // identical to "kubectl apply -f" spec := map[string]interface{}{ - // TODO: Don't assume plain provisioner + "installNamespace": o.Spec.InstallNamespace, "provisionerClassName": bundleProvisioner, "source": map[string]interface{}{ // TODO: Don't assume image type @@ -452,10 +452,6 @@ func (r *ClusterExtensionReconciler) GenerateExpectedBundleDeployment(o ocv1alph }, } - if len(o.Spec.WatchNamespaces) > 0 { - spec["watchNamespaces"] = o.Spec.WatchNamespaces - } - bd := &unstructured.Unstructured{Object: map[string]interface{}{ "apiVersion": rukpakv1alpha2.GroupVersion.String(), "kind": rukpakv1alpha2.BundleDeploymentKind, diff --git a/internal/controllers/clusterextension_controller_test.go b/internal/controllers/clusterextension_controller_test.go index 2145f55a4..418bd4a0e 100644 --- a/internal/controllers/clusterextension_controller_test.go +++ b/internal/controllers/clusterextension_controller_test.go @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/require" apimeta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/rand" @@ -53,7 +52,10 @@ func TestClusterExtensionNonExistentPackage(t *testing.T) { pkgName := fmt.Sprintf("non-existent-%s", rand.String(6)) clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, - Spec: ocv1alpha1.ClusterExtensionSpec{PackageName: pkgName}, + Spec: ocv1alpha1.ClusterExtensionSpec{ + PackageName: pkgName, + InstallNamespace: "default", + }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -93,8 +95,9 @@ func TestClusterExtensionNonExistentVersion(t *testing.T) { clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: "0.50.0", // this version of the package does not exist + PackageName: pkgName, + Version: "0.50.0", // this version of the package does not exist + InstallNamespace: "default", }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -134,12 +137,16 @@ func TestClusterExtensionBundleDeploymentDoesNotExist(t *testing.T) { ctx := context.Background() extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} const pkgName = "prometheus" + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) t.Log("When the cluster extension specifies a valid available package") t.Log("By initializing cluster state") clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, - Spec: ocv1alpha1.ClusterExtensionSpec{PackageName: pkgName}, + Spec: ocv1alpha1.ClusterExtensionSpec{ + PackageName: pkgName, + InstallNamespace: installNamespace, + }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -156,6 +163,7 @@ func TestClusterExtensionBundleDeploymentDoesNotExist(t *testing.T) { bd := &rukpakv1alpha2.BundleDeployment{} require.NoError(t, cl.Get(ctx, types.NamespacedName{Name: extKey.Name}, bd)) require.Equal(t, "core-rukpak-io-registry", bd.Spec.ProvisionerClassName) + require.Equal(t, installNamespace, bd.Spec.InstallNamespace) require.Equal(t, rukpakv1alpha2.SourceTypeImage, bd.Spec.Source.Type) require.NotNil(t, bd.Spec.Source.Image) require.Equal(t, "quay.io/operatorhubio/prometheus@fake2.0.0", bd.Spec.Source.Image.Ref) @@ -189,12 +197,16 @@ func TestClusterExtensionBundleDeploymentOutOfDate(t *testing.T) { ctx := context.Background() extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} const pkgName = "prometheus" + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) t.Log("When the cluster extension specifies a valid available package") t.Log("By initializing cluster state") clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, - Spec: ocv1alpha1.ClusterExtensionSpec{PackageName: pkgName}, + Spec: ocv1alpha1.ClusterExtensionSpec{ + PackageName: pkgName, + InstallNamespace: installNamespace, + }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -216,6 +228,7 @@ func TestClusterExtensionBundleDeploymentOutOfDate(t *testing.T) { }, }, Spec: rukpakv1alpha2.BundleDeploymentSpec{ + InstallNamespace: "default", ProvisionerClassName: "core-rukpak-io-registry", Source: rukpakv1alpha2.BundleSource{ Type: rukpakv1alpha2.SourceTypeImage, @@ -227,6 +240,7 @@ func TestClusterExtensionBundleDeploymentOutOfDate(t *testing.T) { } t.Log("By modifying the BD spec and creating the object") + bd.Spec.InstallNamespace = "incorrect" bd.Spec.ProvisionerClassName = "core-rukpak-io-helm" require.NoError(t, cl.Create(ctx, bd)) @@ -244,6 +258,7 @@ func TestClusterExtensionBundleDeploymentOutOfDate(t *testing.T) { bd = &rukpakv1alpha2.BundleDeployment{} require.NoError(t, cl.Get(ctx, types.NamespacedName{Name: extKey.Name}, bd)) require.Equal(t, "core-rukpak-io-registry", bd.Spec.ProvisionerClassName) + require.Equal(t, installNamespace, bd.Spec.InstallNamespace) require.Equal(t, rukpakv1alpha2.SourceTypeImage, bd.Spec.Source.Type) require.NotNil(t, bd.Spec.Source.Image) require.Equal(t, "quay.io/operatorhubio/prometheus@fake2.0.0", bd.Spec.Source.Image.Ref) @@ -274,12 +289,16 @@ func TestClusterExtensionBundleDeploymentUpToDate(t *testing.T) { ctx := context.Background() extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} const pkgName = "prometheus" + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) t.Log("When the cluster extension specifies a valid available package") t.Log("By initializing cluster state") clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, - Spec: ocv1alpha1.ClusterExtensionSpec{PackageName: pkgName}, + Spec: ocv1alpha1.ClusterExtensionSpec{ + PackageName: pkgName, + InstallNamespace: installNamespace, + }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -301,6 +320,7 @@ func TestClusterExtensionBundleDeploymentUpToDate(t *testing.T) { }, }, Spec: rukpakv1alpha2.BundleDeploymentSpec{ + InstallNamespace: installNamespace, ProvisionerClassName: "core-rukpak-io-registry", Source: rukpakv1alpha2.BundleSource{ Type: rukpakv1alpha2.SourceTypeImage, @@ -522,7 +542,7 @@ func TestClusterExtensionBundleDeploymentUpToDate(t *testing.T) { require.Equal(t, &ocv1alpha1.BundleMetadata{Name: "operatorhub/prometheus/beta/2.0.0", Version: "2.0.0"}, ext.Status.ResolvedBundle) require.Nil(t, ext.Status.InstalledBundle) - t.Log("By cchecking the expected conditions") + t.Log("By checking the expected conditions") cond = apimeta.FindStatusCondition(ext.Status.Conditions, ocv1alpha1.TypeResolved) require.NotNil(t, cond) require.Equal(t, metav1.ConditionTrue, cond.Status) @@ -544,12 +564,16 @@ func TestClusterExtensionExpectedBundleDeployment(t *testing.T) { ctx := context.Background() extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} const pkgName = "prometheus" + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) t.Log("When the cluster extension specifies a valid available package") t.Log("By initializing cluster state") clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, - Spec: ocv1alpha1.ClusterExtensionSpec{PackageName: pkgName}, + Spec: ocv1alpha1.ClusterExtensionSpec{ + PackageName: pkgName, + InstallNamespace: installNamespace, + }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -558,6 +582,7 @@ func TestClusterExtensionExpectedBundleDeployment(t *testing.T) { bd := &rukpakv1alpha2.BundleDeployment{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: rukpakv1alpha2.BundleDeploymentSpec{ + InstallNamespace: "foo", ProvisionerClassName: "bar", Source: rukpakv1alpha2.BundleSource{ Type: rukpakv1alpha2.SourceTypeHTTP, @@ -581,6 +606,7 @@ func TestClusterExtensionExpectedBundleDeployment(t *testing.T) { bd = &rukpakv1alpha2.BundleDeployment{} require.NoError(t, cl.Get(ctx, types.NamespacedName{Name: extKey.Name}, bd)) require.Equal(t, "core-rukpak-io-registry", bd.Spec.ProvisionerClassName) + require.Equal(t, installNamespace, bd.Spec.InstallNamespace) require.Equal(t, rukpakv1alpha2.SourceTypeImage, bd.Spec.Source.Type) require.NotNil(t, bd.Spec.Source.Image) require.Equal(t, "quay.io/operatorhubio/prometheus@fake2.0.0", bd.Spec.Source.Image.Ref) @@ -618,12 +644,15 @@ func TestClusterExtensionChannelVersionExists(t *testing.T) { pkgName := "prometheus" pkgVer := "1.0.0" pkgChan := "beta" + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) + clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, + PackageName: pkgName, + Version: pkgVer, + Channel: pkgChan, + InstallNamespace: installNamespace, }, } err := cl.Create(ctx, clusterExtension) @@ -658,6 +687,7 @@ func TestClusterExtensionChannelVersionExists(t *testing.T) { bd := &rukpakv1alpha2.BundleDeployment{} require.NoError(t, cl.Get(ctx, types.NamespacedName{Name: extKey.Name}, bd)) require.Equal(t, "core-rukpak-io-registry", bd.Spec.ProvisionerClassName) + require.Equal(t, installNamespace, bd.Spec.InstallNamespace) require.Equal(t, rukpakv1alpha2.SourceTypeImage, bd.Spec.Source.Type) require.NotNil(t, bd.Spec.Source.Image) require.Equal(t, "quay.io/operatorhubio/prometheus@fake1.0.0", bd.Spec.Source.Image.Ref) @@ -677,12 +707,14 @@ func TestClusterExtensionChannelExistsNoVersion(t *testing.T) { pkgName := "prometheus" pkgVer := "" pkgChan := "beta" + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, + PackageName: pkgName, + Version: pkgVer, + Channel: pkgChan, + InstallNamespace: installNamespace, }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -715,6 +747,7 @@ func TestClusterExtensionChannelExistsNoVersion(t *testing.T) { bd := &rukpakv1alpha2.BundleDeployment{} require.NoError(t, cl.Get(ctx, types.NamespacedName{Name: extKey.Name}, bd)) require.Equal(t, "core-rukpak-io-registry", bd.Spec.ProvisionerClassName) + require.Equal(t, installNamespace, bd.Spec.InstallNamespace) require.Equal(t, rukpakv1alpha2.SourceTypeImage, bd.Spec.Source.Type) require.NotNil(t, bd.Spec.Source.Image) require.Equal(t, "quay.io/operatorhubio/prometheus@fake2.0.0", bd.Spec.Source.Image.Ref) @@ -737,9 +770,10 @@ func TestClusterExtensionVersionNoChannel(t *testing.T) { clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, + PackageName: pkgName, + Version: pkgVer, + Channel: pkgChan, + InstallNamespace: "default", }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -787,8 +821,9 @@ func TestClusterExtensionNoChannel(t *testing.T) { clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Channel: pkgChan, + PackageName: pkgName, + Channel: pkgChan, + InstallNamespace: "default", }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -836,9 +871,10 @@ func TestClusterExtensionNoVersion(t *testing.T) { clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, + PackageName: pkgName, + Version: pkgVer, + Channel: pkgChan, + InstallNamespace: "default", }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -886,9 +922,10 @@ func TestClusterExtensionPlainV0Bundle(t *testing.T) { clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, + PackageName: pkgName, + Version: pkgVer, + Channel: pkgChan, + InstallNamespace: "default", }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -943,9 +980,10 @@ func TestClusterExtensionBadBundleMediaType(t *testing.T) { clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, + PackageName: pkgName, + Version: pkgVer, + Channel: pkgChan, + InstallNamespace: "default", }, } require.NoError(t, cl.Create(ctx, clusterExtension)) @@ -1005,11 +1043,10 @@ func verifyConditionsInvariants(t *testing.T, ext *ocv1alpha1.ClusterExtension) func TestGeneratedBundleDeployment(t *testing.T) { test := []struct { - name string - clusterExtension ocv1alpha1.ClusterExtension - bundlePath string - bundleProvisioner string - expectedBundleDeployment *unstructured.Unstructured + name string + clusterExtension ocv1alpha1.ClusterExtension + bundlePath string + bundleProvisioner string }{ { name: "when all the specs are provided.", @@ -1019,24 +1056,11 @@ func TestGeneratedBundleDeployment(t *testing.T) { UID: types.UID("test"), }, Spec: ocv1alpha1.ClusterExtensionSpec{ - WatchNamespaces: []string{"alpha", "beta", "gamma"}, - }, - }, - bundlePath: "testpath", - bundleProvisioner: "foo", - expectedBundleDeployment: &unstructured.Unstructured{}, - }, - { - name: "when watchNamespaces are not provided.", - clusterExtension: ocv1alpha1.ClusterExtension{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-bd", - UID: types.UID("test"), + InstallNamespace: "test-ns", }, }, - bundlePath: "testpath", - bundleProvisioner: "foo", - expectedBundleDeployment: &unstructured.Unstructured{}, + bundlePath: "testpath", + bundleProvisioner: "foo", }, } @@ -1049,7 +1073,7 @@ func TestGeneratedBundleDeployment(t *testing.T) { require.Equal(t, tt.clusterExtension.GetName(), resultBundleDeployment.GetName()) require.Equal(t, tt.bundlePath, resultBundleDeployment.Spec.Source.Image.Ref) require.Equal(t, tt.bundleProvisioner, resultBundleDeployment.Spec.ProvisionerClassName) - require.Equal(t, tt.clusterExtension.Spec.WatchNamespaces, resultBundleDeployment.Spec.WatchNamespaces) + require.Equal(t, tt.clusterExtension.Spec.InstallNamespace, resultBundleDeployment.Spec.InstallNamespace) } } @@ -1067,13 +1091,15 @@ func TestClusterExtensionUpgrade(t *testing.T) { pkgName := "prometheus" pkgVer := "1.0.0" pkgChan := "beta" + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, + PackageName: pkgName, + Version: pkgVer, + Channel: pkgChan, + InstallNamespace: installNamespace, }, } // Create a cluster extension @@ -1159,13 +1185,15 @@ func TestClusterExtensionUpgrade(t *testing.T) { pkgName := "prometheus" pkgVer := "1.0.0" pkgChan := "beta" + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, + PackageName: pkgName, + Version: pkgVer, + Channel: pkgChan, + InstallNamespace: installNamespace, }, } // Create a cluster extension @@ -1262,6 +1290,7 @@ func TestClusterExtensionUpgrade(t *testing.T) { require.NoError(t, cl.DeleteAllOf(ctx, &rukpakv1alpha2.BundleDeployment{})) }() + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, @@ -1270,6 +1299,7 @@ func TestClusterExtensionUpgrade(t *testing.T) { Version: "1.0.0", Channel: "beta", UpgradeConstraintPolicy: ocv1alpha1.UpgradeConstraintPolicyIgnore, + InstallNamespace: installNamespace, }, } // Create a cluster extension @@ -1350,13 +1380,15 @@ func TestClusterExtensionDowngrade(t *testing.T) { require.NoError(t, cl.DeleteAllOf(ctx, &rukpakv1alpha2.BundleDeployment{})) }() + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: "prometheus", - Version: "1.0.1", - Channel: "beta", + PackageName: "prometheus", + Version: "1.0.1", + Channel: "beta", + InstallNamespace: installNamespace, }, } // Create a cluster extension @@ -1431,6 +1463,7 @@ func TestClusterExtensionDowngrade(t *testing.T) { require.NoError(t, cl.DeleteAllOf(ctx, &rukpakv1alpha2.BundleDeployment{})) }() + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, @@ -1439,6 +1472,7 @@ func TestClusterExtensionDowngrade(t *testing.T) { Version: "2.0.0", Channel: "beta", UpgradeConstraintPolicy: ocv1alpha1.UpgradeConstraintPolicyIgnore, + InstallNamespace: installNamespace, }, } // Create a cluster extension diff --git a/internal/controllers/clusterextension_registryv1_validation_test.go b/internal/controllers/clusterextension_registryv1_validation_test.go index 40493add4..4339e768d 100644 --- a/internal/controllers/clusterextension_registryv1_validation_test.go +++ b/internal/controllers/clusterextension_registryv1_validation_test.go @@ -108,10 +108,14 @@ func TestClusterExtensionRegistryV1DisallowDependencies(t *testing.T) { BundleProvider: &fakeCatalogClient, } + installNamespace := fmt.Sprintf("test-ns-%s", rand.String(8)) extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} clusterExtension := &ocv1alpha1.ClusterExtension{ ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, - Spec: ocv1alpha1.ClusterExtensionSpec{PackageName: tt.bundle.Package}, + Spec: ocv1alpha1.ClusterExtensionSpec{ + PackageName: tt.bundle.Package, + InstallNamespace: installNamespace, + }, } require.NoError(t, cl.Create(ctx, clusterExtension)) diff --git a/test/e2e/cluster_extension_admission_test.go b/test/e2e/cluster_extension_admission_test.go index bfa58d4c5..b1cca6c3f 100644 --- a/test/e2e/cluster_extension_admission_test.go +++ b/test/e2e/cluster_extension_admission_test.go @@ -35,7 +35,8 @@ func TestClusterExtensionPackageUniqueness(t *testing.T) { Name: firstResourceName, }, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: firstResourcePackageName, + PackageName: firstResourcePackageName, + InstallNamespace: "default", }, } require.NoError(t, c.Create(ctx, clusterExtension1)) @@ -47,7 +48,8 @@ func TestClusterExtensionPackageUniqueness(t *testing.T) { GenerateName: "test-extension-", }, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: firstResourcePackageName, + PackageName: firstResourcePackageName, + InstallNamespace: "default", }, } err := c.Create(ctx, clusterExtension2) @@ -59,7 +61,8 @@ func TestClusterExtensionPackageUniqueness(t *testing.T) { GenerateName: "test-extension-", }, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: "package2", + PackageName: "package2", + InstallNamespace: "default", }, } require.NoError(t, c.Create(ctx, clusterExtension2)) @@ -75,7 +78,8 @@ func TestClusterExtensionPackageUniqueness(t *testing.T) { Name: clusterExtension2.Name, }, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: firstResourcePackageName, + PackageName: firstResourcePackageName, + InstallNamespace: "default", }, } err = c.Patch(ctx, intent, client.Apply, client.ForceOwnership, fieldOwner) @@ -91,7 +95,8 @@ func TestClusterExtensionPackageUniqueness(t *testing.T) { Name: clusterExtension2.Name, }, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: "package3", + PackageName: "package3", + InstallNamespace: "default", }, } require.NoError(t, c.Patch(ctx, intent, client.Apply, client.ForceOwnership, fieldOwner)) diff --git a/test/e2e/cluster_extension_install_test.go b/test/e2e/cluster_extension_install_test.go index cdc95ce59..3f2b7df86 100644 --- a/test/e2e/cluster_extension_install_test.go +++ b/test/e2e/cluster_extension_install_test.go @@ -73,7 +73,8 @@ func TestClusterExtensionInstallRegistry(t *testing.T) { defer getArtifactsOutput(t) clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ - PackageName: "prometheus", + PackageName: "prometheus", + InstallNamespace: "default", } t.Log("It resolves the specified package with correct bundle path") t.Log("By creating the ClusterExtension resource") @@ -129,7 +130,8 @@ func TestClusterExtensionInstallPlain(t *testing.T) { defer getArtifactsOutput(t) clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ - PackageName: "plain", + PackageName: "plain", + InstallNamespace: "default", } t.Log("It resolves the specified package with correct bundle path") t.Log("By creating the ClusterExtension resource") @@ -186,7 +188,8 @@ func TestClusterExtensionInstallReResolvesWhenNewCatalog(t *testing.T) { pkgName := "prometheus" clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, + PackageName: pkgName, + InstallNamespace: "default", } t.Log("By deleting the catalog first") @@ -247,8 +250,9 @@ func TestClusterExtensionBlockInstallNonSuccessorVersion(t *testing.T) { t.Log("By creating an ClusterExtension at a specified version") clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ - PackageName: "prometheus", - Version: "1.0.0", + PackageName: "prometheus", + Version: "1.0.0", + InstallNamespace: "default", } require.NoError(t, c.Create(context.Background(), clusterExtension)) t.Log("By eventually reporting a successful resolution") @@ -291,8 +295,9 @@ func TestClusterExtensionForceInstallNonSuccessorVersion(t *testing.T) { t.Log("By creating an ClusterExtension at a specified version") clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ - PackageName: "prometheus", - Version: "1.0.0", + PackageName: "prometheus", + Version: "1.0.0", + InstallNamespace: "default", } require.NoError(t, c.Create(context.Background(), clusterExtension)) t.Log("By eventually reporting a successful resolution") @@ -335,8 +340,9 @@ func TestClusterExtensionInstallSuccessorVersion(t *testing.T) { t.Log("By creating an ClusterExtension at a specified version") clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ - PackageName: "prometheus", - Version: "1.0.0", + PackageName: "prometheus", + Version: "1.0.0", + InstallNamespace: "default", } require.NoError(t, c.Create(context.Background(), clusterExtension)) t.Log("By eventually reporting a successful resolution") diff --git a/test/extension-developer-e2e/extension_developer_test.go b/test/extension-developer-e2e/extension_developer_test.go index 325d32c86..cb7b5f7d0 100644 --- a/test/extension-developer-e2e/extension_developer_test.go +++ b/test/extension-developer-e2e/extension_developer_test.go @@ -37,7 +37,8 @@ func TestExtensionDeveloper(t *testing.T) { Name: "plainv0", }, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: os.Getenv("PLAIN_PKG_NAME"), + PackageName: os.Getenv("PLAIN_PKG_NAME"), + InstallNamespace: "default", }, }, { @@ -45,7 +46,8 @@ func TestExtensionDeveloper(t *testing.T) { Name: "registryv1", }, Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: os.Getenv("REG_PKG_NAME"), + PackageName: os.Getenv("REG_PKG_NAME"), + InstallNamespace: "default", }, }, } diff --git a/testdata/crds/core.rukpak.io_bundledeployments.yaml b/testdata/crds/core.rukpak.io_bundledeployments.yaml index 0cedcf0c5..c9a7e6f9e 100644 --- a/testdata/crds/core.rukpak.io_bundledeployments.yaml +++ b/testdata/crds/core.rukpak.io_bundledeployments.yaml @@ -50,21 +50,33 @@ spec: More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: + properties: + name: + maxLength: 52 + type: string type: object spec: description: BundleDeploymentSpec defines the desired state of BundleDeployment properties: config: - description: Config is provisioner specific configurations + description: config is provisioner specific configurations type: object x-kubernetes-preserve-unknown-fields: true + installNamespace: + description: |- + installNamespace is the namespace where the bundle should be installed. However, note that + the bundle may contain resources that are cluster-scoped or that are + installed in a different namespace. This namespace is expected to exist. + maxLength: 63 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string provisionerClassName: - description: ProvisionerClassName sets the name of the provisioner + description: provisionerClassName sets the name of the provisioner that should reconcile this BundleDeployment. pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string source: - description: Source defines the configuration for the underlying Bundle + description: source defines the configuration for the underlying Bundle content. properties: configMaps: @@ -136,6 +148,13 @@ spec: from the specified repo. Ref is required, and exactly one field within Ref is required. Setting more than one field or zero fields will result in an error. + oneOf: + - required: + - branch + - required: + - commit + - required: + - tag properties: branch: description: |- @@ -221,22 +240,11 @@ spec: required: - type type: object - watchNamespaces: - description: watchNamespaces indicates which namespaces the operator - should watch. - items: - type: string - type: array required: + - installNamespace - provisionerClassName - source type: object - x-kubernetes-validations: - - message: Empty string not accepted if length of watchNamespaces is more - than 1. - rule: '!has(self.watchNamespaces) || size(self.watchNamespaces) <= 1 - || (size(self.watchNamespaces) > 1 && !self.watchNamespaces.exists(e, - e == ''''))' status: description: BundleDeploymentStatus defines the observed state of BundleDeployment properties: