diff --git a/charts/greenhouse/Chart.yaml b/charts/greenhouse/Chart.yaml index 24640344f..5ee101861 100644 --- a/charts/greenhouse/Chart.yaml +++ b/charts/greenhouse/Chart.yaml @@ -5,7 +5,7 @@ apiVersion: v2 name: greenhouse description: A Helm chart for deploying greenhouse type: application -version: 0.7.1 +version: 0.7.2 appVersion: "0.1.0" dependencies: diff --git a/charts/greenhouse/templates/plugin-ingress-nginx.yaml b/charts/greenhouse/templates/plugin-ingress-nginx.yaml index a087d0ab4..02c8b94ed 100644 --- a/charts/greenhouse/templates/plugin-ingress-nginx.yaml +++ b/charts/greenhouse/templates/plugin-ingress-nginx.yaml @@ -18,6 +18,9 @@ spec: value: true - name: controller.scope.enabled value: false + - name: controller.config + value: + allow-cross-namespace-resources: true {{ if .Values.ingress.loadBalancerIP }} - name: controller.service.loadBalancerIP value: {{ .Values.ingress.loadBalancerIP | quote }} diff --git a/go.mod b/go.mod index b2e046011..fc854819e 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ replace ( k8s.io/client-go => k8s.io/client-go v0.31.5 k8s.io/component-base => k8s.io/component-base v0.31.5 k8s.io/kubectl => k8s.io/kubectl v0.31.5 - sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.19.4 + sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.19.5 ) require ( @@ -44,8 +44,7 @@ require ( k8s.io/client-go v0.31.5 k8s.io/kubectl v0.31.5 k8s.io/utils v0.0.0-20241210054802-24370beab758 - sigs.k8s.io/controller-runtime v0.19.4 - sigs.k8s.io/e2e-framework v0.5.0 + sigs.k8s.io/controller-runtime v0.19.5 sigs.k8s.io/kind v0.26.0 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index 22e4090f4..b89ed1341 100644 --- a/go.sum +++ b/go.sum @@ -722,10 +722,8 @@ k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJ k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.6 h1:z8cmxQXBU8yZ4mkytWqXfo6tZcamPwjsuxYU81xJ8Lk= oras.land/oras-go v1.2.6/go.mod h1:OVPc1PegSEe/K8YiLfosrlqlqTN9PUyFvOw5Y9gwrT8= -sigs.k8s.io/controller-runtime v0.19.4 h1:SUmheabttt0nx8uJtoII4oIP27BVVvAKFvdvGFwV/Qo= -sigs.k8s.io/controller-runtime v0.19.4/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/e2e-framework v0.5.0 h1:YLhk8R7EHuTFQAe6Fxy5eBzn5Vb+yamR5u8MH1Rq3cE= -sigs.k8s.io/e2e-framework v0.5.0/go.mod h1:jJSH8u2RNmruekUZgHAtmRjb5Wj67GErli9UjLSY7Zc= +sigs.k8s.io/controller-runtime v0.19.5 h1:rsE2cRYe0hK/rAAwiS1bwqgEcgCxTz9lavs3FMgLW0c= +sigs.k8s.io/controller-runtime v0.19.5/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.26.0 h1:8fS6I0Q5WGlmLprSpH0DarlOSdcsv0txnwc93J2BP7M= diff --git a/pkg/clientutil/finalizer.go b/pkg/clientutil/finalizer.go deleted file mode 100644 index 2957fe92d..000000000 --- a/pkg/clientutil/finalizer.go +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -// SPDX-License-Identifier: Apache-2.0 - -package clientutil - -import ( - "context" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -// EnsureFinalizer ensures a finalizer is present on the object. Returns an error on failure. -func EnsureFinalizer(ctx context.Context, c client.Client, o client.Object, finalizer string) error { - if controllerutil.ContainsFinalizer(o, finalizer) { - return nil - } - _, err := Patch(ctx, c, o, func() error { - controllerutil.AddFinalizer(o, finalizer) - return nil - }) - return err -} - -// RemoveFinalizer removes a finalizer from an object. Returns an error on failure. -func RemoveFinalizer(ctx context.Context, c client.Client, o client.Object, finalizer string) error { - if !controllerutil.ContainsFinalizer(o, finalizer) { - return nil - } - _, err := Patch(ctx, c, o, func() error { - controllerutil.RemoveFinalizer(o, finalizer) - return nil - }) - return err -} diff --git a/pkg/controllers/plugin/helm_chart_testing.go b/pkg/controllers/plugin/helm_chart_testing.go index cac074612..fb0bec595 100644 --- a/pkg/controllers/plugin/helm_chart_testing.go +++ b/pkg/controllers/plugin/helm_chart_testing.go @@ -58,7 +58,7 @@ func (r *PluginReconciler) reconcileHelmChartTest(ctx context.Context, plugin *g return &reconcileResult{requeueAfter: result.requeueAfter}, nil } - hasHelmChartTest, err := helm.HelmChartTest(ctx, restClientGetter, plugin) + hasHelmChartTest, err := helm.ChartTest(restClientGetter, plugin) prometheusLabels := prometheus.Labels{ "cluster": plugin.Spec.ClusterName, "plugin": plugin.Name, diff --git a/pkg/controllers/plugin/plugin_controller.go b/pkg/controllers/plugin/plugin_controller.go index fadb8dd6a..a4aa64144 100644 --- a/pkg/controllers/plugin/plugin_controller.go +++ b/pkg/controllers/plugin/plugin_controller.go @@ -81,7 +81,9 @@ func (r *PluginReconciler) SetupWithManager(name string, mgr ctrl.Manager) error WithOptions(controller.Options{ RateLimiter: workqueue.NewTypedMaxOfRateLimiter( workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](30*time.Second, 1*time.Hour), - &workqueue.TypedBucketRateLimiter[reconcile.Request]{Limiter: rate.NewLimiter(rate.Limit(10), 100)})}). + &workqueue.TypedBucketRateLimiter[reconcile.Request]{Limiter: rate.NewLimiter(rate.Limit(10), 100)}), + MaxConcurrentReconciles: 3, + }). For(&greenhousev1alpha1.Plugin{}). // If the release was (manually) modified the secret would have been modified. Reconcile it. Watches(&corev1.Secret{}, @@ -168,7 +170,7 @@ func (r *PluginReconciler) EnsureCreated(ctx context.Context, resource lifecycle reconcileErr := r.reconcileHelmRelease(ctx, restClientGetter, plugin, pluginDefinition) - // PluginStatus, WorkloadStatus and HelmChartTest should be reconciled regardless of Helm reconciliation result. + // PluginStatus, WorkloadStatus and ChartTest should be reconciled regardless of Helm reconciliation result. r.reconcileStatus(ctx, restClientGetter, plugin, pluginDefinition, &plugin.Status) workloadStatusResult, workloadStatusErr := r.reconcilePluginWorkloadStatus(ctx, restClientGetter, plugin, pluginDefinition) diff --git a/pkg/controllers/propagation_reconciler.go b/pkg/controllers/propagation_reconciler.go index e24f096de..9986209b0 100644 --- a/pkg/controllers/propagation_reconciler.go +++ b/pkg/controllers/propagation_reconciler.go @@ -99,7 +99,12 @@ func (r *PropagationReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ctrl.Result{}, err } } - if err := clientutil.RemoveFinalizer(ctx, r.Client, obj, greenhouseapis.FinalizerCleanupPropagatedResource); err != nil { + + _, err := clientutil.Patch(ctx, r.Client, obj, func() error { + controllerutil.RemoveFinalizer(obj, greenhouseapis.FinalizerCleanupPropagatedResource) + return nil + }) + if err != nil { return ctrl.Result{}, err } diff --git a/pkg/helm/helm.go b/pkg/helm/helm.go index 2a2383365..9a2e168aa 100644 --- a/pkg/helm/helm.go +++ b/pkg/helm/helm.go @@ -50,6 +50,9 @@ var ( // IsHelmDebug is configured via a flag and enables extensive debug logging for Helm actions. IsHelmDebug bool + + // greenhouse helm timeout for install and upgrade actions + installUpgradeTimeout = 300 * time.Second ) // driftDetectionInterval is the interval after which a drift detection is performed. @@ -81,7 +84,7 @@ func InstallOrUpgradeHelmChartFromPlugin(ctx context.Context, local client.Clien // Avoid attempts to upgrade a failed release and attempt to resurrect it. if latestRelease.Info != nil && latestRelease.Info.Status == release.StatusFailed { log.FromContext(ctx).Info("attempting to reset release status", "current status", latestRelease.Info.Status.String()) - if err := ResetHelmReleaseStatusToDeployed(ctx, restClientGetter, plugin); err != nil { + if err := ResetHelmReleaseStatusToDeployed(restClientGetter, plugin); err != nil { metrics.UpdateMetrics(plugin, metrics.MetricResultError, metrics.MetricReasonUpgradeFailed) return err } @@ -112,8 +115,8 @@ func InstallOrUpgradeHelmChartFromPlugin(ctx context.Context, local client.Clien return nil } -// HelmChartTest to do helm test on the plugin -func HelmChartTest(ctx context.Context, restClientGetter genericclioptions.RESTClientGetter, plugin *greenhousev1alpha1.Plugin) (bool, error) { +// ChartTest to do helm test on the plugin +func ChartTest(restClientGetter genericclioptions.RESTClientGetter, plugin *greenhousev1alpha1.Plugin) (bool, error) { var hasTestHook bool cfg, err := newHelmAction(restClientGetter, plugin.Spec.ReleaseNamespace) if err != nil { @@ -231,7 +234,7 @@ func DiffChartToDeployedResources(ctx context.Context, local client.Client, rest } // ResetHelmReleaseStatusToDeployed resets the status of the release to deployed using a rollback. -func ResetHelmReleaseStatusToDeployed(ctx context.Context, restClientGetter genericclioptions.RESTClientGetter, plugin *greenhousev1alpha1.Plugin) error { +func ResetHelmReleaseStatusToDeployed(restClientGetter genericclioptions.RESTClientGetter, plugin *greenhousev1alpha1.Plugin) error { r, err := getLatestUpgradeableRelease(restClientGetter, plugin) if err != nil { return err @@ -353,6 +356,7 @@ func upgradeRelease(ctx context.Context, local client.Client, restClientGetter g upgradeAction.Namespace = plugin.Spec.ReleaseNamespace upgradeAction.DependencyUpdate = true upgradeAction.MaxHistory = 5 + upgradeAction.Timeout = installUpgradeTimeout // set a timeout for the upgrade to not be stuck in pending state upgradeAction.Description = pluginDefinition.Spec.Version helmChart, err := loadHelmChart(&upgradeAction.ChartPathOptions, pluginDefinition.Spec.HelmChart, settings) @@ -365,7 +369,7 @@ func upgradeRelease(ctx context.Context, local client.Client, restClientGetter g return err } - helmValues, err := getValuesForHelmChart(ctx, local, helmChart, plugin, false) + helmValues, err := getValuesForHelmChart(ctx, local, helmChart, plugin) if err != nil { return err } @@ -390,6 +394,7 @@ func installRelease(ctx context.Context, local client.Client, restClientGetter g installAction := action.NewInstall(cfg) installAction.ReleaseName = plugin.Name installAction.Namespace = plugin.Spec.ReleaseNamespace + installAction.Timeout = installUpgradeTimeout // set a timeout for the installation to not be stuck in pending state installAction.CreateNamespace = true installAction.DependencyUpdate = true installAction.DryRun = isDryRun @@ -409,7 +414,7 @@ func installRelease(ctx context.Context, local client.Client, restClientGetter g if err := replaceCustomResourceDefinitions(ctx, c, helmChart.CRDObjects(), false); err != nil { return nil, err } - helmValues, err := getValuesForHelmChart(ctx, local, helmChart, plugin, isDryRun) + helmValues, err := getValuesForHelmChart(ctx, local, helmChart, plugin) if err != nil { return nil, err } @@ -517,9 +522,9 @@ func mergeMaps(a, b map[string]interface{}) map[string]interface{} { // getValuesForHelmChart returns a set of values to be used for Helm operations. // The order is important as the values defined in the Helm chart can be overridden by the values defined in the Plugin. -func getValuesForHelmChart(ctx context.Context, c client.Client, helmChart *chart.Chart, plugin *greenhousev1alpha1.Plugin, isDryRun bool) (map[string]interface{}, error) { +func getValuesForHelmChart(ctx context.Context, c client.Client, helmChart *chart.Chart, plugin *greenhousev1alpha1.Plugin) (map[string]interface{}, error) { // Copy the values from the Helm chart ensuring a non-nil map. - helmValues := mergeMaps(make(map[string]interface{}, 0), helmChart.Values) + helmValues := mergeMaps(make(map[string]interface{}), helmChart.Values) // Get values defined in plugin. pluginValues, err := getValuesFromPlugin(ctx, c, plugin) if err != nil { diff --git a/pkg/helm/helm_test.go b/pkg/helm/helm_test.go index 709dcfd48..01a2bc6f9 100644 --- a/pkg/helm/helm_test.go +++ b/pkg/helm/helm_test.go @@ -35,7 +35,7 @@ var _ = Describe("helm package test", func() { When("getting the values for the Helm chart of a plugin", func() { It("should correctly get regular values and overwrite helm values", func() { plugin.Spec.OptionValues = []greenhousesapv1alpha1.PluginOptionValue{*optionValue} - helmValues, err := helm.ExportGetValuesForHelmChart(context.Background(), test.K8sClient, helmChart, plugin, true) + helmValues, err := helm.ExportGetValuesForHelmChart(context.Background(), test.K8sClient, helmChart, plugin) Expect(err).ShouldNot(HaveOccurred(), "there should be no error getting the values") Expect(helmValues).ShouldNot(BeNil(), @@ -50,7 +50,7 @@ var _ = Describe("helm package test", func() { Expect(test.K8sClient.Create(test.Ctx, pluginSecret, &client.CreateOptions{})). Should(Succeed(), "creating an secret should be successful") - helmValues, err := helm.ExportGetValuesForHelmChart(context.Background(), test.K8sClient, helmChart, plugin, true) + helmValues, err := helm.ExportGetValuesForHelmChart(context.Background(), test.K8sClient, helmChart, plugin) Expect(err).ShouldNot(HaveOccurred(), "there should be no error getting the values") Expect(helmValues).ShouldNot(BeNil(), @@ -136,7 +136,7 @@ var _ = Describe("helm package test", func() { }) }) - When("handling a helm chart with CRDs", func() { + When("handling a helm chart with CRDs", Ordered, func() { It("should re-create CRDs from Helm chart when CRD is missing on upgrade", func() { By("installing helm chart") err := helm.InstallOrUpgradeHelmChartFromPlugin(test.Ctx, test.K8sClient, test.RestClientGetter, testPluginWithHelmChartCRDs, plugin) @@ -246,7 +246,7 @@ var _ = Describe("helm package test", func() { var _ = DescribeTable("getting helm values from Plugin", func(defaultValue any, exp any) { helmChart := &chart.Chart{ - Values: make(map[string]interface{}, 0), + Values: make(map[string]interface{}), } pluginWithOptionValue := &greenhousesapv1alpha1.Plugin{ @@ -265,7 +265,7 @@ var _ = DescribeTable("getting helm values from Plugin", func(defaultValue any, }, } - helmValues, err := helm.ExportGetValuesForHelmChart(context.Background(), test.K8sClient, helmChart, pluginWithOptionValue, true) + helmValues, err := helm.ExportGetValuesForHelmChart(context.Background(), test.K8sClient, helmChart, pluginWithOptionValue) Expect(err).ShouldNot(HaveOccurred(), "there should be no error getting the values") Expect(helmValues).ShouldNot(BeNil(), @@ -371,7 +371,7 @@ var _ = Describe("Plugin option checksum", Ordered, func() { Value: test.MustReturnJSONFor("pluginValue1"), }, } - optionValuesEmpty = []greenhousesapv1alpha1.PluginOptionValue{} + optionValuesEmpty []greenhousesapv1alpha1.PluginOptionValue ) BeforeAll(func() { diff --git a/pkg/lifecycle/reconcile.go b/pkg/lifecycle/reconcile.go index 61e955ab3..be67c754f 100644 --- a/pkg/lifecycle/reconcile.go +++ b/pkg/lifecycle/reconcile.go @@ -77,7 +77,7 @@ func Reconcile(ctx context.Context, kubeClient client.Client, namespacedName typ // check whether finalizer is set if !shouldBeDeleted && !hasFinalizer { - return ctrl.Result{}, clientutil.EnsureFinalizer(ctx, kubeClient, runtimeObject, CommonCleanupFinalizer) + return ctrl.Result{}, ensureFinalizer(ctx, kubeClient, runtimeObject, CommonCleanupFinalizer) } var ( @@ -88,7 +88,7 @@ func Reconcile(ctx context.Context, kubeClient client.Client, namespacedName typ // check if the resource is already deleted (a control state to decide whether to remove finalizer) // at this point the remote resource is already cleaned up so garbage collection can be done if isResourceDeleted(runtimeObject) { - err = clientutil.RemoveFinalizer(ctx, kubeClient, runtimeObject, CommonCleanupFinalizer) + err = removeFinalizer(ctx, kubeClient, runtimeObject, CommonCleanupFinalizer) return ctrl.Result{}, client.IgnoreNotFound(err) } // if the resource is not deleted yet, we need to ensure it is deleted @@ -182,3 +182,27 @@ func patchStatus(ctx context.Context, kubeClient client.Client, newObject Runtim } return reconcileError } + +// ensureFinalizer - ensures a finalizer is present on the object. Returns an error on failure. +func ensureFinalizer(ctx context.Context, c client.Client, o client.Object, finalizer string) error { + if controllerutil.ContainsFinalizer(o, finalizer) { + return nil + } + _, err := clientutil.Patch(ctx, c, o, func() error { + controllerutil.AddFinalizer(o, finalizer) + return nil + }) + return err +} + +// removeFinalizer - removes a finalizer from an object. Returns an error on failure. +func removeFinalizer(ctx context.Context, c client.Client, o client.Object, finalizer string) error { + if !controllerutil.ContainsFinalizer(o, finalizer) { + return nil + } + _, err := clientutil.Patch(ctx, c, o, func() error { + controllerutil.RemoveFinalizer(o, finalizer) + return nil + }) + return err +} diff --git a/test/e2e/README.md b/test/e2e/README.md deleted file mode 100644 index 585c4f058..000000000 --- a/test/e2e/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Greenhouse end-to-end testing - -## Framework - -We are using the [k8s sig controller-runtime envtest package](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest). - -Test are written in [Ginkgo](https://onsi.github.io/ginkgo/) making use of the [Gomega](https://onsi.github.io/gomega/) matching/assertion library. We use the same framework for our unit and integration tests. - -```bash -make e2e -``` - -will run the e2e test suite without making assumptions on the infrastructure to test against. - -Leveraging envtest, we will basically have three different test scenarios. The following env vars steer these: - - -| Env Var | Meaning | -| --- | --- | -| `USE_EXISTING_CLUSTER` | If set to `true`, the e2e test suite will not spin up a local apiserver and etcd. Instead, it will expect an existing greenhouse installation on the cluster inferred from the `TEST_KUBECONFIG` environment variable. | -| `TEST_KUBECONFIG` | Required when `USE_EXISTING_CLUSTER` is `true`. Points to the remote cluster the e2e test suite is running against. | -| `INTERNAL_KUBECONFIG` | The path to the kubeconfig file for accessing the Greenhouse cluster itself from the running instance. This is used when `USE_EXISTING_CLUSTER` is set to `true`. KIND makes it necessary to set this separately to the `TEST_KUBECONFIG` as the internal api server address differs to the external. Other setups may not use this. If unset `TEST_KUBECONFIG` is used. | - -## Run everything local a.k.a. `USE_EXISTING_CLUSTER = false` or unset - -Just running the tests via: - -```bash -make e2e-local -``` - -will spin up a local apiserver and etcd together with a local greenhouse controller. The e2e test suite will assert against this setup. - -## Run against an existing greenhouse installation a.k.a. `USE_EXISTING_CLUSTER = true` - -We can run our e2e test suite against a running greenhouse installation by exposing some env vars (also see [envtest package](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest#pkg-constants)): - -```bash -export USE_EXISTING_CLUSTER=true -``` - -This will stop envtest from spinning up a local apiserver and etcd and expect an existing greenhouse installation on the cluster infered from the set `TEST_KUBECONFIG` environment variable: - -```bash -export TEST_KUBECONFIG=/path/to/greenhouse.kubeconfig -``` - -To run the e2e test suite against a remote installation: - -```bash -make e2e-remote -``` - -Test setup asserts `TEST_KUBECONFIG` is set and working and will fail otherwise. - -### Run against a local Greenhouse installation in KIND cluster a.k.a. `USE_EXISTING_CLUSTER = true` and `INTERNAL_KUBECONFIG` set - -We provide a convenience method to run the e2e test suite against a local KIND cluster with a greenhouse installation by running: - -```bash -make e2e-local-cluster -``` - -This will spin up a local KIND cluster, install all relevant CRDs, webhooks and the greenhouse controller. diff --git a/test/e2e/controllers.go b/test/e2e/controllers.go deleted file mode 100644 index ab441099e..000000000 --- a/test/e2e/controllers.go +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -// SPDX-License-Identifier: Apache-2.0 - -//go:build e2e - -package e2e - -import ( - "os" - "time" - - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/cloudoperators/greenhouse/pkg/clientutil" - clustercontrollers "github.com/cloudoperators/greenhouse/pkg/controllers/cluster" - organizationcontrollers "github.com/cloudoperators/greenhouse/pkg/controllers/organization" - plugincontrollers "github.com/cloudoperators/greenhouse/pkg/controllers/plugin" - teamcontrollers "github.com/cloudoperators/greenhouse/pkg/controllers/team" - teammembershipcontrollers "github.com/cloudoperators/greenhouse/pkg/controllers/teammembership" - teamrbaccontrollers "github.com/cloudoperators/greenhouse/pkg/controllers/teamrbac" -) - -const ( - defaultRemoteClusterBearerTokenValidity = 24 * time.Hour - defaultRenewRemoteClusterBearerTokenAfter = 20 * time.Hour -) - -// knownControllers contains all controllers to be registered when starting the e2e test suite - -var knownControllers = map[string]func(controllerName string, mgr ctrl.Manager) error{ - // Organization controllers. - "organizationController": (&organizationcontrollers.OrganizationReconciler{}).SetupWithManager, - "organizationRBAC": (&organizationcontrollers.RBACReconciler{}).SetupWithManager, - "organizationDEX": startOrganizationDexReconciler, - "organizationServiceProxy": (&organizationcontrollers.ServiceProxyReconciler{}).SetupWithManager, - "organizationTeamRoleSeeder": (&organizationcontrollers.TeamRoleSeederReconciler{}).SetupWithManager, - - // Team controllers. - "teamController": (&teamcontrollers.TeamReconciler{}).SetupWithManager, - "teamPropagation": (&teamcontrollers.TeamPropagationReconciler{}).SetupWithManager, - - // TeamMembership controllers. - "teamMembershipPropagation": (&teammembershipcontrollers.TeamMembershipPropagationReconciler{}).SetupWithManager, - - // Team RBAC controllers. - "teamRoleBindingController": (&teamrbaccontrollers.TeamRoleBindingReconciler{}).SetupWithManager, - - // Plugin controllers. - // "pluginPropagation": (&plugincontrollers.PluginPropagationReconciler{}).SetupWithManager, - - // Plugin controllers. - "pluginHelm": (&plugincontrollers.HelmReconciler{ - KubeRuntimeOpts: clientutil.RuntimeOptions{QPS: 5, Burst: 10}, - }).SetupWithManager, - "pluginPreset": (&plugincontrollers.PluginPresetReconciler{}).SetupWithManager, - - // Cluster controllers - "bootStrap": (&clustercontrollers.BootstrapReconciler{}).SetupWithManager, - "clusterReconciler": startClusterReconciler, - // "clusterPropagation": (&clustercontrollers.ClusterPropagationReconciler{}).SetupWithManager, -} - -func startOrganizationDexReconciler(name string, mgr ctrl.Manager) error { - namespace := "greenhouse" - if v, ok := os.LookupEnv("POD_NAMESPACE"); ok { - namespace = v - } - return (&organizationcontrollers.DexReconciler{ - Namespace: namespace, - }).SetupWithManager(name, mgr) -} - -func startClusterReconciler(name string, mgr ctrl.Manager) error { - return (&clustercontrollers.RemoteClusterReconciler{ - RemoteClusterBearerTokenValidity: defaultRemoteClusterBearerTokenValidity, - RenewRemoteClusterBearerTokenAfter: defaultRenewRemoteClusterBearerTokenAfter, - }).SetupWithManager(name, mgr) -} diff --git a/test/e2e/fixtures/fixtures.go b/test/e2e/fixtures/fixtures.go deleted file mode 100644 index bcef03f57..000000000 --- a/test/e2e/fixtures/fixtures.go +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -// SPDX-License-Identifier: Apache-2.0 - -package fixtures - -import ( - "context" - - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - - greenhousev1alpha1 "github.com/cloudoperators/greenhouse/pkg/apis/greenhouse/v1alpha1" - "github.com/cloudoperators/greenhouse/pkg/test" -) - -func CreateNginxPluginDefinition(ctx context.Context, setup *test.TestSetup) *greenhousev1alpha1.PluginDefinition { - return setup.CreatePluginDefinition(ctx, "nginx-18.1.7", - test.WithVersion("18.1.7"), - test.WithHelmChart( - &greenhousev1alpha1.HelmChartReference{ - Name: "bitnamicharts/nginx", - Repository: "oci://registry-1.docker.io", - Version: "18.1.7", - }, - ), - test.AppendPluginOption(greenhousev1alpha1.PluginOption{ - Default: &apiextensionsv1.JSON{Raw: []byte("false")}, - Description: "autoscaling.enabled", - Name: "autoscaling.enabled", - Type: "bool", - }), - test.AppendPluginOption(greenhousev1alpha1.PluginOption{ - Default: &apiextensionsv1.JSON{Raw: []byte("\"\"")}, - Description: "autoscaling.maxReplicas", - Name: "autoscaling.maxReplicas", - Type: "string", - }), - test.AppendPluginOption(greenhousev1alpha1.PluginOption{ - Default: &apiextensionsv1.JSON{Raw: []byte("\"\"")}, - Description: "autoscaling.minReplicas", - Name: "autoscaling.minReplicas", - Type: "string", - }), - test.AppendPluginOption(greenhousev1alpha1.PluginOption{ - Default: &apiextensionsv1.JSON{Raw: []byte("true")}, - Description: "containerSecurityContext.enabled", - Name: "containerSecurityContext.enabled", - Type: "bool", - }), - test.AppendPluginOption(greenhousev1alpha1.PluginOption{ - Default: &apiextensionsv1.JSON{Raw: []byte("1")}, - Description: "replicaCount", - Name: "replicaCount", - Type: "int", - }), - test.AppendPluginOption(greenhousev1alpha1.PluginOption{ - Default: &apiextensionsv1.JSON{Raw: []byte("true")}, - Description: "podSecurityContext.enabled", - Name: "podSecurityContext.enabled", - Type: "bool", - }), - ) -} - -func CreateTestHookPluginDefinition(ctx context.Context, setup *test.TestSetup) *greenhousev1alpha1.PluginDefinition { - return setup.CreatePluginDefinition(ctx, "test-hooks", - test.WithVersion("0.1.0"), - test.WithHelmChart(&greenhousev1alpha1.HelmChartReference{ - Name: "./../../pkg/test/fixtures/testHook", - Repository: "dummy", - Version: "0.1.0", - }), - test.AppendPluginOption(greenhousev1alpha1.PluginOption{ - Name: "hook_enabled", - Type: "bool", - Default: &apiextensionsv1.JSON{Raw: []byte("false")}, - }), - ) -} diff --git a/test/e2e/local-cluster/create_cluster.go b/test/e2e/local-cluster/create_cluster.go deleted file mode 100644 index d108f8738..000000000 --- a/test/e2e/local-cluster/create_cluster.go +++ /dev/null @@ -1,250 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -// SPDX-License-Identifier: Apache-2.0 -package main - -import ( - "bufio" - "context" - "flag" - "fmt" - "os" - "os/exec" - "time" - - "gopkg.in/yaml.v3" - "helm.sh/helm/v3/pkg/action" - "helm.sh/helm/v3/pkg/chart/loader" - "k8s.io/cli-runtime/pkg/genericclioptions" - - "sigs.k8s.io/e2e-framework/support/kind" - - "sigs.k8s.io/controller-runtime/pkg/log" -) - -var ( - kindClusterName string - - kubeconfigName string - kubeconfigInternalName string - - dockerImageRepository string - dockerImageTag string - dockerImagePlatform string - - dockerImageBuildSkip = false - - greenhouseControllerManagerNamespace string - greenhouseControllerManagerRelease string - - greenhouseControllerManagerValuesFilename string - - idProxyNamespace string - idProxyRelease string - idProxyValuesFilename string - - verbose bool -) - -const ( - testTimeout = 3 * time.Minute - testRetryInterval = 3 * time.Second -) - -func init() { - l := log.FromContext(context.Background()) - - flag.StringVar(&kindClusterName, "kindClusterName", "greenhouse-e2e", "Cluster name for creating a new kind cluster") - - flag.StringVar(&kubeconfigName, "kubeconfigName", "e2e.kubeconfig", "kubeconfig file name for connecting to the e2e clusters") - flag.StringVar(&kubeconfigInternalName, "kubeconfigInternalName", "e2e.internal.kubeconfig", "kubeconfig file name for connecting to the e2e clusters from the same Docker network") - - flag.StringVar(&dockerImageRepository, "dockerImageRepository", "greenhouse", "Docker image repository for Greenhouse manager") - flag.StringVar(&dockerImageTag, "dockerImageTag", "e2e-latest", "Docker image tag for Greenhouse manager") - flag.StringVar(&dockerImagePlatform, "dockerImagePlatform", "linux/amd64", "Docker image platform for Greenhouse manager") - flag.BoolVar(&dockerImageBuildSkip, "dockerImageBuildSkip", false, "Skip building the docker image for Greenhouse manager") - - flag.StringVar(&greenhouseControllerManagerNamespace, "greenhouseControllerManagerNamespace", "greenhouse", "Namespace for deploying Greenhouse manager") - flag.StringVar(&greenhouseControllerManagerRelease, "greenhouseControllerManagerRelease", "greenhouse", "Helm release name for deploying Greenhouse manager") - - flag.StringVar(&greenhouseControllerManagerValuesFilename, "greenhouseControllerManagerValuesFile", "./manager.values.yaml", "path to the values file for greenhouse controller manager") - - flag.StringVar(&idProxyNamespace, "gidProxyNamespace", "greenhouse", "Namespace for deploying idproxy") - flag.StringVar(&idProxyRelease, "idProxyRelease", "idproxy", "Helm release name for deploying idproxy") - flag.StringVar(&idProxyValuesFilename, "idProxyValuesFilename", "./idproxy.values.yaml", "path to the values file for idproxy") - - flag.BoolVar(&verbose, "v", false, "enable verbose logging") - - flag.Parse() - - l.Info("configuration loaded", "kindClusterName", kindClusterName, "dockerImageRepository", dockerImageRepository, "dockerImageTag", dockerImageTag, "dockerImageBuildSkip", dockerImageBuildSkip, "kubeconfigName", kubeconfigName, "kubeconfigInternalName", kubeconfigInternalName, "verbose", verbose) -} - -func main() { - ctx := context.Background() - l := log.FromContext(ctx) - - // Create cluster - l.Info("[START] Create kind cluster") - cluster := kind.NewCluster(kindClusterName) - cluster.SetDefaults() - kubeconfig, err := cluster.Create(ctx) - if err != nil { - l.Error(err, "Failed in cluster creation") - os.Exit(1) - } - l.Info("[SUCCESS] Create kind cluster") - - // Export kubeconfig - l.Info("[START] Export kubeconfig files") - f, err := os.Create(kubeconfigName) - if err != nil { - l.Error(err, "Failed in kubeconfig creation") - os.Exit(1) - } - args := []string{"export", "kubeconfig", "--name", kindClusterName, "--kubeconfig", f.Name()} - cmd := exec.Command("kind", args...) - _, err = cmd.Output() - if err != nil { - l.Error(err, "Failed in kubeconfig export") - os.Exit(1) - } - f, err = os.Create(kubeconfigInternalName) - if err != nil { - l.Error(err, "Failed in kubeconfig creation") - os.Exit(1) - } - args = []string{"export", "kubeconfig", "--name", kindClusterName, "--internal", "--kubeconfig", f.Name()} - cmd = exec.Command("kind", args...) - _, err = cmd.Output() - if err != nil { - l.Error(err, "Failed in kubeconfig export") - os.Exit(1) - } - - l.Info("[SUCCESS] Export kubeconfig files") - - // Build image - l.Info("[START] Docker image build") - image := fmt.Sprintf("%s:%s", dockerImageRepository, dockerImageTag) - if !dockerImageBuildSkip { - cmdArgs := []string{"build", "-t", fmt.Sprintf("%s:%s", dockerImageRepository, dockerImageTag), "--platform", dockerImagePlatform, "--no-cache", "./../../../"} - cmd := exec.Command("docker", cmdArgs...) - stderr, err := cmd.StderrPipe() - if err != nil { - l.Error(err, "Failed in docker image build") - os.Exit(1) - } - - err = cmd.Start() - if err != nil { - l.Error(err, "Failed in docker image build") - os.Exit(1) - } - - if verbose { - scanner := bufio.NewScanner(stderr) - - for scanner.Scan() { - m := scanner.Text() - l.Info("[DOCKER BUILD]", m) - } - } - - err = cmd.Wait() - if err != nil { - l.Error(err, "Failed in docker image build") - os.Exit(1) - } - l.Info("[SUCCESS] Docker image build") - } else { - l.Info("[SKIP] Docker image build") - } - - // Load image - l.Info("[START] Docker image load") - err = cluster.LoadImage(ctx, image) - if err != nil { - l.Error(err, "Failed in image load") - os.Exit(1) - } - l.Info("[SUCCESS] Docker image load") - - // Deploy idproxy chart - l.Info("[START] Deploy idproxy chart") - err = installChart(ctx, "./../../../charts/idproxy", idProxyRelease, kubeconfig, idProxyNamespace, idProxyValuesFilename) - if err != nil { - l.Error(err, "Failed in deploy idproxy") - os.Exit(1) - } - l.Info("[SUCCESS] Deploy idproxy chart") - - // Deploy Greenhouse manager - l.Info("[START] Deploy greenhouse manager chart") - err = installChart(ctx, "./../../../charts/manager", greenhouseControllerManagerRelease, kubeconfig, greenhouseControllerManagerNamespace, greenhouseControllerManagerValuesFilename) - if err != nil { - l.Error(err, "Failed in deploy greenhouse") - os.Exit(1) - } - l.Info("[SUCCESS] Deploy greenhouse manager chart") -} - -func installChart(ctx context.Context, dir, release, kubeconfig, namespace, valuesFilename string) error { - l := log.FromContext(ctx) - - chart, err := loader.Load(dir) - if err != nil { - return err - } - - actionConfig := new(action.Configuration) - if err := actionConfig.Init( - &genericclioptions.ConfigFlags{ - KubeConfig: &kubeconfig, - Namespace: &namespace, - }, - namespace, - "secret", - l.V(10).Info, - ); err != nil { - return err - } - - values := map[string]interface{}{} - valuesFile, err := os.ReadFile(valuesFilename) - if err != nil { - return err - } - err = yaml.Unmarshal(valuesFile, &values) - if err != nil { - return err - } - - get := action.NewGet(actionConfig) - _, err = get.Run(release) - if err != nil { - if err.Error() == "release: not found" { - client := action.NewInstall(actionConfig) - client.ReleaseName = release - client.Namespace = namespace - client.CreateNamespace = true - client.Wait = true - client.Timeout = testTimeout - - if _, err := client.RunWithContext(ctx, chart, values); err != nil { - l.Error(err, "chart install") - return err - } - } - } else { - client := action.NewUpgrade(actionConfig) - client.Namespace = namespace - client.Wait = true - client.Timeout = testTimeout - if _, err := client.RunWithContext(ctx, release, chart, values); err != nil { - l.Error(err, "chart upgrade") - return err - } - } - - return nil -} diff --git a/test/e2e/local-cluster/idproxy.values.yaml b/test/e2e/local-cluster/idproxy.values.yaml deleted file mode 100644 index b8dc6dffb..000000000 --- a/test/e2e/local-cluster/idproxy.values.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -# SPDX-License-Identifier: Apache-2.0 - -replicaCount: 0 - -serviceAccount: - create: false \ No newline at end of file diff --git a/test/e2e/local-cluster/manager.values.yaml b/test/e2e/local-cluster/manager.values.yaml deleted file mode 100644 index ace6d01f1..000000000 --- a/test/e2e/local-cluster/manager.values.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -# SPDX-License-Identifier: Apache-2.0 - -global: - dnsDomain: greenhouse.cloudoperators - -controllerManager: - image: - repository: greenhouse - tag: e2e-latest - - replicas: 1 - -alerts: - enabled: false diff --git a/test/e2e/onboard_self_test.go b/test/e2e/onboard_self_test.go deleted file mode 100644 index 6fe08ddcf..000000000 --- a/test/e2e/onboard_self_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -// SPDX-License-Identifier: Apache-2.0 - -//go:build e2e - -package e2e - -import ( - "fmt" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "sigs.k8s.io/controller-runtime/pkg/client" - - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - - greenhouseapis "github.com/cloudoperators/greenhouse/pkg/apis" - "github.com/cloudoperators/greenhouse/pkg/test" - - greenhousev1alpha1 "github.com/cloudoperators/greenhouse/pkg/apis/greenhouse/v1alpha1" -) - -var _ = Describe("OnboardSelf", Ordered, func() { - Context("When onboarding the Greenhouse cluster as a cluster resource", func() { - It("Should create a cluster resource for the Greenhouse cluster", func() { - By("Creating a secret with a valid kubeconfig for a remote cluster") - - selfKubeConfig := test.KubeConfig - // We allow to override the kubeconfig used to access the Greenhouse cluster from itself. - // This is necessary for the setup with KIND, as we need to use a different kubeconfig to access the Api Server from within the cluster - if test.IsUseExistingCluster { - internalKubeConfig, err := test.KubeconfigFromEnvVar("INTERNAL_KUBECONFIG") - if err != nil { - fmt.Print("Onboarding self without INTERNAL_KUBECONFIG --> set when using setup with KIND") - } else { - selfKubeConfig = internalKubeConfig - } - } - - validKubeConfigSecret := corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: corev1.GroupName, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "greenhouse-self", - Namespace: test.TestNamespace, - }, - Data: map[string][]byte{ - greenhouseapis.KubeConfigKey: selfKubeConfig, - }, - Type: greenhouseapis.SecretTypeKubeConfig, - } - Expect(test.K8sClient.Create(test.Ctx, &validKubeConfigSecret, &client.CreateOptions{})).Should(Succeed()) - - By("Checking the resource exists and is ready") - greenhouseCluster := &greenhousev1alpha1.Cluster{} - id := types.NamespacedName{Name: "greenhouse-self", Namespace: test.TestNamespace} - Eventually(func(g Gomega) bool { - g.Expect(test.K8sClient.Get(test.Ctx, id, greenhouseCluster)).Should(Succeed(), "the cluster should have been created") - g.Expect(greenhouseCluster.Spec.AccessMode).To(Equal(greenhousev1alpha1.ClusterAccessModeDirect), "the cluster accessmode should be set to direct") - readyCondition := greenhouseCluster.Status.GetConditionByType(greenhousev1alpha1.ReadyCondition) - g.Expect(readyCondition).ToNot(BeNil()) - g.Expect(readyCondition.Status).To(Equal(metav1.ConditionTrue)) - return true - }).Should(BeTrue(), "getting the cluster should succeed eventually and the cluster accessmode and status should be set correctly") - }) - - It("Should delete the cluster resource correctly", func() { - By("Deleting the cluster resource") - greenhouseCluster := &greenhousev1alpha1.Cluster{} - Expect(test.K8sClient.Get(test.Ctx, types.NamespacedName{Name: "greenhouse-self", Namespace: test.TestNamespace}, greenhouseCluster)).Should(Succeed()) - id := types.NamespacedName{Name: "greenhouse-self", Namespace: test.TestNamespace} - test.MustDeleteCluster(test.Ctx, test.K8sClient, id) - By("Checking the resource is deleted") - Eventually(func(g Gomega) bool { - err := test.K8sClient.Get(test.Ctx, id, greenhouseCluster) - g.Expect(err).To(HaveOccurred()) - g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) - return true - }).Should(BeTrue(), "getting the cluster should fail eventually") - }) - }) -}) diff --git a/test/e2e/plugin_lifecycle_test.go b/test/e2e/plugin_lifecycle_test.go deleted file mode 100644 index 8880b5d38..000000000 --- a/test/e2e/plugin_lifecycle_test.go +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -// SPDX-License-Identifier: Apache-2.0 - -//go:build e2e - -package e2e - -import ( - "strings" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - . "github.com/onsi/gomega/gstruct" - appsv1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - greenhouseapis "github.com/cloudoperators/greenhouse/pkg/apis" - greenhousev1alpha1 "github.com/cloudoperators/greenhouse/pkg/apis/greenhouse/v1alpha1" - "github.com/cloudoperators/greenhouse/pkg/test" - "github.com/cloudoperators/greenhouse/test/e2e/fixtures" -) - -var _ = Describe("PluginLifecycle", Ordered, func() { - Context("without helm hook", func() { - It("should deploy the plugin", func() { - - const clusterName = "test-cluster-a" - setup := test.NewTestSetup(test.Ctx, test.K8sClient, "teamrbac") - secret := setup.CreateSecret(test.Ctx, clusterName, - test.WithSecretType(greenhouseapis.SecretTypeKubeConfig), - test.WithSecretData(map[string][]byte{greenhouseapis.KubeConfigKey: remoteKubeConfig})) - cluster := &greenhousev1alpha1.Cluster{ - ObjectMeta: metav1.ObjectMeta{ - Name: clusterName, - Namespace: setup.Namespace(), - }, - } - test.EventuallyCreated(test.Ctx, test.K8sClient, cluster) - - pluginDefinitionList := &greenhousev1alpha1.PluginDefinitionList{} - pluginList := &greenhousev1alpha1.PluginList{} - deploymentList := &appsv1.DeploymentList{} - ctx := test.Ctx - - // Creating plugin definition - testPluginDefinition := fixtures.CreateNginxPluginDefinition(ctx, setup) - err := test.K8sClient.List(ctx, pluginDefinitionList) - Expect(err).NotTo(HaveOccurred()) - Expect(len(pluginDefinitionList.Items)).To(BeEquivalentTo(1)) - - // Creating plugin - testPlugin := setup.CreatePlugin(test.Ctx, "test-nginx-plugin", - test.WithPluginDefinition(testPluginDefinition.Name), - test.WithCluster(secret.Name), - test.WithReleaseNamespace(setup.Namespace()), - test.WithPluginOptionValue("replicaCount", &apiextensionsv1.JSON{Raw: []byte("1")}, nil)) - Eventually(func(g Gomega) bool { - err = test.K8sClient.List(ctx, pluginList) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(len(pluginList.Items)).To(BeEquivalentTo(1)) - g.Expect(pluginList.Items[0].Status.HelmReleaseStatus).ToNot(BeNil()) - g.Expect(pluginList.Items[0].Status.HelmReleaseStatus.Status).To(BeEquivalentTo("deployed")) - return true - }).Should(BeTrue()) - - // Checking deployment - err = remoteClient.List(ctx, deploymentList, client.InNamespace(setup.Namespace())) - Expect(err).NotTo(HaveOccurred()) - SetDefaultEventuallyTimeout(60 * time.Second) - Eventually(func(g Gomega) bool { - err = remoteClient.List(ctx, deploymentList, client.InNamespace(setup.Namespace())) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(deploymentList.Items).ToNot(BeEmpty()) - return true - }).Should(BeTrue()) - - // Checking the name of deployment - nginxDeploymentExists := false - for _, deployment := range deploymentList.Items { - if strings.Contains(deployment.Name, "nginx") { - nginxDeploymentExists = true - Expect(deployment.Spec.Replicas).To(PointTo(Equal(int32(1)))) - break - } - } - Expect(nginxDeploymentExists).To(BeTrue()) - - // Updating replicas - namespacedName := types.NamespacedName{Name: testPlugin.Name, Namespace: testPlugin.Namespace} - err = test.K8sClient.Get(ctx, namespacedName, testPlugin) - Expect(err).NotTo(HaveOccurred()) - testPlugin = &pluginList.Items[0] - test.SetOptionValueForPlugin(testPlugin, "replicaCount", "2") - err = test.K8sClient.Update(ctx, testPlugin) - Expect(err).NotTo(HaveOccurred()) - Eventually(func(g Gomega) bool { - err = remoteClient.List(ctx, deploymentList, client.InNamespace(setup.Namespace())) - g.Expect(err).NotTo(HaveOccurred()) - for _, deployment := range deploymentList.Items { - if strings.Contains(deployment.Name, "nginx") { - g.Expect(deployment.Spec.Replicas).To(PointTo(Equal(int32(2)))) - } - } - return true - }).Should(BeTrue()) - - // Deleting plugin - test.EventuallyDeleted(ctx, test.K8sClient, testPlugin) - - // Check, is deployment deleted - Eventually(func(g Gomega) bool { - err = remoteClient.List(ctx, deploymentList, client.InNamespace(setup.Namespace())) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(len(deploymentList.Items)).To(BeEquivalentTo(0)) - return true - }).Should(BeTrue()) - - // Deleting plugin definition - test.EventuallyDeleted(ctx, test.K8sClient, testPluginDefinition) - }) - }) - - Context("with helm lifecycle hooks", func() { - It("should deploy the plugin", func() { - - const clusterName = "test-cluster-b" - setup := test.NewTestSetup(test.Ctx, test.K8sClient, "teamrbac") - secret := setup.CreateSecret(test.Ctx, clusterName, - test.WithSecretType(greenhouseapis.SecretTypeKubeConfig), - test.WithSecretData(map[string][]byte{greenhouseapis.KubeConfigKey: remoteKubeConfig})) - cluster := &greenhousev1alpha1.Cluster{ - ObjectMeta: metav1.ObjectMeta{ - Name: clusterName, - Namespace: setup.Namespace(), - }, - } - test.EventuallyCreated(test.Ctx, test.K8sClient, cluster) - - pluginDefinitionList := &greenhousev1alpha1.PluginDefinitionList{} - pluginList := &greenhousev1alpha1.PluginList{} - podList := &v1.PodList{} - ctx := test.Ctx - - // Creating plugin definition - testPluginDefinition := fixtures.CreateTestHookPluginDefinition(test.Ctx, setup) - err := test.K8sClient.List(ctx, pluginDefinitionList) - Expect(err).NotTo(HaveOccurred()) - Expect(len(pluginDefinitionList.Items)).To(BeEquivalentTo(1)) - - // Creating plugin - _ = setup.CreatePlugin(test.Ctx, "test-hook-plugin", - test.WithPluginDefinition(testPluginDefinition.Name), - test.WithCluster(secret.Name), - test.WithReleaseNamespace(setup.Namespace())) - - // Check jobs - jobList := &batchv1.JobList{} - err = remoteClient.List(ctx, jobList, client.InNamespace(setup.Namespace())) - Expect(err).NotTo(HaveOccurred()) - Expect(len(jobList.Items)).To(BeEquivalentTo(0)) - - // Check plugin list - var plugin greenhousev1alpha1.Plugin - Eventually(func(g Gomega) { - err = test.K8sClient.List(ctx, pluginList) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(len(pluginList.Items)).To(BeEquivalentTo(1)) - g.Expect(pluginList.Items[0].Status.HelmReleaseStatus).ToNot(BeNil()) - g.Expect(pluginList.Items[0].Status.HelmReleaseStatus.Status).To(BeEquivalentTo("deployed")) - plugin = pluginList.Items[0] - }).Should(Succeed()) - - // Checking pod - err = remoteClient.List(ctx, podList, client.InNamespace(setup.Namespace())) - Expect(err).NotTo(HaveOccurred()) - Eventually(func(g Gomega) { - err = remoteClient.List(ctx, podList, client.InNamespace(setup.Namespace())) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(podList.Items).ToNot(BeEmpty()) - }).Should(Succeed()) - - // Checking the name of pod - podExists := false - for _, pod := range podList.Items { - if strings.Contains(pod.Name, "alpine") { - podExists = true - break - } - } - Expect(podExists).To(BeTrue()) - - // Update plugin value - test.SetOptionValueForPlugin(&plugin, "hook_enabled", "true") - err = test.K8sClient.Update(ctx, &plugin) - Expect(err).NotTo(HaveOccurred()) - - // Check jobs - Eventually(func(g Gomega) { - err = remoteClient.List(ctx, jobList, client.InNamespace(setup.Namespace())) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(len(jobList.Items)).To(BeEquivalentTo(1)) - }).Should(Succeed()) - - }) - }) -}) diff --git a/test/e2e/suite_test.go b/test/e2e/suite_test.go deleted file mode 100644 index 9495e508e..000000000 --- a/test/e2e/suite_test.go +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -// SPDX-License-Identifier: Apache-2.0 - -//go:build e2e - -package e2e - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/cloudoperators/greenhouse/pkg/test" -) - -var ( - remoteCfg *rest.Config - remoteKubeConfig []byte - remoteClient client.Client -) - -func TestE2E(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "E2ESuite") -} - -var _ = BeforeSuite(func() { - // Register all known controllers and webhooks if we run the e2e tests locally - // Register controllers. - for controllerName, hookFunc := range knownControllers { - test.RegisterController(controllerName, hookFunc) - } - // register webhooks - for webhookName, hookFunc := range knownWebhooks { - test.RegisterWebhook(webhookName, hookFunc) - } - - if !test.IsUseExistingCluster { - remoteCfg, remoteClient, _, remoteKubeConfig = test.StartControlPlane("6885", true, false) - } else { - remoteCfg = test.Cfg - remoteClient = test.K8sClient - remoteKubeConfig = test.KubeConfig - } - - test.TestBeforeSuite() -}) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - test.TestAfterSuite() -}) diff --git a/test/e2e/webhooks.go b/test/e2e/webhooks.go deleted file mode 100644 index d7142c42a..000000000 --- a/test/e2e/webhooks.go +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors -// SPDX-License-Identifier: Apache-2.0 - -//go:build e2e - -package e2e - -import ( - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/cloudoperators/greenhouse/pkg/admission" -) - -var knownWebhooks = map[string]func(mgr ctrl.Manager) error{ - "cluster": admission.SetupClusterWebhookWithManager, - "secrets": admission.SetupSecretWebhookWithManager, - "organization": admission.SetupOrganizationWebhookWithManager, - "pluginDefinition": admission.SetupPluginDefinitionWebhookWithManager, - "plugin": admission.SetupPluginWebhookWithManager, - "pluginPreset": admission.SetupPluginPresetWebhookWithManager, - "teamrole": admission.SetupTeamRoleWebhookWithManager, - "teamrolebinding": admission.SetupTeamRoleBindingWebhookWithManager, - "team": admission.SetupTeamWebhookWithManager, -}