diff --git a/api/v1/coherenceresource_utils.go b/api/v1/coherenceresource_utils.go index a86425c3d..32b0d4d7e 100644 --- a/api/v1/coherenceresource_utils.go +++ b/api/v1/coherenceresource_utils.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -12,6 +12,7 @@ import ( "github.com/ghodss/yaml" "github.com/go-logr/logr" "github.com/oracle/coherence-operator/pkg/data" + "github.com/oracle/coherence-operator/pkg/operator" "github.com/pkg/errors" "io" crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -39,7 +40,10 @@ func EnsureV1CRDs(ctx context.Context, logger logr.Logger, scheme *runtime.Schem if err != nil { return err } - return ensureV1CRDs(ctx, logger, scheme, cl, "apiextensions.k8s.io_v1_customresourcedefinition_coherencejob.coherence.oracle.com.yaml") + if operator.ShouldInstallJobCRD() { + return ensureV1CRDs(ctx, logger, scheme, cl, "apiextensions.k8s.io_v1_customresourcedefinition_coherencejob.coherence.oracle.com.yaml") + } + return nil } // ensureV1CRDs ensures that the specified V1 CRDs are loaded using the specified embedded CRD files diff --git a/docs/installation/01_installation.adoc b/docs/installation/01_installation.adoc index adad23df4..48ee27382 100644 --- a/docs/installation/01_installation.adoc +++ b/docs/installation/01_installation.adoc @@ -28,6 +28,7 @@ easily be installed into a Kubernetes cluster. *** <> *** <> *** <> +*** <> *** <> ** <> ** <> @@ -637,6 +638,24 @@ deploymentAnnotations: two: value-two ---- +[#helm-job] +=== CoherenceJob CRD Support + +By default, the Operator will install both CRDs, `Coherence` and `CoherenceJob`. +If support for `CoherenceJob` is not required then it can be excluded from being installed setting the +Operator command line parameter `--install-job-crd` to `false`. + +When installing with Helm, the `allowCoherenceJobs` value can be set to `false` to disable support for `CoherenceJob` +resources (the default value is `true`). + +[source,bash] +---- +helm install \ + --namespace \ + --set allowCoherenceJobs=false \ + coherence \ + coherence/coherence-operator +---- [#helm-uninstall] === Uninstall the Coherence Operator Helm chart diff --git a/helm-charts/coherence-operator/templates/deployment.yaml b/helm-charts/coherence-operator/templates/deployment.yaml index b7c78677c..bd7f52533 100644 --- a/helm-charts/coherence-operator/templates/deployment.yaml +++ b/helm-charts/coherence-operator/templates/deployment.yaml @@ -117,6 +117,9 @@ spec: {{- if (eq .Values.webhooks false) }} - --enable-webhook=false {{- end }} +{{- if (eq .Values.allowCoherenceJobs false) }} + - --install-job-crd=false +{{- end }} {{- if (.Values.globalLabels) }} {{- range $k, $v := .Values.globalLabels }} - --global-label={{ $k }}={{ $v }} diff --git a/helm-charts/coherence-operator/values.yaml b/helm-charts/coherence-operator/values.yaml index 783fada00..b54104e14 100644 --- a/helm-charts/coherence-operator/values.yaml +++ b/helm-charts/coherence-operator/values.yaml @@ -1,4 +1,4 @@ -# Copyright 2020, 2023, Oracle Corporation and/or its affiliates. +# Copyright 2020, 2024, Oracle Corporation and/or its affiliates. # Licensed under the Universal Permissive License v 1.0 as shown at # http://oss.oracle.com/licenses/upl. @@ -204,4 +204,9 @@ nodeRoles: false # If this is set to false, then it will be possible to install invalid Coherence resource into the Kubernetes # cluster, that may cause errors when the Operator tries to reconcile them, or worse the Operator may create # other invalid Kubernetes resources that fail to run. -webhooks: true \ No newline at end of file +webhooks: true + +# If set to false, the Operator will not support the CoherenceJob resource type. +# The CoherenceJob CRD will not be installed by the Operator and the Operator will +# not listen for any CoherenceJob resource events. +allowCoherenceJobs: true diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index 3f90e91a3..f454e7dd1 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -53,6 +53,7 @@ const ( FlagCertIssuer = "cert-issuer" FlagCoherenceImage = "coherence-image" FlagCRD = "install-crd" + FlagJobCRD = "install-job-crd" FlagDevMode = "coherence-dev-mode" FlagDryRun = "dry-run" FlagEnableWebhook = "enable-webhook" @@ -164,7 +165,12 @@ func SetupFlags(cmd *cobra.Command, v *viper.Viper) { cmd.Flags().Bool( FlagCRD, true, - "Enables automatic installation/update of Coherence CRDs", + "Enables automatic installation/update of all Coherence CRDs", + ) + cmd.Flags().Bool( + FlagJobCRD, + true, + "Enables automatic installation/update of CoherenceJob CRD", ) cmd.Flags().Bool( FlagEnableWebhook, @@ -344,6 +350,10 @@ func ShouldInstallCRDs() bool { return GetViper().GetBool(FlagCRD) && !IsDryRun() } +func ShouldInstallJobCRD() bool { + return GetViper().GetBool(FlagJobCRD) +} + func ShouldEnableWebhooks() bool { return GetViper().GetBool(FlagEnableWebhook) && !IsDryRun() } diff --git a/pkg/operator/operator_test.go b/pkg/operator/operator_test.go index 2e5a98d3f..15bf31320 100644 --- a/pkg/operator/operator_test.go +++ b/pkg/operator/operator_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -12,6 +12,8 @@ import ( . "github.com/onsi/gomega" v1 "github.com/oracle/coherence-operator/api/v1" "github.com/oracle/coherence-operator/pkg/fakes" + "github.com/oracle/coherence-operator/pkg/operator" + "github.com/spf13/viper" crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "testing" ) @@ -29,6 +31,7 @@ func TestShouldCreateV1CRDs(t *testing.T) { ctx := context.TODO() log := logr.New(fakes.TestLogSink{T: t}) + viper.GetViper().Set(operator.FlagJobCRD, true) err = v1.EnsureV1CRDs(ctx, log, mgr.Scheme, mgr.Client) g.Expect(err).NotTo(HaveOccurred()) @@ -53,6 +56,43 @@ func TestShouldCreateV1CRDs(t *testing.T) { } } +func TestShouldNotCreateJobCRDWhenFlagIsFalse(t *testing.T) { + var err error + + g := NewGomegaWithT(t) + mgr, err := fakes.NewFakeManager() + g.Expect(err).NotTo(HaveOccurred()) + + err = crdv1.AddToScheme(mgr.Scheme) + g.Expect(err).NotTo(HaveOccurred()) + + ctx := context.TODO() + log := logr.New(fakes.TestLogSink{T: t}) + + viper.GetViper().Set(operator.FlagJobCRD, false) + err = v1.EnsureV1CRDs(ctx, log, mgr.Scheme, mgr.Client) + g.Expect(err).NotTo(HaveOccurred()) + + crdList := crdv1.CustomResourceDefinitionList{} + err = mgr.Client.List(ctx, &crdList) + g.Expect(err).NotTo(HaveOccurred()) + + g.Expect(len(crdList.Items)).To(Equal(1)) + + expected := make(map[string]bool) + expected["coherence.coherence.oracle.com"] = false + + for _, crd := range crdList.Items { + expected[crd.Name] = true + } + + for crd, found := range expected { + if !found { + t.Errorf("Failed to create CRD " + crd) + } + } +} + func TestShouldUpdateV1CRDs(t *testing.T) { var err error @@ -62,6 +102,8 @@ func TestShouldUpdateV1CRDs(t *testing.T) { err = crdv1.AddToScheme(mgr.Scheme) g.Expect(err).NotTo(HaveOccurred()) + viper.GetViper().Set(operator.FlagJobCRD, true) + oldCRDs := make(map[string]*crdv1.CustomResourceDefinition) oldCRDs["coherence.coherence.oracle.com"] = nil oldCRDs["coherencejob.coherence.oracle.com"] = nil @@ -92,3 +134,44 @@ func TestShouldUpdateV1CRDs(t *testing.T) { g.Expect(crd.GetResourceVersion()).To(Equal(oldCRD.GetResourceVersion())) } } + +func TestShouldNotUpdateJobCRDWhenFlagIsFalse(t *testing.T) { + var err error + + g := NewGomegaWithT(t) + mgr, err := fakes.NewFakeManager() + g.Expect(err).NotTo(HaveOccurred()) + err = crdv1.AddToScheme(mgr.Scheme) + g.Expect(err).NotTo(HaveOccurred()) + + viper.GetViper().Set(operator.FlagJobCRD, false) + + oldCRDs := make(map[string]*crdv1.CustomResourceDefinition) + oldCRDs["coherence.coherence.oracle.com"] = nil + + for name := range oldCRDs { + crd := crdv1.CustomResourceDefinition{} + crd.SetName(name) + crd.SetResourceVersion("1") + oldCRDs[name] = &crd + _ = mgr.GetClient().Create(context.TODO(), &crd) + } + + ctx := context.TODO() + log := logr.New(fakes.TestLogSink{T: t}) + + err = v1.EnsureV1CRDs(ctx, log, mgr.Scheme, mgr.Client) + g.Expect(err).NotTo(HaveOccurred()) + + crdList := crdv1.CustomResourceDefinitionList{} + err = mgr.Client.List(ctx, &crdList) + g.Expect(err).NotTo(HaveOccurred()) + + g.Expect(len(crdList.Items)).To(Equal(1)) + + for _, crd := range crdList.Items { + oldCRD := oldCRDs[crd.Name] + g.Expect(crd).NotTo(Equal(oldCRD)) + g.Expect(crd.GetResourceVersion()).To(Equal(oldCRD.GetResourceVersion())) + } +} diff --git a/pkg/runner/cmd_operator.go b/pkg/runner/cmd_operator.go index 6d695a4e2..6a47458e7 100644 --- a/pkg/runner/cmd_operator.go +++ b/pkg/runner/cmd_operator.go @@ -152,12 +152,14 @@ func execute() error { } // Set up the CoherenceJob reconciler - if err = (&controllers.CoherenceJobReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("CoherenceJob"), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - return errors.Wrap(err, "unable to create CoherenceJob controller") + if operator.ShouldInstallJobCRD() { + if err = (&controllers.CoherenceJobReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("CoherenceJob"), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + return errors.Wrap(err, "unable to create CoherenceJob controller") + } } dryRun := operator.IsDryRun() diff --git a/test/e2e/helm/helm_test.go b/test/e2e/helm/helm_test.go index 4e8289e44..e46b65f6b 100644 --- a/test/e2e/helm/helm_test.go +++ b/test/e2e/helm/helm_test.go @@ -16,6 +16,7 @@ import ( "github.com/oracle/coherence-operator/test/e2e/helper/matchers" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -141,6 +142,27 @@ func TestDisableWebhooks(t *testing.T) { g.Expect(c.Args).Should(ContainElements("operator", "--enable-leader-election", "--enable-webhook=false")) } +func TestDisableJobCRD(t *testing.T) { + g := NewGomegaWithT(t) + + err := RemoveCRDs() + g.Expect(err).NotTo(HaveOccurred()) + + result, err := helmInstall("--set", "allowCoherenceJobs=false") + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(result).NotTo(BeNil()) + + dep := &appsv1.Deployment{} + err = result.Get("coherence-operator", dep) + g.Expect(err).NotTo(HaveOccurred()) + + c := findContainer("manager", dep) + g.Expect(c).NotTo(BeNil()) + + g.Expect(c.Args).NotTo(BeNil()) + g.Expect(c.Args).Should(ContainElements("operator", "--enable-leader-election", "--install-job-crd=false")) +} + func TestSetOnlySameNamespace(t *testing.T) { g := NewGomegaWithT(t) result, err := helmInstall("--set", "onlySameNamespace=true") @@ -885,6 +907,25 @@ func RemoveWebHook() error { return nil } +// Remove the CRDs that the Operator install creates. +func RemoveCRDs() error { + cohCrd := crdv1.CustomResourceDefinition{} + cohCrd.Name = "coherence.coherence.oracle.com" + err := testContext.Client.Delete(goctx.TODO(), &cohCrd) + if err != nil && !errors.IsNotFound(err) { + return err + } + + cohJobCrd := crdv1.CustomResourceDefinition{} + cohJobCrd.Name = "coherencejob.coherence.oracle.com" + err = testContext.Client.Delete(goctx.TODO(), &cohJobCrd) + if err != nil && !errors.IsNotFound(err) { + return err + } + + return nil +} + // RemoveRBAC removes all the RBAC rules that the Operator install creates to // ensure that nothing is left from a previous test. func RemoveRBAC() error {