diff --git a/Makefile b/Makefile index daee0830..4361e79c 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ clean: ## Remove binaries and test artifacts generate: controller-gen ## Generate code and manifests $(Q)$(CONTROLLER_GEN) crd:crdVersions=v1,generateEmbeddedObjectMeta=true output:crd:dir=./manifests/apis/crds paths=./api/... - $(Q)$(CONTROLLER_GEN) webhook paths=./api/... output:stdout > ./manifests/apis/webhooks/resources/webhook.yaml + $(Q)$(CONTROLLER_GEN) webhook paths=./api/... paths=./internal/webhook/... output:stdout > ./manifests/apis/webhooks/resources/webhook.yaml $(Q)$(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths=./api/... $(Q)$(CONTROLLER_GEN) rbac:roleName=core-admin \ paths=./internal/provisioner/bundle/... \ @@ -77,6 +77,7 @@ generate: controller-gen ## Generate code and manifests paths=./internal/provisioner/registry/... \ paths=./internal/uploadmgr/... \ output:stdout > ./manifests/core/resources/cluster_role.yaml + $(Q)$(CONTROLLER_GEN) rbac:roleName=webhooks-admin paths=./internal/webhook/... output:stdout > ./manifests/apis/webhooks/resources/cluster_role.yaml $(Q)$(CONTROLLER_GEN) rbac:roleName=helm-provisioner-admin \ paths=./internal/provisioner/bundle/... \ paths=./internal/provisioner/bundledeployment/... \ @@ -100,10 +101,10 @@ UNIT_TEST_DIRS=$(shell go list ./... | grep -v /test/) test-unit: setup-envtest ## Run the unit tests eval $$($(SETUP_ENVTEST) use -p env $(ENVTEST_VERSION)) && go test -tags $(GO_BUILD_TAGS) -count=1 -short $(UNIT_TEST_DIRS) -FOCUS := $(if $(TEST),-v -focus "$(TEST)") -E2E_FLAGS ?= "" +FOCUS := $(if $(TEST),-v --focus "$(TEST)") +E2E_FLAGS ?= test-e2e: ginkgo ## Run the e2e tests - $(GINKGO) --tags $(GO_BUILD_TAGS) $(E2E_FLAGS) -trace -progress $(FOCUS) test/e2e + $(GINKGO) --tags $(GO_BUILD_TAGS) $(E2E_FLAGS) --trace --progress $(FOCUS) test/e2e e2e: KIND_CLUSTER_NAME=rukpak-e2e e2e: rukpakctl run image-registry local-git kind-load-bundles registry-load-bundles test-e2e kind-cluster-cleanup ## Run e2e tests against an ephemeral kind cluster diff --git a/api/v1alpha1/bundle_types.go b/api/v1alpha1/bundle_types.go index 63732ebc..cf4c3923 100644 --- a/api/v1alpha1/bundle_types.go +++ b/api/v1alpha1/bundle_types.go @@ -29,11 +29,11 @@ var ( type SourceType string const ( - SourceTypeImage SourceType = "image" - SourceTypeGit SourceType = "git" - SourceTypeLocal SourceType = "local" - SourceTypeUpload SourceType = "upload" - SourceTypeHTTP SourceType = "http" + SourceTypeImage SourceType = "image" + SourceTypeGit SourceType = "git" + SourceTypeConfigMaps SourceType = "configMaps" + SourceTypeUpload SourceType = "upload" + SourceTypeHTTP SourceType = "http" TypeUnpacked = "Unpacked" @@ -65,8 +65,9 @@ type BundleSource struct { Image *ImageSource `json:"image,omitempty"` // Git is the git repository that backs the content of this Bundle. Git *GitSource `json:"git,omitempty"` - // Local is a reference to a local object in the cluster. - Local *LocalSource `json:"local,omitempty"` + // ConfigMaps is a list of config map references and their relative + // directory paths that represent a bundle filesystem. + ConfigMaps []ConfigMapSource `json:"configMaps,omitempty"` // Upload is a source that enables this Bundle's content to be uploaded // via Rukpak's bundle upload service. This source type is primarily useful // with bundle development workflows because it enables bundle developers @@ -99,8 +100,12 @@ type GitSource struct { Auth Authorization `json:"auth,omitempty"` } -type LocalSource struct { - ConfigMapRef *ConfigMapRef `json:"configMap"` +type ConfigMapSource struct { + // ConfigMap is a reference to a configmap in the rukpak system namespace + ConfigMap corev1.LocalObjectReference `json:"configMap"` + // Path is the relative directory path within the bundle where the files + // from the configmap will be present when the bundle is unpacked. + Path string `json:"path,omitempty"` } type HTTPSource struct { diff --git a/api/v1alpha1/bundle_webhook.go b/api/v1alpha1/bundle_webhook.go index f7c4d6be..8697bf34 100644 --- a/api/v1alpha1/bundle_webhook.go +++ b/api/v1alpha1/bundle_webhook.go @@ -81,6 +81,15 @@ func checkBundleSource(r *Bundle) error { if strings.HasPrefix(filepath.Clean(r.Spec.Source.Git.Directory), "../") { return fmt.Errorf(`bundle.spec.source.git.directory begins with "../": directory must define path within the repository`) } + case SourceTypeConfigMaps: + if len(r.Spec.Source.ConfigMaps) == 0 { + return fmt.Errorf(`bundle.spec.source.configmaps must be set for source type "configmaps"`) + } + for i, cm := range r.Spec.Source.ConfigMaps { + if strings.HasPrefix(filepath.Clean(cm.Path), ".."+string(filepath.Separator)) { + return fmt.Errorf("bundle.spec.source.configmaps[%d].path is invalid: %s is outside bundle root", i, cm.Path) + } + } } return nil } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 84bc5581..c8c665bb 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -216,10 +216,10 @@ func (in *BundleSource) DeepCopyInto(out *BundleSource) { *out = new(GitSource) **out = **in } - if in.Local != nil { - in, out := &in.Local, &out.Local - *out = new(LocalSource) - (*in).DeepCopyInto(*out) + if in.ConfigMaps != nil { + in, out := &in.ConfigMaps, &out.ConfigMaps + *out = make([]ConfigMapSource, len(*in)) + copy(*out, *in) } if in.Upload != nil { in, out := &in.Upload, &out.Upload @@ -318,6 +318,22 @@ func (in *ConfigMapRef) DeepCopy() *ConfigMapRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapSource) DeepCopyInto(out *ConfigMapSource) { + *out = *in + out.ConfigMap = in.ConfigMap +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapSource. +func (in *ConfigMapSource) DeepCopy() *ConfigMapSource { + if in == nil { + return nil + } + out := new(ConfigMapSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GitRef) DeepCopyInto(out *GitRef) { *out = *in @@ -381,26 +397,6 @@ func (in *ImageSource) DeepCopy() *ImageSource { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LocalSource) DeepCopyInto(out *LocalSource) { - *out = *in - if in.ConfigMapRef != nil { - in, out := &in.ConfigMapRef, &out.ConfigMapRef - *out = new(ConfigMapRef) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalSource. -func (in *LocalSource) DeepCopy() *LocalSource { - if in == nil { - return nil - } - out := new(LocalSource) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *UploadSource) DeepCopyInto(out *UploadSource) { *out = *in diff --git a/cmd/core/main.go b/cmd/core/main.go index 3fb1991c..3aeaa8d5 100644 --- a/cmd/core/main.go +++ b/cmd/core/main.go @@ -36,6 +36,7 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/cluster" crfinalizer "sigs.k8s.io/controller-runtime/pkg/finalizer" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -116,6 +117,15 @@ func main() { dependentSelector := labels.NewSelector().Add(*dependentRequirement) cfg := ctrl.GetConfigOrDie() + systemNs := util.PodNamespace(systemNamespace) + systemNsCluster, err := cluster.New(cfg, func(opts *cluster.Options) { + opts.Scheme = scheme + opts.Namespace = systemNs + }) + if err != nil { + setupLog.Error(err, "unable to create system namespace cluster") + os.Exit(1) + } mgr, err := ctrl.NewManager(cfg, ctrl.Options{ Scheme: scheme, MetricsBindAddress: httpBindAddr, @@ -138,7 +148,11 @@ func main() { os.Exit(1) } - ns := util.PodNamespace(systemNamespace) + if err := mgr.Add(systemNsCluster); err != nil { + setupLog.Error(err, "unable to add system namespace cluster to manager") + os.Exit(1) + } + storageURL, err := url.Parse(fmt.Sprintf("%s/bundles/", httpExternalAddr)) if err != nil { setupLog.Error(err, "unable to parse bundle content server URL") @@ -201,7 +215,7 @@ func main() { os.Exit(1) } - unpacker, err := source.NewDefaultUnpacker(mgr, ns, unpackImage, baseUploadManagerURL, rootCAs) + unpacker, err := source.NewDefaultUnpacker(systemNsCluster, systemNs, unpackImage, baseUploadManagerURL, rootCAs) if err != nil { setupLog.Error(err, "unable to setup bundle unpacker") os.Exit(1) @@ -216,12 +230,12 @@ func main() { cfgGetter := helmclient.NewActionConfigGetter(mgr.GetConfig(), mgr.GetRESTMapper(), mgr.GetLogger()) acg := helmclient.NewActionClientGetter(cfgGetter) commonBDProvisionerOptions := []bundledeployment.Option{ - bundledeployment.WithReleaseNamespace(ns), + bundledeployment.WithReleaseNamespace(systemNs), bundledeployment.WithActionClientGetter(acg), bundledeployment.WithStorage(bundleStorage), } - if err := bundle.SetupProvisioner(mgr, append( + if err := bundle.SetupProvisioner(mgr, systemNsCluster.GetCache(), systemNs, append( commonBundleProvisionerOptions, bundle.WithProvisionerID(plain.ProvisionerID), bundle.WithHandler(bundle.HandlerFunc(plain.HandleBundle)), @@ -230,7 +244,7 @@ func main() { os.Exit(1) } - if err := bundle.SetupProvisioner(mgr, append( + if err := bundle.SetupProvisioner(mgr, systemNsCluster.GetCache(), systemNs, append( commonBundleProvisionerOptions, bundle.WithProvisionerID(registry.ProvisionerID), bundle.WithHandler(bundle.HandlerFunc(registry.HandleBundle)), diff --git a/cmd/helm/main.go b/cmd/helm/main.go index 55b7d62c..a5f769c5 100644 --- a/cmd/helm/main.go +++ b/cmd/helm/main.go @@ -32,6 +32,7 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/cluster" crfinalizer "sigs.k8s.io/controller-runtime/pkg/finalizer" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -106,6 +107,15 @@ func main() { dependentSelector := labels.NewSelector().Add(*dependentRequirement) cfg := ctrl.GetConfigOrDie() + systemNs := util.PodNamespace(systemNamespace) + systemNsCluster, err := cluster.New(cfg, func(opts *cluster.Options) { + opts.Scheme = scheme + opts.Namespace = systemNs + }) + if err != nil { + setupLog.Error(err, "unable to create system namespace cluster") + os.Exit(1) + } mgr, err := ctrl.NewManager(cfg, ctrl.Options{ Scheme: scheme, MetricsBindAddress: httpBindAddr, @@ -128,7 +138,11 @@ func main() { os.Exit(1) } - ns := util.PodNamespace(systemNamespace) + if err := mgr.Add(systemNsCluster); err != nil { + setupLog.Error(err, "unable to add system namespace cluster to manager") + os.Exit(1) + } + storageURL, err := url.Parse(fmt.Sprintf("%s/bundles/", httpExternalAddr)) if err != nil { setupLog.Error(err, "unable to parse bundle content server URL") @@ -183,7 +197,7 @@ func main() { os.Exit(1) } - unpacker, err := source.NewDefaultUnpacker(mgr, ns, unpackImage, baseUploadManagerURL, rootCAs) + unpacker, err := source.NewDefaultUnpacker(systemNsCluster, systemNs, unpackImage, baseUploadManagerURL, rootCAs) if err != nil { setupLog.Error(err, "unable to setup bundle unpacker") os.Exit(1) @@ -198,12 +212,12 @@ func main() { cfgGetter := helmclient.NewActionConfigGetter(mgr.GetConfig(), mgr.GetRESTMapper(), mgr.GetLogger()) acg := helmclient.NewActionClientGetter(cfgGetter) commonBDProvisionerOptions := []bundledeployment.Option{ - bundledeployment.WithReleaseNamespace(ns), + bundledeployment.WithReleaseNamespace(systemNs), bundledeployment.WithActionClientGetter(acg), bundledeployment.WithStorage(bundleStorage), } - if err := bundle.SetupProvisioner(mgr, append( + if err := bundle.SetupProvisioner(mgr, systemNsCluster.GetCache(), systemNs, append( commonBundleProvisionerOptions, bundle.WithProvisionerID(helm.ProvisionerID), bundle.WithHandler(bundle.HandlerFunc(helm.HandleBundle)), diff --git a/cmd/rukpakctl/cmd/bundle.go b/cmd/rukpakctl/cmd/bundle.go deleted file mode 100644 index 07ed917f..00000000 --- a/cmd/rukpakctl/cmd/bundle.go +++ /dev/null @@ -1,128 +0,0 @@ -/* -Copyright © 2022 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "context" - "errors" - "fmt" - "log" - - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/kubernetes/scheme" - runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/config" - - rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" - "github.com/operator-framework/rukpak/cmd/rukpakctl/utils" - "github.com/operator-framework/rukpak/internal/provisioner/plain" - "github.com/operator-framework/rukpak/internal/util" -) - -type bundleOptions struct { - *kubernetes.Clientset - runtimeclient.Client - namespace string -} - -// bundleCmd represents the bundle command -func newBundleCmd() *cobra.Command { - var bundleOpt bundleOptions - - bundleCmd := &cobra.Command{ - Use: "bundle ", - Short: "create rukpak bundle resource.", - Long: `create rukpak bundle resource with specified contents.`, - Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return errors.New("requires argument: ") - } - return nil - }, - Run: func(cmd *cobra.Command, args []string) { - sch := scheme.Scheme - if err := rukpakv1alpha1.AddToScheme(sch); err != nil { - log.Fatal(err) - } - - cfg, err := config.GetConfig() - if err != nil { - log.Fatalf("failed to find kubeconfig location: %v", err) - } - - bundleOpt.Client, err = runtimeclient.New(cfg, runtimeclient.Options{ - Scheme: sch, - }) - if err != nil { - log.Fatalf("failed to create kubernetes client: %v", err) - } - - if bundleOpt.Clientset, err = kubernetes.NewForConfig(cfg); err != nil { - log.Fatalf("failed to create kubernetes client: %v", err) - } - - err = bundle(cmd.Context(), bundleOpt, args) - if err != nil { - log.Fatalf("bundle command failed: %v", err) - } - }, - } - bundleCmd.Flags().StringVar(&bundleOpt.namespace, "namespace", util.DefaultSystemNamespace, "namespace for target or work resources") - return bundleCmd -} - -func bundle(ctx context.Context, opt bundleOptions, args []string) error { - namePrefix := "rukpakctl-bundle-" - if len(args) > 1 { - namePrefix = args[1] - } - // Create a bundle configmap - configmapName, err := utils.CreateConfigmap(ctx, opt.CoreV1(), namePrefix, args[0], opt.namespace) - if err != nil { - return fmt.Errorf("failed to create a configmap: %v", err) - } - - bundle := &rukpakv1alpha1.Bundle{ - TypeMeta: metav1.TypeMeta{ - Kind: "Bundle", - APIVersion: "core.rukpak.io/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: namePrefix, - }, - Spec: rukpakv1alpha1.BundleSpec{ - ProvisionerClassName: plain.ProvisionerID, - Source: rukpakv1alpha1.BundleSource{ - Type: rukpakv1alpha1.SourceTypeLocal, - Local: &rukpakv1alpha1.LocalSource{ - ConfigMapRef: &rukpakv1alpha1.ConfigMapRef{ - Name: configmapName, - Namespace: opt.namespace, - }, - }, - }, - }, - } - err = opt.Create(ctx, bundle) - if err != nil { - return fmt.Errorf("failed to create bundle: %v", err) - } - fmt.Printf("bundle %q created\n", bundle.ObjectMeta.Name) - - return nil -} diff --git a/cmd/rukpakctl/cmd/bundledeployment.go b/cmd/rukpakctl/cmd/bundledeployment.go deleted file mode 100644 index 476d1a67..00000000 --- a/cmd/rukpakctl/cmd/bundledeployment.go +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright © 2022 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "context" - "errors" - "fmt" - "log" - - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/kubernetes/scheme" - runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/config" - - rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" - "github.com/operator-framework/rukpak/cmd/rukpakctl/utils" - "github.com/operator-framework/rukpak/internal/provisioner/plain" - "github.com/operator-framework/rukpak/internal/util" -) - -type bundleDeploymentOptions struct { - *kubernetes.Clientset - runtimeclient.Client - namespace string -} - -// contentCmd represents the content command -func newBundleDeploymentCmd() *cobra.Command { - var bundleDeploymentOpt bundleDeploymentOptions - - bdCmd := &cobra.Command{ - Use: "bundledeployment ", - Short: "create rukpak bundledeployment resource", - Long: `create rukpak bundledeployment resource with specified contents.`, - Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return errors.New("requires argument: ") - } - return nil - }, - Run: func(cmd *cobra.Command, args []string) { - sch := scheme.Scheme - if err := rukpakv1alpha1.AddToScheme(sch); err != nil { - log.Fatal(err) - } - - cfg, err := config.GetConfig() - if err != nil { - log.Fatalf("failed to find kubeconfig location: %v", err) - } - - bundleDeploymentOpt.Client, err = runtimeclient.New(cfg, runtimeclient.Options{ - Scheme: sch, - }) - if err != nil { - log.Fatalf("failed to create kubernetes client: %v", err) - } - - if bundleDeploymentOpt.Clientset, err = kubernetes.NewForConfig(cfg); err != nil { - log.Fatalf("failed to create kubernetes client: %v", err) - } - - if err := bundleDeployment(cmd.Context(), bundleDeploymentOpt, args); err != nil { - log.Fatalf("bundledeployment command failed: %v", err) - } - }, - } - bdCmd.Flags().StringVar(&bundleDeploymentOpt.namespace, "namespace", util.DefaultSystemNamespace, "namespace for target or work resources") - return bdCmd -} - -func bundleDeployment(ctx context.Context, opt bundleDeploymentOptions, args []string) error { - namePrefix := "rukpakctl-bd-" - if len(args) > 1 { - namePrefix = args[1] - } - // Create a bundle configmap - configmapName, err := utils.CreateConfigmap(ctx, opt.CoreV1(), namePrefix, args[0], opt.namespace) - if err != nil { - return fmt.Errorf("failed to create a configmap: %v", err) - } - - bundleDeployment := &rukpakv1alpha1.BundleDeployment{ - TypeMeta: metav1.TypeMeta{ - Kind: "BundleDeployment", - APIVersion: "core.rukpak.io/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: namePrefix, - }, - Spec: rukpakv1alpha1.BundleDeploymentSpec{ - ProvisionerClassName: plain.ProvisionerID, - Template: &rukpakv1alpha1.BundleTemplate{ - Spec: rukpakv1alpha1.BundleSpec{ - ProvisionerClassName: plain.ProvisionerID, - Source: rukpakv1alpha1.BundleSource{ - Type: rukpakv1alpha1.SourceTypeLocal, - Local: &rukpakv1alpha1.LocalSource{ - ConfigMapRef: &rukpakv1alpha1.ConfigMapRef{ - Name: configmapName, - Namespace: opt.namespace, - }, - }, - }, - }, - }, - }, - } - err = opt.Create(ctx, bundleDeployment) - if err != nil { - return fmt.Errorf("failed to create bundledeployment: %v", err) - } - fmt.Printf("bundledeployment %q created\n", bundleDeployment.ObjectMeta.Name) - - return nil -} diff --git a/cmd/rukpakctl/cmd/create.go b/cmd/rukpakctl/cmd/create.go deleted file mode 100644 index 0f56a650..00000000 --- a/cmd/rukpakctl/cmd/create.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright © 2022 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "github.com/spf13/cobra" -) - -// newCreateCmd creates the "create" subcommand -func newCreateCmd() *cobra.Command { - createCmd := &cobra.Command{Use: "create", - Short: "create command creates rukpak resource", - Long: `create command creates specified rukpak resource.`, - } - createCmd.AddCommand( - newBundleCmd(), - newBundleDeploymentCmd(), - ) - return createCmd -} diff --git a/cmd/rukpakctl/cmd/root.go b/cmd/rukpakctl/cmd/root.go index ec9fc6db..bf0eae48 100644 --- a/cmd/rukpakctl/cmd/root.go +++ b/cmd/rukpakctl/cmd/root.go @@ -25,7 +25,6 @@ to quickly create a Cobra application.`, rootCmd.AddCommand( newContentCmd(), - newCreateCmd(), newRunCmd(), ) diff --git a/cmd/rukpakctl/utils/utils.go b/cmd/rukpakctl/utils/utils.go deleted file mode 100644 index c31bb79e..00000000 --- a/cmd/rukpakctl/utils/utils.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright © 2022 NAME HERE -*/ -package utils - -import ( - "context" - "os" - "path/filepath" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - typedv1 "k8s.io/client-go/kubernetes/typed/core/v1" -) - -func CreateConfigmap(ctx context.Context, core typedv1.CoreV1Interface, name, dir, namespace string) (string, error) { - // Create a bundle configmap - data := map[string]string{} - err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - return nil - } - c, err := os.ReadFile(path) - if err != nil { - return err - } - data[info.Name()] = string(c) - return nil - }) - if err != nil { - return "", err - } - configmap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: name, - Namespace: namespace, - }, - Data: data, - } - configmap, err = core.ConfigMaps(namespace).Create(ctx, configmap, metav1.CreateOptions{}) - return configmap.ObjectMeta.Name, err -} diff --git a/cmd/webhooks/main.go b/cmd/webhooks/main.go index b5af29c7..6261be7e 100644 --- a/cmd/webhooks/main.go +++ b/cmd/webhooks/main.go @@ -34,6 +34,7 @@ import ( rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" "github.com/operator-framework/rukpak/internal/util" "github.com/operator-framework/rukpak/internal/version" + "github.com/operator-framework/rukpak/internal/webhook" ) var ( @@ -107,6 +108,10 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", rukpakv1alpha1.BundleKind) os.Exit(1) } + if err = (&webhook.ConfigMap{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "ConfigMap") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/go.mod b/go.mod index b3e5cc62..7034ff12 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ require ( github.com/stretchr/testify v1.8.1 golang.org/x/crypto v0.6.0 golang.org/x/sync v0.1.0 - gopkg.in/src-d/go-git.v4 v4.13.1 helm.sh/helm/v3 v3.11.1 k8s.io/api v0.26.1 k8s.io/apiextensions-apiserver v0.26.1 @@ -132,7 +131,6 @@ require ( github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/src-d/gcfg v1.4.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect diff --git a/go.sum b/go.sum index de8f8e93..47b85705 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,6 @@ github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBY github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -126,7 +124,6 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= @@ -398,7 +395,6 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -416,7 +412,6 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -526,7 +521,6 @@ github.com/operator-framework/helm-operator-plugins v0.0.11/go.mod h1:X5HB7sPe/c github.com/operator-framework/operator-lib v0.11.0 h1:eYzqpiOfq9WBI4Trddisiq/X9BwCisZd3rIzmHRC9Z8= github.com/operator-framework/operator-lib v0.11.0/go.mod h1:RpyKhFAoG6DmKTDIwMuO6pI3LRc8IE9rxEYWy476o6g= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -581,7 +575,6 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= @@ -608,13 +601,10 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -629,7 +619,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= @@ -684,7 +673,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -816,7 +804,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -919,7 +906,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1093,12 +1079,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= diff --git a/internal/provisioner/bundle/bundle.go b/internal/provisioner/bundle/bundle.go index 66c192db..cab9e871 100644 --- a/internal/provisioner/bundle/bundle.go +++ b/internal/provisioner/bundle/bundle.go @@ -13,6 +13,7 @@ import ( apimacherrors "k8s.io/apimachinery/pkg/util/errors" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" crfinalizer "sigs.k8s.io/controller-runtime/pkg/finalizer" "sigs.k8s.io/controller-runtime/pkg/log" @@ -57,7 +58,7 @@ func WithFinalizers(f crfinalizer.Finalizers) Option { } } -func SetupProvisioner(mgr manager.Manager, opts ...Option) error { +func SetupProvisioner(mgr manager.Manager, systemNsCache cache.Cache, systemNamespace string, opts ...Option) error { b := &bundleProvisioner{ cl: mgr.GetClient(), } @@ -82,7 +83,8 @@ func SetupProvisioner(mgr manager.Manager, opts ...Option) error { // The default image source unpacker creates Pod's ownerref'd to its bundle, so // we need to watch pods to ensure we reconcile events coming from these // pods. - Watches(&crsource.Kind{Type: &corev1.Pod{}}, util.MapOwneeToOwnerProvisionerHandler(context.Background(), mgr.GetClient(), l, b.provisionerID, &rukpakv1alpha1.Bundle{})). + Watches(crsource.NewKindWithCache(&corev1.Pod{}, systemNsCache), util.MapOwneeToOwnerProvisionerHandler(context.Background(), mgr.GetClient(), l, b.provisionerID, &rukpakv1alpha1.Bundle{})). + Watches(crsource.NewKindWithCache(&corev1.ConfigMap{}, systemNsCache), util.MapConfigMapToBundlesHandler(context.Background(), mgr.GetClient(), systemNamespace, b.provisionerID)). Complete(b) } @@ -127,6 +129,7 @@ type bundleProvisioner struct { //+kubebuilder:rbac:groups=core.rukpak.io,resources=bundles/finalizers,verbs=update //+kubebuilder:rbac:verbs=get,urls=/bundles/*;/uploads/* //+kubebuilder:rbac:groups=core,resources=pods,verbs=list;watch;create;delete +//+kubebuilder:rbac:groups=core,resources=configmaps,verbs=list;watch //+kubebuilder:rbac:groups=core,resources=pods/log,verbs=get //+kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create //+kubebuilder:rbac:groups=authorization.k8s.io,resources=subjectaccessreviews,verbs=create diff --git a/internal/source/configmaps.go b/internal/source/configmaps.go new file mode 100644 index 00000000..9b1f4d86 --- /dev/null +++ b/internal/source/configmaps.go @@ -0,0 +1,87 @@ +package source + +import ( + "context" + "fmt" + "path/filepath" + "testing/fstest" + + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" +) + +type ConfigMaps struct { + Reader client.Reader + ConfigMapNamespace string +} + +func (o *ConfigMaps) Unpack(ctx context.Context, bundle *rukpakv1alpha1.Bundle) (*Result, error) { + if bundle.Spec.Source.Type != rukpakv1alpha1.SourceTypeConfigMaps { + return nil, fmt.Errorf("bundle source type %q not supported", bundle.Spec.Source.Type) + } + if bundle.Spec.Source.ConfigMaps == nil { + return nil, fmt.Errorf("bundle source configmaps configuration is unset") + } + + configMapSources := bundle.Spec.Source.ConfigMaps + + bundleFS := fstest.MapFS{} + for _, cmSource := range configMapSources { + cmName := cmSource.ConfigMap.Name + dir := filepath.Clean(cmSource.Path) + + // Check for paths outside the bundle root is handled in the bundle validation webhook + // if strings.HasPrefix("../", dir) { ... } + + var cm corev1.ConfigMap + if err := o.Reader.Get(ctx, client.ObjectKey{Name: cmName, Namespace: o.ConfigMapNamespace}, &cm); err != nil { + return nil, fmt.Errorf("get configmap %s/%s: %v", o.ConfigMapNamespace, cmName, err) + } + + // TODO: move configmaps immutability check to webhooks + // This would require the webhook to lookup referenced configmaps. + // We would need to implement this in two places: + // 1. During bundle create: + // - if referenced configmap already exists, ensure it is immutable + // - if referenced configmap does not exist, allow the bundle to be created anyway + // 2. During configmap create: + // - if the configmap is referenced by a bundle, ensure it is immutable + // - if not referenced by a bundle, allow the configmap to be created. + if cm.Immutable == nil || *cm.Immutable == false { + return nil, fmt.Errorf("configmap %s/%s is mutable: all bundle configmaps must be immutable", o.ConfigMapNamespace, cmName) + } + + files := map[string][]byte{} + for filename, data := range cm.Data { + files[filename] = []byte(data) + } + for filename, data := range cm.BinaryData { + files[filename] = data + } + + seenFilepaths := map[string]string{} + for filename, data := range files { + filepath := filepath.Join(dir, filename) + + // forbid multiple configmaps in the list from referencing the same destination file. + if existingCmName, ok := seenFilepaths[filepath]; ok { + return nil, fmt.Errorf("configmap %s/%s contains path %q which is already referenced by configmap %s/%s", + o.ConfigMapNamespace, cmName, filepath, o.ConfigMapNamespace, existingCmName) + } + seenFilepaths[filepath] = cmName + bundleFS[filepath] = &fstest.MapFile{ + Data: data, + } + } + } + + resolvedSource := &rukpakv1alpha1.BundleSource{ + Type: rukpakv1alpha1.SourceTypeConfigMaps, + ConfigMaps: bundle.Spec.Source.DeepCopy().ConfigMaps, + } + + message := generateMessage("configMaps") + return &Result{Bundle: bundleFS, ResolvedSource: resolvedSource, State: StateUnpacked, Message: message}, nil +} diff --git a/internal/source/git.go b/internal/source/git.go index 7f6cb69f..4a47afcd 100644 --- a/internal/source/git.go +++ b/internal/source/git.go @@ -18,9 +18,9 @@ import ( "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport/http" + sshgit "github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/go-git/go-git/v5/storage/memory" "golang.org/x/crypto/ssh" - sshgit "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/internal/source/local.go b/internal/source/local.go deleted file mode 100644 index d5f4c9d5..00000000 --- a/internal/source/local.go +++ /dev/null @@ -1,80 +0,0 @@ -package source - -import ( - "context" - "fmt" - "io/fs" - "path/filepath" - - rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" - "github.com/operator-framework/rukpak/internal/util" - - "github.com/go-git/go-billy/v5/memfs" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type Local struct { - client.Client - // reader queries the API server directly - reader client.Reader -} - -func (o *Local) Unpack(ctx context.Context, bundle *rukpakv1alpha1.Bundle) (*Result, error) { - if bundle.Spec.Source.Type != rukpakv1alpha1.SourceTypeLocal { - return nil, fmt.Errorf("bundle source type %q not supported", bundle.Spec.Source.Type) - } - if bundle.Spec.Source.Local == nil { - return nil, fmt.Errorf("bundle source local configuration is unset") - } - - configMapRef := bundle.Spec.Source.Local.ConfigMapRef - - var cm corev1.ConfigMap - if err := o.reader.Get(ctx, client.ObjectKey{Name: configMapRef.Name, Namespace: configMapRef.Namespace}, &cm); err != nil { - return nil, fmt.Errorf("could not find configmap %s/%s on the cluster", configMapRef.Namespace, configMapRef.Name) - } - - // If the configmap is empty, return early - if len(cm.Data) == 0 { - return nil, fmt.Errorf("configmap %s/%s is empty: at least one object is required", configMapRef.Namespace, configMapRef.Name) - } - - var memFS = memfs.New() - for filename, contents := range cm.Data { - file, err := memFS.Create(filepath.Join("manifests", filename)) - if err != nil { - return nil, fmt.Errorf("creating filesystem from configmap: %s", err) - } - _, err = file.Write([]byte(contents)) - if err != nil { - return nil, fmt.Errorf("creating filesystem from configmap: %s", err) - } - } - - // Add an ownerref to the configmap based on the Bundle - var ownerref = metav1.NewControllerRef(bundle, bundle.GroupVersionKind()) - cm.OwnerReferences = append(cm.OwnerReferences, *ownerref) - // Update labels to reflect this ConfigMap is now managed by rukpak - var labels = cm.GetLabels() - if labels == nil { - labels = make(map[string]string) - } - labels[util.CoreOwnerKindKey] = rukpakv1alpha1.BundleKind - labels[util.CoreOwnerNameKey] = bundle.GetName() - - if err := o.Update(ctx, &cm); err != nil { - return nil, fmt.Errorf("could not update configmap with bundle ownerreference: %s", err) - } - - var bundleFS fs.FS = &billyFS{memFS} - resolvedSource := &rukpakv1alpha1.BundleSource{ - Type: rukpakv1alpha1.SourceTypeLocal, - Local: bundle.Spec.Source.Local.DeepCopy(), - } - - message := generateMessage("local") - - return &Result{Bundle: bundleFS, ResolvedSource: resolvedSource, State: StateUnpacked, Message: message}, nil -} diff --git a/internal/source/unpacker.go b/internal/source/unpacker.go index 64da643f..f68af841 100644 --- a/internal/source/unpacker.go +++ b/internal/source/unpacker.go @@ -10,7 +10,7 @@ import ( "time" "k8s.io/client-go/kubernetes" - ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cluster" rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" ) @@ -101,8 +101,8 @@ func (s *unpacker) Unpack(ctx context.Context, bundle *rukpakv1alpha1.Bundle) (* // source types. // // TODO: refactor NewDefaultUnpacker due to growing parameter list -func NewDefaultUnpacker(mgr ctrl.Manager, namespace, unpackImage string, baseUploadManagerURL string, rootCAs *x509.CertPool) (Unpacker, error) { - cfg := mgr.GetConfig() +func NewDefaultUnpacker(systemNsCluster cluster.Cluster, namespace, unpackImage string, baseUploadManagerURL string, rootCAs *x509.CertPool) (Unpacker, error) { + cfg := systemNsCluster.GetConfig() kubeClient, err := kubernetes.NewForConfig(cfg) if err != nil { return nil, err @@ -116,26 +116,26 @@ func NewDefaultUnpacker(mgr ctrl.Manager, namespace, unpackImage string, baseUpl httpTransport.TLSClientConfig.RootCAs = rootCAs return NewUnpacker(map[rukpakv1alpha1.SourceType]Unpacker{ rukpakv1alpha1.SourceTypeImage: &Image{ - Client: mgr.GetClient(), + Client: systemNsCluster.GetClient(), KubeClient: kubeClient, PodNamespace: namespace, UnpackImage: unpackImage, }, rukpakv1alpha1.SourceTypeGit: &Git{ - Reader: mgr.GetAPIReader(), + Reader: systemNsCluster.GetClient(), SecretNamespace: namespace, }, - rukpakv1alpha1.SourceTypeLocal: &Local{ - Client: mgr.GetClient(), - reader: mgr.GetAPIReader(), + rukpakv1alpha1.SourceTypeConfigMaps: &ConfigMaps{ + Reader: systemNsCluster.GetClient(), + ConfigMapNamespace: namespace, }, rukpakv1alpha1.SourceTypeUpload: &Upload{ baseDownloadURL: baseUploadManagerURL, - bearerToken: mgr.GetConfig().BearerToken, + bearerToken: systemNsCluster.GetConfig().BearerToken, client: http.Client{Timeout: uploadClientTimeout, Transport: httpTransport}, }, rukpakv1alpha1.SourceTypeHTTP: &HTTP{ - Reader: mgr.GetAPIReader(), + Reader: systemNsCluster.GetClient(), SecretNamespace: namespace, }, }), nil diff --git a/internal/util/util.go b/internal/util/util.go index d9d9a563..a8f43c9a 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -13,6 +13,7 @@ import ( "time" "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -220,6 +221,37 @@ func MapBundleToBundleDeploymentHandler(ctx context.Context, cl client.Client, l return []reconcile.Request{{NamespacedName: client.ObjectKeyFromObject(managingBD)}} } } +func MapConfigMapToBundles(ctx context.Context, cl client.Client, cmNamespace string, cm corev1.ConfigMap) []*rukpakv1alpha1.Bundle { + bundleList := &rukpakv1alpha1.BundleList{} + if err := cl.List(ctx, bundleList); err != nil { + return nil + } + var bs []*rukpakv1alpha1.Bundle + for _, b := range bundleList.Items { + b := b + for _, cmSource := range b.Spec.Source.ConfigMaps { + cmName := cmSource.ConfigMap.Name + if cm.Name == cmName && cm.Namespace == cmNamespace { + bs = append(bs, &b) + } + } + } + return bs +} +func MapConfigMapToBundlesHandler(ctx context.Context, cl client.Client, configMapNamespace string, provisionerClassName string) handler.EventHandler { + return handler.EnqueueRequestsFromMapFunc(func(object client.Object) []reconcile.Request { + cm := object.(*corev1.ConfigMap) + var requests []reconcile.Request + matchingBundles := MapConfigMapToBundles(ctx, cl, configMapNamespace, *cm) + for _, b := range matchingBundles { + if b.Spec.ProvisionerClassName != provisionerClassName { + continue + } + requests = append(requests, reconcile.Request{NamespacedName: client.ObjectKeyFromObject(b)}) + } + return requests + }) +} // GetBundlesForBundleDeploymentSelector is responsible for returning a list of // Bundle resource that exist on cluster that match the label selector specified diff --git a/internal/webhook/configmaps.go b/internal/webhook/configmaps.go new file mode 100644 index 00000000..e2e411c0 --- /dev/null +++ b/internal/webhook/configmaps.go @@ -0,0 +1,55 @@ +package webhook + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" +) + +//+kubebuilder:rbac:groups=core.rukpak.io,resources=bundles,verbs=list;watch +//+kubebuilder:webhook:path=/validate-core-v1-configmap,mutating=false,failurePolicy=fail,sideEffects=None,groups="",resources=configmaps,verbs=create;delete,versions=v1,name=vconfigmaps.core.rukpak.io,admissionReviewVersions=v1 + +type ConfigMap struct { + cl client.Client +} + +func (w *ConfigMap) ValidateCreate(_ context.Context, _ runtime.Object) error { + return nil +} + +func (w *ConfigMap) ValidateUpdate(_ context.Context, _, _ runtime.Object) error { + return nil +} + +func (w *ConfigMap) ValidateDelete(ctx context.Context, obj runtime.Object) error { + cm := obj.(*corev1.ConfigMap) + + bundleList := &rukpakv1alpha1.BundleList{} + if err := w.cl.List(ctx, bundleList); err != nil { + return err + } + for _, b := range bundleList.Items { + for _, cmSource := range b.Spec.Source.ConfigMaps { + if cmSource.ConfigMap.Name == cm.Name { + return fmt.Errorf("configmap %q is in-use by bundle %q", cm.Name, b.Name) + } + } + } + return nil +} + +func (w *ConfigMap) SetupWebhookWithManager(mgr ctrl.Manager) error { + w.cl = mgr.GetClient() + mgr.GetWebhookServer().Register("/validate-core-v1-configmap", admission.WithCustomValidator(&corev1.ConfigMap{}, w).WithRecoverPanic(true)) + return nil +} + +var _ webhook.CustomValidator = &ConfigMap{} diff --git a/manifests/apis/crds/core.rukpak.io_bundledeployments.yaml b/manifests/apis/crds/core.rukpak.io_bundledeployments.yaml index e79f3963..5d911a4d 100644 --- a/manifests/apis/crds/core.rukpak.io_bundledeployments.yaml +++ b/manifests/apis/crds/core.rukpak.io_bundledeployments.yaml @@ -98,6 +98,32 @@ spec: description: Source defines the configuration for the underlying Bundle content. properties: + configMaps: + description: ConfigMaps is a list of config map references + and their relative directory paths that represent a + bundle filesystem. + items: + properties: + configMap: + description: ConfigMap is a reference to a configmap + in the rukpak system namespace + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + path: + description: Path is the relative directory path + within the bundle where the files from the configmap + will be present when the bundle is unpacked. + type: string + required: + - configMap + type: object + type: array git: description: Git is the git repository that backs the content of this Bundle. @@ -239,23 +265,6 @@ spec: required: - ref type: object - local: - description: Local is a reference to a local object in - the cluster. - properties: - configMap: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - required: - - configMap - type: object type: description: Type defines the kind of Bundle content being sourced. diff --git a/manifests/apis/crds/core.rukpak.io_bundles.yaml b/manifests/apis/crds/core.rukpak.io_bundles.yaml index 81c5ea65..95f497d4 100644 --- a/manifests/apis/crds/core.rukpak.io_bundles.yaml +++ b/manifests/apis/crds/core.rukpak.io_bundles.yaml @@ -62,6 +62,29 @@ spec: description: Source defines the configuration for the underlying Bundle content. properties: + configMaps: + description: ConfigMaps is a list of config map references and + their relative directory paths that represent a bundle filesystem. + items: + properties: + configMap: + description: ConfigMap is a reference to a configmap in + the rukpak system namespace + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + path: + description: Path is the relative directory path within + the bundle where the files from the configmap will be + present when the bundle is unpacked. + type: string + required: + - configMap + type: object + type: array git: description: Git is the git repository that backs the content of this Bundle. @@ -192,22 +215,6 @@ spec: required: - ref type: object - local: - description: Local is a reference to a local object in the cluster. - properties: - configMap: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - required: - - configMap - type: object type: description: Type defines the kind of Bundle content being sourced. type: string @@ -305,6 +312,29 @@ spec: type: string resolvedSource: properties: + configMaps: + description: ConfigMaps is a list of config map references and + their relative directory paths that represent a bundle filesystem. + items: + properties: + configMap: + description: ConfigMap is a reference to a configmap in + the rukpak system namespace + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + path: + description: Path is the relative directory path within + the bundle where the files from the configmap will be + present when the bundle is unpacked. + type: string + required: + - configMap + type: object + type: array git: description: Git is the git repository that backs the content of this Bundle. @@ -435,22 +465,6 @@ spec: required: - ref type: object - local: - description: Local is a reference to a local object in the cluster. - properties: - configMap: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - required: - - configMap - type: object type: description: Type defines the kind of Bundle content being sourced. type: string diff --git a/manifests/apis/crds/patches/bundle_validation.yaml b/manifests/apis/crds/patches/bundle_validation.yaml index 971d42b7..050c7eb0 100644 --- a/manifests/apis/crds/patches/bundle_validation.yaml +++ b/manifests/apis/crds/patches/bundle_validation.yaml @@ -15,7 +15,7 @@ - required: - image - required: - - local + - configMaps - required: - upload - required: diff --git a/manifests/apis/webhooks/kustomization.yml b/manifests/apis/webhooks/kustomization.yml index 412d7d98..96496a9c 100644 --- a/manifests/apis/webhooks/kustomization.yml +++ b/manifests/apis/webhooks/kustomization.yml @@ -8,12 +8,15 @@ resources: - resources/certificate.yaml - resources/deployment.yaml - resources/webhook.yaml + - resources/cluster_role.yaml + - resources/cluster_role_binding.yaml configurations: - kustomizeconfig.yaml patchesStrategicMerge: - patches/cainjection.yaml +- patches/namespace_selectors.yaml vars: - name: CERTIFICATE_NAMESPACE # namespace of the certificate CR diff --git a/manifests/apis/webhooks/patches/namespace_selectors.yaml b/manifests/apis/webhooks/patches/namespace_selectors.yaml new file mode 100644 index 00000000..e0da085e --- /dev/null +++ b/manifests/apis/webhooks/patches/namespace_selectors.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration +webhooks: + - name: vconfigmaps.core.rukpak.io + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: rukpak-system diff --git a/manifests/apis/webhooks/resources/cluster_role.yaml b/manifests/apis/webhooks/resources/cluster_role.yaml new file mode 100644 index 00000000..1e620ef9 --- /dev/null +++ b/manifests/apis/webhooks/resources/cluster_role.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: webhooks-admin +rules: +- apiGroups: + - core.rukpak.io + resources: + - bundles + verbs: + - list + - watch diff --git a/manifests/apis/webhooks/resources/cluster_role_binding.yaml b/manifests/apis/webhooks/resources/cluster_role_binding.yaml new file mode 100644 index 00000000..0a49811d --- /dev/null +++ b/manifests/apis/webhooks/resources/cluster_role_binding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: webhooks-admin +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: webhooks-admin +subjects: + - apiGroup: "" + kind: ServiceAccount + name: rukpak-webhooks-admin + namespace: rukpak-system diff --git a/manifests/apis/webhooks/resources/webhook.yaml b/manifests/apis/webhooks/resources/webhook.yaml index fb519b68..d59c5a5a 100644 --- a/manifests/apis/webhooks/resources/webhook.yaml +++ b/manifests/apis/webhooks/resources/webhook.yaml @@ -25,3 +25,23 @@ webhooks: resources: - bundles sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-core-v1-configmap + failurePolicy: Fail + name: vconfigmaps.core.rukpak.io + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - DELETE + resources: + - configmaps + sideEffects: None diff --git a/manifests/core/resources/cluster_role.yaml b/manifests/core/resources/cluster_role.yaml index 66fb3192..91776366 100644 --- a/manifests/core/resources/cluster_role.yaml +++ b/manifests/core/resources/cluster_role.yaml @@ -28,6 +28,13 @@ rules: - subjectaccessreviews verbs: - create +- apiGroups: + - "" + resources: + - configmaps + verbs: + - list + - watch - apiGroups: - "" resources: diff --git a/manifests/provisioners/helm/resources/cluster_role.yaml b/manifests/provisioners/helm/resources/cluster_role.yaml index 4bbd48c0..f5983f77 100644 --- a/manifests/provisioners/helm/resources/cluster_role.yaml +++ b/manifests/provisioners/helm/resources/cluster_role.yaml @@ -28,6 +28,13 @@ rules: - subjectaccessreviews verbs: - create +- apiGroups: + - "" + resources: + - configmaps + verbs: + - list + - watch - apiGroups: - "" resources: diff --git a/test/e2e/plain_provisioner_test.go b/test/e2e/plain_provisioner_test.go index bf06d4b0..fe83b2e2 100644 --- a/test/e2e/plain_provisioner_test.go +++ b/test/e2e/plain_provisioner_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/tools/remotecommand" "k8s.io/client-go/util/retry" + "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" @@ -822,7 +823,11 @@ var _ = Describe("plain provisioner bundle", func() { return err } if bundle.Status.Phase != rukpakv1alpha1.PhaseUnpacked { - return errors.New("bundle is not unpacked") + unpackedCondition := meta.FindStatusCondition(bundle.Status.Conditions, rukpakv1alpha1.TypeUnpacked) + if unpackedCondition == nil { + return errors.New("bundle is not unpacked") + } + return fmt.Errorf("bundle is not unpacked: %s", unpackedCondition.Message) } provisionerPods := &corev1.PodList{} @@ -867,10 +872,11 @@ var _ = Describe("plain provisioner bundle", func() { Expect(err).To(BeNil()) configmap = &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: "local-configmap-", + GenerateName: "bundle-configmap-valid-", Namespace: defaultSystemNamespace, }, - Data: data, + Data: data, + Immutable: pointer.Bool(true), } err = c.Create(ctx, configmap) Expect(err).To(BeNil()) @@ -881,13 +887,11 @@ var _ = Describe("plain provisioner bundle", func() { Spec: rukpakv1alpha1.BundleSpec{ ProvisionerClassName: plain.ProvisionerID, Source: rukpakv1alpha1.BundleSource{ - Type: rukpakv1alpha1.SourceTypeLocal, - Local: &rukpakv1alpha1.LocalSource{ - ConfigMapRef: &rukpakv1alpha1.ConfigMapRef{ - Name: configmap.ObjectMeta.Name, - Namespace: defaultSystemNamespace, - }, - }, + Type: rukpakv1alpha1.SourceTypeConfigMaps, + ConfigMaps: []rukpakv1alpha1.ConfigMapSource{{ + ConfigMap: corev1.LocalObjectReference{Name: configmap.ObjectMeta.Name}, + Path: "manifests", + }}, }, }, } @@ -896,8 +900,10 @@ var _ = Describe("plain provisioner bundle", func() { }) AfterEach(func() { - err := c.Delete(ctx, bundle) - Expect(client.IgnoreNotFound(err)).To(BeNil()) + Expect(client.IgnoreNotFound(c.Delete(ctx, bundle))).To(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(c.Delete(ctx, configmap)) + }).Should(Succeed()) }) It("Can create and unpack the bundle successfully", func() { @@ -906,24 +912,14 @@ var _ = Describe("plain provisioner bundle", func() { return err } if bundle.Status.Phase != rukpakv1alpha1.PhaseUnpacked { - return errors.New("bundle is not unpacked") + unpackedCondition := meta.FindStatusCondition(bundle.Status.Conditions, rukpakv1alpha1.TypeUnpacked) + if unpackedCondition == nil { + return errors.New("bundle is not unpacked") + } + return fmt.Errorf("bundle is not unpacked: %s", unpackedCondition.Message) } return nil }).Should(BeNil()) - - By("deleting the configmap after the bundle is deleted") - err := c.Delete(ctx, bundle) - Expect(err).To(BeNil()) - - Eventually(func() (bool, error) { - if err := c.Get(ctx, client.ObjectKeyFromObject(configmap), configmap); err != nil { - if apierrors.IsNotFound(err) { - return true, nil - } - return false, err - } - return false, nil - }).Should(BeTrue()) }) }) @@ -942,13 +938,11 @@ var _ = Describe("plain provisioner bundle", func() { Spec: rukpakv1alpha1.BundleSpec{ ProvisionerClassName: plain.ProvisionerID, Source: rukpakv1alpha1.BundleSource{ - Type: rukpakv1alpha1.SourceTypeLocal, - Local: &rukpakv1alpha1.LocalSource{ - ConfigMapRef: &rukpakv1alpha1.ConfigMapRef{ - Name: "non-exist", - Namespace: defaultSystemNamespace, - }, - }, + Type: rukpakv1alpha1.SourceTypeConfigMaps, + ConfigMaps: []rukpakv1alpha1.ConfigMapSource{{ + ConfigMap: corev1.LocalObjectReference{Name: "non-exist"}, + Path: "manifests", + }}, }, }, } @@ -973,7 +967,7 @@ var _ = Describe("plain provisioner bundle", func() { WithTransform(func(c *metav1.Condition) metav1.ConditionStatus { return c.Status }, Equal(metav1.ConditionFalse)), WithTransform(func(c *metav1.Condition) string { return c.Reason }, Equal(rukpakv1alpha1.ReasonUnpackFailed)), WithTransform(func(c *metav1.Condition) string { return c.Message }, - ContainSubstring(fmt.Sprintf("source bundle content: could not find configmap %s/%s on the cluster", defaultSystemNamespace, "non-exist"))), + ContainSubstring(fmt.Sprintf("source bundle content: get configmap %[1]s/%[2]s: ConfigMap %[2]q not found", defaultSystemNamespace, "non-exist"))), )) }) }) @@ -1005,10 +999,11 @@ var _ = Describe("plain provisioner bundle", func() { Expect(err).To(BeNil()) configmap = &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: "local-configmap-", + GenerateName: "bundle-configmap-invalid-", Namespace: defaultSystemNamespace, }, - Data: data, + Data: data, + Immutable: pointer.Bool(true), } err = c.Create(ctx, configmap) Expect(err).To(BeNil()) @@ -1019,13 +1014,11 @@ var _ = Describe("plain provisioner bundle", func() { Spec: rukpakv1alpha1.BundleSpec{ ProvisionerClassName: plain.ProvisionerID, Source: rukpakv1alpha1.BundleSource{ - Type: rukpakv1alpha1.SourceTypeLocal, - Local: &rukpakv1alpha1.LocalSource{ - ConfigMapRef: &rukpakv1alpha1.ConfigMapRef{ - Name: configmap.ObjectMeta.Name, - Namespace: defaultSystemNamespace, - }, - }, + Type: rukpakv1alpha1.SourceTypeConfigMaps, + ConfigMaps: []rukpakv1alpha1.ConfigMapSource{{ + ConfigMap: corev1.LocalObjectReference{Name: configmap.ObjectMeta.Name}, + Path: "manifests", + }}, }, }, } @@ -1034,10 +1027,10 @@ var _ = Describe("plain provisioner bundle", func() { }) AfterEach(func() { - err := c.Delete(ctx, bundle) - Expect(client.IgnoreNotFound(err)).To(BeNil()) - err = c.Delete(ctx, configmap) - Expect(client.IgnoreNotFound(err)).To(BeNil()) + Expect(client.IgnoreNotFound(c.Delete(ctx, bundle))).To(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(c.Delete(ctx, configmap)) + }).Should(Succeed()) }) It("checks the bundle's phase gets failing", func() { By("waiting until the bundle is reporting Failing state")