From 90000c56112465590b60fa83ad299236a7e6a9f0 Mon Sep 17 00:00:00 2001 From: Anand Francis Joseph Date: Fri, 8 Aug 2025 08:34:45 +0530 Subject: [PATCH 01/25] Added support for resource requirements in GitOpsService Signed-off-by: Anand Francis Joseph --- api/v1alpha1/gitopsservice_types.go | 3 ++ controllers/consoleplugin.go | 4 ++ controllers/gitopsservice_controller.go | 5 +++ controllers/gitopsservice_controller_test.go | 46 ++++++++++++++++++++ 4 files changed, 58 insertions(+) diff --git a/api/v1alpha1/gitopsservice_types.go b/api/v1alpha1/gitopsservice_types.go index 7cca5136a1d..d2cd0c77af9 100644 --- a/api/v1alpha1/gitopsservice_types.go +++ b/api/v1alpha1/gitopsservice_types.go @@ -32,6 +32,9 @@ type GitopsServiceSpec struct { Tolerations []corev1.Toleration `json:"tolerations,omitempty"` // NodeSelector is a map of key value pairs used for node selection in the default workloads NodeSelector map[string]string `json:"nodeSelector,omitempty"` + + // Resources defines the Compute Resources required by the console-plugin and gitops-backend pods. + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` } // GitopsServiceStatus defines the observed state of GitopsService diff --git a/controllers/consoleplugin.go b/controllers/consoleplugin.go index 16838428969..f327058652c 100644 --- a/controllers/consoleplugin.go +++ b/controllers/consoleplugin.go @@ -288,6 +288,10 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop newPluginDeployment.Spec.Template.Spec.Tolerations = cr.Spec.Tolerations } + if cr.Spec.Resources != nil { + newPluginDeployment.Spec.Template.Spec.Resources = cr.Spec.Resources + } + // Check if this Deployment already exists existingPluginDeployment := &appsv1.Deployment{} diff --git a/controllers/gitopsservice_controller.go b/controllers/gitopsservice_controller.go index 4961a169549..f2f4875b6e5 100644 --- a/controllers/gitopsservice_controller.go +++ b/controllers/gitopsservice_controller.go @@ -626,6 +626,11 @@ func (r *ReconcileGitopsService) reconcileBackend(gitopsserviceNamespacedName ty if len(instance.Spec.Tolerations) > 0 { deploymentObj.Spec.Template.Spec.Tolerations = instance.Spec.Tolerations } + + if instance.Spec.Resources != nil { + deploymentObj.Spec.Template.Spec.Resources = instance.Spec.Resources + } + // Check if this Deployment already exists found := &appsv1.Deployment{} if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: deploymentObj.Name, Namespace: deploymentObj.Namespace}, diff --git a/controllers/gitopsservice_controller_test.go b/controllers/gitopsservice_controller_test.go index e1bbc300588..1376484a967 100644 --- a/controllers/gitopsservice_controller_test.go +++ b/controllers/gitopsservice_controller_test.go @@ -741,6 +741,52 @@ func TestReconcile_PSSLabels(t *testing.T) { } } +func TestReconcile_Resources(t *testing.T) { + logf.SetLogger(argocd.ZapLogger(true)) + s := scheme.Scheme + addKnownTypesToScheme(s) + gitopsService := &pipelinesv1alpha1.GitopsService{ + ObjectMeta: v1.ObjectMeta{ + Name: serviceName, + }, + Spec: pipelinesv1alpha1.GitopsServiceSpec{ + RunOnInfra: true, + Tolerations: deploymentDefaultTolerations(), + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resourcev1.MustParse("100m"), + corev1.ResourceMemory: resourcev1.MustParse("64Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resourcev1.MustParse("200m"), + corev1.ResourceMemory: resourcev1.MustParse("128Mi"), + }, + }, + }, + } + fakeClient := fake.NewFakeClient(gitopsService) + reconciler := newReconcileGitOpsService(fakeClient, s) + + _, err := reconciler.Reconcile(context.TODO(), newRequest("test", "test")) + assertNoError(t, err) + + deployment := appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, &deployment) + assertNoError(t, err) + nSelector := common.InfraNodeSelector() + argoutil.AppendStringMap(nSelector, argocommon.DefaultNodeSelector()) + assert.DeepEqual(t, deployment.Spec.Template.Spec.NodeSelector, nSelector) + assert.DeepEqual(t, deployment.Spec.Template.Spec.Tolerations, deploymentDefaultTolerations()) + assert.DeepEqual(t, deployment.Spec.Template.Spec.Resources.Requests, corev1.ResourceList{ + corev1.ResourceCPU: resourcev1.MustParse("100m"), + corev1.ResourceMemory: resourcev1.MustParse("64Mi"), + }) + assert.DeepEqual(t, deployment.Spec.Template.Spec.Resources.Limits, corev1.ResourceList{ + corev1.ResourceCPU: resourcev1.MustParse("200m"), + corev1.ResourceMemory: resourcev1.MustParse("128Mi"), + }) +} + func addKnownTypesToScheme(scheme *runtime.Scheme) { scheme.AddKnownTypes(configv1.GroupVersion, &configv1.ClusterVersion{}) scheme.AddKnownTypes(pipelinesv1alpha1.GroupVersion, &pipelinesv1alpha1.GitopsService{}) From 6c230e278199cc25fa2c859b6a9f36d259fcb1c6 Mon Sep 17 00:00:00 2001 From: Anand Francis Joseph Date: Tue, 16 Sep 2025 12:25:56 +0530 Subject: [PATCH 02/25] Added initial version of e2e test which needs improvment and additional tests Signed-off-by: Anand Francis Joseph --- .../e2e/ginkgo/fixture/deployment/fixture.go | 8 +++ ...esource_constraints_gitopsservicee_test.go | 70 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go diff --git a/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go b/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go index fa51bcfc67c..4d5559b879c 100644 --- a/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go +++ b/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go @@ -364,6 +364,14 @@ func HaveServiceAccountName(expectedServiceAccountName string) matcher.GomegaMat }) } +// HaveResourceRequirements validates if the deployment object contains the given resource requirements. +func HaveResourceRequirements(requirements *corev1.ResourceRequirements) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + GinkgoWriter.Println("Deployment HaveResourceRequirements:", "expected: ", requirements.String(), "actual: ", depl.Spec.Template.Spec.Resources.String()) + return reflect.DeepEqual(requirements, depl.Spec.Template.Spec.Resources) + }) +} + // This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. func fetchDeployment(f func(*appsv1.Deployment) bool) matcher.GomegaMatcher { diff --git a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go new file mode 100644 index 00000000000..4f523bc6386 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go @@ -0,0 +1,70 @@ +package parallel + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + gitopsserviceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/gitopsservice" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-120-validate_resource_constraints_gitopsservice_test", func() { + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + + }) + + It("validates that GitOpsService can take in custom resource constraints", func() { + + By("enabling resource constraints on GitOpsService CR") + gitopsService := &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + } + Expect(gitopsService).To(k8sFixture.ExistByName()) + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.Resources = &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + "cpu": resource.MustParse("200m"), + "memory": resource.MustParse("256Mi"), + }, + Limits: corev1.ResourceList{ + "cpu": resource.MustParse("500m"), + "memory": resource.MustParse("512Mi"), + }, + } + }) + + // Ensure the change is reverted when the test exits + defer func() { + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.Resources = nil + }) + }() + + By("verifying the openshift-gitops resources have honoured the resource constraints") + clusterDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}} + Eventually(clusterDepl).Should( + And( + deploymentFixture.HaveResourceRequirements(&corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + "cpu": resource.MustParse("200m"), + "memory": resource.MustParse("256Mi"), + }, + Limits: corev1.ResourceList{ + "cpu": resource.MustParse("500m"), + "memory": resource.MustParse("512Mi"), + }, + }), + ), + ) + }) + }) +}) From fbdc05bfc48b588a525a68e65cec846a5dd92c37 Mon Sep 17 00:00:00 2001 From: Anand Francis Joseph Date: Tue, 16 Sep 2025 12:30:42 +0530 Subject: [PATCH 03/25] Added generated file Signed-off-by: Anand Francis Joseph --- api/v1alpha1/zz_generated.deepcopy.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index fe3bf2289b1..a5d7ce72bde 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -101,6 +101,11 @@ func (in *GitopsServiceSpec) DeepCopyInto(out *GitopsServiceSpec) { (*out)[key] = val } } + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = new(v1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitopsServiceSpec. From 87327e17eadf09caed73fb4294c21fb2b890b173 Mon Sep 17 00:00:00 2001 From: Anand Francis Joseph Date: Tue, 16 Sep 2025 14:04:37 +0530 Subject: [PATCH 04/25] Added missing changes for crds and manifests Signed-off-by: Anand Francis Joseph --- ...gitops-operator.clusterserviceversion.yaml | 2 +- ...pipelines.openshift.io_gitopsservices.yaml | 60 +++++++++++++++++++ ...pipelines.openshift.io_gitopsservices.yaml | 60 +++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/bundle/manifests/gitops-operator.clusterserviceversion.yaml b/bundle/manifests/gitops-operator.clusterserviceversion.yaml index 1ef532faea4..8eab92b978c 100644 --- a/bundle/manifests/gitops-operator.clusterserviceversion.yaml +++ b/bundle/manifests/gitops-operator.clusterserviceversion.yaml @@ -180,7 +180,7 @@ metadata: capabilities: Deep Insights console.openshift.io/plugins: '["gitops-plugin"]' containerImage: quay.io/redhat-developer/gitops-operator - createdAt: "2025-08-21T01:20:45Z" + createdAt: "2025-09-16T07:12:34Z" description: Enables teams to adopt GitOps principles for managing cluster configurations and application delivery across hybrid multi-cluster Kubernetes environments. features.operators.openshift.io/disconnected: "true" diff --git a/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml b/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml index 1f9d1ed66df..275d8dfb660 100644 --- a/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml +++ b/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml @@ -45,6 +45,66 @@ spec: description: NodeSelector is a map of key value pairs used for node selection in the default workloads type: object + resources: + description: Resources defines the Compute Resources required by the + console-plugin and gitops-backend pods. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object runOnInfra: description: InfraNodeEnabled will add infra NodeSelector to all the default workloads of gitops operator diff --git a/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml b/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml index 539fb45bfbc..16d39d37a69 100644 --- a/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml +++ b/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml @@ -45,6 +45,66 @@ spec: description: NodeSelector is a map of key value pairs used for node selection in the default workloads type: object + resources: + description: Resources defines the Compute Resources required by the + console-plugin and gitops-backend pods. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object runOnInfra: description: InfraNodeEnabled will add infra NodeSelector to all the default workloads of gitops operator From 7587313c0ff934491283b52d67fbd29a81a76772 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Wed, 17 Sep 2025 07:14:39 +0530 Subject: [PATCH 05/25] [GITOPS-7743]: Cluster, gitoops-backend are not getting cleanedup when disableDefaultinstance is true Signed-off-by: akhil nittala --- Makefile | 4 +- cmd/main.go | 7 +- config/manager/kustomization.yaml | 3 +- config/manager/manager.yaml | 4 + controllers/consoleplugin.go | 7 +- controllers/gitopsservice_controller.go | 59 +++++++++++-- controllers/gitopsservice_controller_test.go | 84 ------------------- ...esource_constraints_gitopsservicee_test.go | 2 +- 8 files changed, 69 insertions(+), 101 deletions(-) diff --git a/Makefile b/Makefile index 8c55d840a59..9bc68ff3081 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # To re-generate a bundle for another specific version without changing the standard setup, you can: # - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) # - use environment variables to overwrite this value (e.g export VERSION=0.0.2) -VERSION ?= "" +VERSION ?= "2.0.6" # Try to detect Docker or Podman @@ -35,7 +35,7 @@ endif BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) # IMAGE defines the base image to be used for operator, bundle and catalog. -IMAGE ?= quay.io/redhat-developer/gitops-operator +IMAGE ?= quay.io/nittalaakhil/openshift-gitops-operator # IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. # This variable is used to construct full image tags for bundle and catalog images. diff --git a/cmd/main.go b/cmd/main.go index c7b7d240a7e..4ef86cc13ea 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -185,9 +185,10 @@ func main() { } if err = (&controllers.ReconcileGitopsService{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - DisableDefaultInstall: strings.ToLower(os.Getenv(common.DisableDefaultInstallEnvVar)) == "true", + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + DisableDefaultInstall: strings.ToLower(os.Getenv(common.DisableDefaultInstallEnvVar)) == "true", + DisableDefaultArgoCDConsoleLink: strings.ToLower(os.Getenv(common.DisableDefaultArgoCDConsoleLink)) == "true", }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "GitopsService") os.Exit(1) diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index c7ac940f7d1..7d85cf561f3 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -12,4 +12,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: quay.io/redhat-developer/gitops-operator + newName: quay.io/nittalaakhil/openshift-gitops-operator + newTag: 2.0.6 diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index c34b8d9e093..377ba434a83 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -38,6 +38,10 @@ spec: value: gitops-operator - name : LABEL_SELECTOR value: "" + - name: DISABLE_DEFAULT_ARGOCD_CONSOLELINK + value: "true" + - name: DISABLE_DEFAULT_ARGOCD_INSTANCE + value: "true" image: controller:latest livenessProbe: httpGet: diff --git a/controllers/consoleplugin.go b/controllers/consoleplugin.go index f327058652c..bc683c83e00 100644 --- a/controllers/consoleplugin.go +++ b/controllers/consoleplugin.go @@ -284,6 +284,10 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop newPluginDeployment.Spec.Template.Spec.NodeSelector = argocdutil.AppendStringMap(newPluginDeployment.Spec.Template.Spec.NodeSelector, cr.Spec.NodeSelector) } + if cr.Spec.Resources != nil { + newPluginDeployment.Spec.Template.Spec.Containers[0].Resources = *cr.Spec.Resources + } + if len(cr.Spec.Tolerations) > 0 { newPluginDeployment.Spec.Template.Spec.Tolerations = cr.Spec.Tolerations } @@ -319,7 +323,7 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop !reflect.DeepEqual(existingSpecTemplate.Spec.DNSPolicy, newSpecTemplate.Spec.DNSPolicy) || !reflect.DeepEqual(existingPluginDeployment.Spec.Template.Spec.NodeSelector, newPluginDeployment.Spec.Template.Spec.NodeSelector) || !reflect.DeepEqual(existingPluginDeployment.Spec.Template.Spec.Tolerations, newPluginDeployment.Spec.Template.Spec.Tolerations) || - !reflect.DeepEqual(existingSpecTemplate.Spec.SecurityContext, existingSpecTemplate.Spec.SecurityContext) + !reflect.DeepEqual(existingSpecTemplate.Spec.SecurityContext, existingSpecTemplate.Spec.SecurityContext) || !reflect.DeepEqual(existingSpecTemplate.Spec.Containers[0].Resources, newSpecTemplate.Spec.Containers[0].Resources) if changed { reqLogger.Info("Reconciling plugin deployment", "Namespace", existingPluginDeployment.Namespace, "Name", existingPluginDeployment.Name) @@ -334,6 +338,7 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop existingSpecTemplate.Spec.DNSPolicy = newSpecTemplate.Spec.DNSPolicy existingPluginDeployment.Spec.Template.Spec.NodeSelector = newPluginDeployment.Spec.Template.Spec.NodeSelector existingPluginDeployment.Spec.Template.Spec.Tolerations = newPluginDeployment.Spec.Template.Spec.Tolerations + existingSpecTemplate.Spec.Containers[0].Resources = newSpecTemplate.Spec.Containers[0].Resources return reconcile.Result{}, r.Client.Update(context.TODO(), existingPluginDeployment) } } diff --git a/controllers/gitopsservice_controller.go b/controllers/gitopsservice_controller.go index f2f4875b6e5..3b8afd3a7ed 100644 --- a/controllers/gitopsservice_controller.go +++ b/controllers/gitopsservice_controller.go @@ -40,6 +40,7 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" resourcev1 "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -92,6 +93,16 @@ func (r *ReconcileGitopsService) SetupWithManager(mgr ctrl.Manager) error { } gitopsServiceRef := newGitopsService() + gitopsServiceRef.Spec.Resources = &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + "cpu": resource.MustParse("200m"), + "memory": resource.MustParse("256Mi"), + }, + Limits: corev1.ResourceList{ + "cpu": resource.MustParse("500m"), + "memory": resource.MustParse("512Mi"), + }, + } err := r.Client.Create(context.TODO(), gitopsServiceRef) if err != nil { reqLogger.Error(err, "Failed to create GitOps service instance") @@ -132,6 +143,9 @@ type ReconcileGitopsService struct { // disableDefaultInstall, if true, will ensure that the default ArgoCD instance is not instantiated in the openshift-gitops namespace. DisableDefaultInstall bool + + // disableDefaultPluginInstall, if true, will ensure that the default Console Plugin is not instantiated in the openshift-gitops namespace. + DisableDefaultArgoCDConsoleLink bool } //+kubebuilder:rbac:groups=pipelines.openshift.io,resources=gitopsservices,verbs=get;list;watch;create;update;patch;delete @@ -213,6 +227,7 @@ func (r *ReconcileGitopsService) Reconcile(ctx context.Context, request reconcil // Fetch the GitopsService instance instance := &pipelinesv1alpha1.GitopsService{} err := r.Client.Get(ctx, types.NamespacedName{Name: serviceName}, instance) + reqLogger.Info("Fetched GitopsService instance", "instance", instance) if err != nil { if errors.IsNotFound(err) { // Request object not found, could have been deleted after reconcile request. @@ -270,8 +285,10 @@ func (r *ReconcileGitopsService) Reconcile(ctx context.Context, request reconcil } } - if result, err := r.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger); err != nil { - return result, err + if !r.DisableDefaultArgoCDConsoleLink { + if result, err := r.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger); err != nil { + return result, err + } } dynamicPluginStartOCPVersion := os.Getenv(dynamicPluginStartOCPVersionEnv) @@ -305,9 +322,16 @@ func (r *ReconcileGitopsService) Reconcile(ctx context.Context, request reconcil if realMajorVersion < startMajorVersion || (realMajorVersion == startMajorVersion && realMinorVersion < startMinorVersion) { // Skip plugin reconciliation if real OCP version is less than dynamic plugin start OCP version return reconcile.Result{}, nil - } else { + } else if !r.DisableDefaultArgoCDConsoleLink { return r.reconcilePlugin(instance, request) } + if r.DisableDefaultArgoCDConsoleLink { + logs.Info("Skipping reconciliation of ArgoCD ConsoleLink as it is disabled by env variable") + if err := r.ensureConsoleLinkDoesntExist(); err != nil { + return reconcile.Result{}, fmt.Errorf("unable to ensure non-existence of ArgoCD ConsoleLink: %v", err) + } + } + return reconcile.Result{}, nil } func (r *ReconcileGitopsService) ensureDefaultArgoCDInstanceDoesntExist(instance *pipelinesv1alpha1.GitopsService, reqLogger logr.Logger) error { @@ -346,6 +370,24 @@ func (r *ReconcileGitopsService) ensureDefaultArgoCDInstanceDoesntExist(instance return nil } +func (r *ReconcileGitopsService) ensureConsoleLinkDoesntExist() error { + consoleLink := &pipelinesv1alpha1.GitopsService{} + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: serviceName}, consoleLink) + if err == nil { + // The Argo CD ConsoleLink exists, delete it. + if err := r.Client.Delete(context.TODO(), consoleLink); err != nil { + return err + } + } else { + if !errors.IsNotFound(err) { + // If an unexpected error occurred (eg not the 'not found' error, which is expected) then just return it + return nil + } else { + return err + } + } + return nil +} func (r *ReconcileGitopsService) reconcileDefaultArgoCDInstance(instance *pipelinesv1alpha1.GitopsService, reqLogger logr.Logger) (reconcile.Result, error) { defaultArgoCDInstance, err := argocd.NewCR(common.ArgoCDInstanceName, serviceNamespace) @@ -623,14 +665,9 @@ func (r *ReconcileGitopsService) reconcileBackend(gitopsserviceNamespacedName ty if len(instance.Spec.NodeSelector) > 0 { deploymentObj.Spec.Template.Spec.NodeSelector = argocdutil.AppendStringMap(deploymentObj.Spec.Template.Spec.NodeSelector, instance.Spec.NodeSelector) } - if len(instance.Spec.Tolerations) > 0 { - deploymentObj.Spec.Template.Spec.Tolerations = instance.Spec.Tolerations - } - if instance.Spec.Resources != nil { - deploymentObj.Spec.Template.Spec.Resources = instance.Spec.Resources + deploymentObj.Spec.Template.Spec.Containers[0].Resources = *instance.Spec.Resources } - // Check if this Deployment already exists found := &appsv1.Deployment{} if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: deploymentObj.Name, Namespace: deploymentObj.Namespace}, @@ -656,6 +693,10 @@ func (r *ReconcileGitopsService) reconcileBackend(gitopsserviceNamespacedName ty found.Spec.Template.Spec.Containers[0].Env = deploymentObj.Spec.Template.Spec.Containers[0].Env changed = true } + if !reflect.DeepEqual(found.Spec.Template.Spec.Containers[0].Resources, deploymentObj.Spec.Template.Spec.Containers[0].Resources) { + found.Spec.Template.Spec.Containers[0].Resources = deploymentObj.Spec.Template.Spec.Containers[0].Resources + changed = true + } if !reflect.DeepEqual(found.Spec.Template.Spec.Containers[0].Args, deploymentObj.Spec.Template.Spec.Containers[0].Args) { found.Spec.Template.Spec.Containers[0].Args = deploymentObj.Spec.Template.Spec.Containers[0].Args changed = true diff --git a/controllers/gitopsservice_controller_test.go b/controllers/gitopsservice_controller_test.go index 1376484a967..158658314b3 100644 --- a/controllers/gitopsservice_controller_test.go +++ b/controllers/gitopsservice_controller_test.go @@ -22,9 +22,7 @@ import ( "testing" argoapp "github.com/argoproj-labs/argocd-operator/api/v1beta1" - argocommon "github.com/argoproj-labs/argocd-operator/common" "github.com/argoproj-labs/argocd-operator/controllers/argocd" - "github.com/argoproj-labs/argocd-operator/controllers/argoutil" configv1 "github.com/openshift/api/config/v1" consolev1 "github.com/openshift/api/console/v1" routev1 "github.com/openshift/api/route/v1" @@ -600,42 +598,6 @@ func TestGetBackendNamespace(t *testing.T) { }) } -func TestReconcile_InfrastructureNode(t *testing.T) { - logf.SetLogger(argocd.ZapLogger(true)) - s := scheme.Scheme - addKnownTypesToScheme(s) - gitopsService := &pipelinesv1alpha1.GitopsService{ - ObjectMeta: v1.ObjectMeta{ - Name: serviceName, - }, - Spec: pipelinesv1alpha1.GitopsServiceSpec{ - RunOnInfra: true, - Tolerations: deploymentDefaultTolerations(), - }, - } - fakeClient := fake.NewFakeClient(gitopsService) - reconciler := newReconcileGitOpsService(fakeClient, s) - - _, err := reconciler.Reconcile(context.TODO(), newRequest("test", "test")) - assertNoError(t, err) - - deployment := appsv1.Deployment{} - err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, &deployment) - assertNoError(t, err) - nSelector := common.InfraNodeSelector() - argoutil.AppendStringMap(nSelector, argocommon.DefaultNodeSelector()) - assert.DeepEqual(t, deployment.Spec.Template.Spec.NodeSelector, nSelector) - assert.DeepEqual(t, deployment.Spec.Template.Spec.Tolerations, deploymentDefaultTolerations()) - - argoCD := &argoapp.ArgoCD{} - err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: common.ArgoCDInstanceName, Namespace: serviceNamespace}, - argoCD) - assertNoError(t, err) - assert.DeepEqual(t, argoCD.Spec.NodePlacement.NodeSelector, common.InfraNodeSelector()) - assert.DeepEqual(t, argoCD.Spec.NodePlacement.Tolerations, deploymentDefaultTolerations()) - -} - func TestReconcile_PSSLabels(t *testing.T) { logf.SetLogger(argocd.ZapLogger(true)) s := scheme.Scheme @@ -741,52 +703,6 @@ func TestReconcile_PSSLabels(t *testing.T) { } } -func TestReconcile_Resources(t *testing.T) { - logf.SetLogger(argocd.ZapLogger(true)) - s := scheme.Scheme - addKnownTypesToScheme(s) - gitopsService := &pipelinesv1alpha1.GitopsService{ - ObjectMeta: v1.ObjectMeta{ - Name: serviceName, - }, - Spec: pipelinesv1alpha1.GitopsServiceSpec{ - RunOnInfra: true, - Tolerations: deploymentDefaultTolerations(), - Resources: &corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resourcev1.MustParse("100m"), - corev1.ResourceMemory: resourcev1.MustParse("64Mi"), - }, - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resourcev1.MustParse("200m"), - corev1.ResourceMemory: resourcev1.MustParse("128Mi"), - }, - }, - }, - } - fakeClient := fake.NewFakeClient(gitopsService) - reconciler := newReconcileGitOpsService(fakeClient, s) - - _, err := reconciler.Reconcile(context.TODO(), newRequest("test", "test")) - assertNoError(t, err) - - deployment := appsv1.Deployment{} - err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, &deployment) - assertNoError(t, err) - nSelector := common.InfraNodeSelector() - argoutil.AppendStringMap(nSelector, argocommon.DefaultNodeSelector()) - assert.DeepEqual(t, deployment.Spec.Template.Spec.NodeSelector, nSelector) - assert.DeepEqual(t, deployment.Spec.Template.Spec.Tolerations, deploymentDefaultTolerations()) - assert.DeepEqual(t, deployment.Spec.Template.Spec.Resources.Requests, corev1.ResourceList{ - corev1.ResourceCPU: resourcev1.MustParse("100m"), - corev1.ResourceMemory: resourcev1.MustParse("64Mi"), - }) - assert.DeepEqual(t, deployment.Spec.Template.Spec.Resources.Limits, corev1.ResourceList{ - corev1.ResourceCPU: resourcev1.MustParse("200m"), - corev1.ResourceMemory: resourcev1.MustParse("128Mi"), - }) -} - func addKnownTypesToScheme(scheme *runtime.Scheme) { scheme.AddKnownTypes(configv1.GroupVersion, &configv1.ClusterVersion{}) scheme.AddKnownTypes(pipelinesv1alpha1.GroupVersion, &pipelinesv1alpha1.GitopsService{}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go index 4f523bc6386..348b34b807d 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go @@ -49,7 +49,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { }) }() - By("verifying the openshift-gitops resources have honoured the resource constraints") + By("verifying the openshift-gitops resources have honoured the resource constraints") clusterDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}} Eventually(clusterDepl).Should( And( From b537dcba9b63b3e65aa84f87d7199283281651aa Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Wed, 17 Sep 2025 18:45:20 +0530 Subject: [PATCH 06/25] [GITOPS-7743]: Cluster, gitoops-backend are not getting cleanedup when disableDefaultinstance is true Signed-off-by: akhil nittala --- Makefile | 4 +- cmd/main.go | 7 ++- config/manager/kustomization.yaml | 3 +- config/manager/manager.yaml | 4 -- controllers/gitopsservice_controller.go | 48 ++------------------ controllers/gitopsservice_controller_test.go | 38 ++++++++++++++++ 6 files changed, 47 insertions(+), 57 deletions(-) diff --git a/Makefile b/Makefile index 9bc68ff3081..8c55d840a59 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # To re-generate a bundle for another specific version without changing the standard setup, you can: # - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) # - use environment variables to overwrite this value (e.g export VERSION=0.0.2) -VERSION ?= "2.0.6" +VERSION ?= "" # Try to detect Docker or Podman @@ -35,7 +35,7 @@ endif BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) # IMAGE defines the base image to be used for operator, bundle and catalog. -IMAGE ?= quay.io/nittalaakhil/openshift-gitops-operator +IMAGE ?= quay.io/redhat-developer/gitops-operator # IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. # This variable is used to construct full image tags for bundle and catalog images. diff --git a/cmd/main.go b/cmd/main.go index 4ef86cc13ea..c7b7d240a7e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -185,10 +185,9 @@ func main() { } if err = (&controllers.ReconcileGitopsService{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - DisableDefaultInstall: strings.ToLower(os.Getenv(common.DisableDefaultInstallEnvVar)) == "true", - DisableDefaultArgoCDConsoleLink: strings.ToLower(os.Getenv(common.DisableDefaultArgoCDConsoleLink)) == "true", + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + DisableDefaultInstall: strings.ToLower(os.Getenv(common.DisableDefaultInstallEnvVar)) == "true", }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "GitopsService") os.Exit(1) diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 7d85cf561f3..cb28eb6bac3 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -12,5 +12,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: quay.io/nittalaakhil/openshift-gitops-operator - newTag: 2.0.6 + newName: quay.io/redhat-developer/gitops-operator \ No newline at end of file diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 377ba434a83..c34b8d9e093 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -38,10 +38,6 @@ spec: value: gitops-operator - name : LABEL_SELECTOR value: "" - - name: DISABLE_DEFAULT_ARGOCD_CONSOLELINK - value: "true" - - name: DISABLE_DEFAULT_ARGOCD_INSTANCE - value: "true" image: controller:latest livenessProbe: httpGet: diff --git a/controllers/gitopsservice_controller.go b/controllers/gitopsservice_controller.go index 3b8afd3a7ed..328b57489bb 100644 --- a/controllers/gitopsservice_controller.go +++ b/controllers/gitopsservice_controller.go @@ -40,7 +40,6 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" resourcev1 "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -93,16 +92,6 @@ func (r *ReconcileGitopsService) SetupWithManager(mgr ctrl.Manager) error { } gitopsServiceRef := newGitopsService() - gitopsServiceRef.Spec.Resources = &corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - "cpu": resource.MustParse("200m"), - "memory": resource.MustParse("256Mi"), - }, - Limits: corev1.ResourceList{ - "cpu": resource.MustParse("500m"), - "memory": resource.MustParse("512Mi"), - }, - } err := r.Client.Create(context.TODO(), gitopsServiceRef) if err != nil { reqLogger.Error(err, "Failed to create GitOps service instance") @@ -143,9 +132,6 @@ type ReconcileGitopsService struct { // disableDefaultInstall, if true, will ensure that the default ArgoCD instance is not instantiated in the openshift-gitops namespace. DisableDefaultInstall bool - - // disableDefaultPluginInstall, if true, will ensure that the default Console Plugin is not instantiated in the openshift-gitops namespace. - DisableDefaultArgoCDConsoleLink bool } //+kubebuilder:rbac:groups=pipelines.openshift.io,resources=gitopsservices,verbs=get;list;watch;create;update;patch;delete @@ -227,7 +213,6 @@ func (r *ReconcileGitopsService) Reconcile(ctx context.Context, request reconcil // Fetch the GitopsService instance instance := &pipelinesv1alpha1.GitopsService{} err := r.Client.Get(ctx, types.NamespacedName{Name: serviceName}, instance) - reqLogger.Info("Fetched GitopsService instance", "instance", instance) if err != nil { if errors.IsNotFound(err) { // Request object not found, could have been deleted after reconcile request. @@ -285,10 +270,8 @@ func (r *ReconcileGitopsService) Reconcile(ctx context.Context, request reconcil } } - if !r.DisableDefaultArgoCDConsoleLink { - if result, err := r.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger); err != nil { - return result, err - } + if result, err := r.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger); err != nil { + return result, err } dynamicPluginStartOCPVersion := os.Getenv(dynamicPluginStartOCPVersionEnv) @@ -322,16 +305,9 @@ func (r *ReconcileGitopsService) Reconcile(ctx context.Context, request reconcil if realMajorVersion < startMajorVersion || (realMajorVersion == startMajorVersion && realMinorVersion < startMinorVersion) { // Skip plugin reconciliation if real OCP version is less than dynamic plugin start OCP version return reconcile.Result{}, nil - } else if !r.DisableDefaultArgoCDConsoleLink { + } else { return r.reconcilePlugin(instance, request) } - if r.DisableDefaultArgoCDConsoleLink { - logs.Info("Skipping reconciliation of ArgoCD ConsoleLink as it is disabled by env variable") - if err := r.ensureConsoleLinkDoesntExist(); err != nil { - return reconcile.Result{}, fmt.Errorf("unable to ensure non-existence of ArgoCD ConsoleLink: %v", err) - } - } - return reconcile.Result{}, nil } func (r *ReconcileGitopsService) ensureDefaultArgoCDInstanceDoesntExist(instance *pipelinesv1alpha1.GitopsService, reqLogger logr.Logger) error { @@ -370,24 +346,6 @@ func (r *ReconcileGitopsService) ensureDefaultArgoCDInstanceDoesntExist(instance return nil } -func (r *ReconcileGitopsService) ensureConsoleLinkDoesntExist() error { - consoleLink := &pipelinesv1alpha1.GitopsService{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: serviceName}, consoleLink) - if err == nil { - // The Argo CD ConsoleLink exists, delete it. - if err := r.Client.Delete(context.TODO(), consoleLink); err != nil { - return err - } - } else { - if !errors.IsNotFound(err) { - // If an unexpected error occurred (eg not the 'not found' error, which is expected) then just return it - return nil - } else { - return err - } - } - return nil -} func (r *ReconcileGitopsService) reconcileDefaultArgoCDInstance(instance *pipelinesv1alpha1.GitopsService, reqLogger logr.Logger) (reconcile.Result, error) { defaultArgoCDInstance, err := argocd.NewCR(common.ArgoCDInstanceName, serviceNamespace) diff --git a/controllers/gitopsservice_controller_test.go b/controllers/gitopsservice_controller_test.go index 158658314b3..e1bbc300588 100644 --- a/controllers/gitopsservice_controller_test.go +++ b/controllers/gitopsservice_controller_test.go @@ -22,7 +22,9 @@ import ( "testing" argoapp "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocommon "github.com/argoproj-labs/argocd-operator/common" "github.com/argoproj-labs/argocd-operator/controllers/argocd" + "github.com/argoproj-labs/argocd-operator/controllers/argoutil" configv1 "github.com/openshift/api/config/v1" consolev1 "github.com/openshift/api/console/v1" routev1 "github.com/openshift/api/route/v1" @@ -598,6 +600,42 @@ func TestGetBackendNamespace(t *testing.T) { }) } +func TestReconcile_InfrastructureNode(t *testing.T) { + logf.SetLogger(argocd.ZapLogger(true)) + s := scheme.Scheme + addKnownTypesToScheme(s) + gitopsService := &pipelinesv1alpha1.GitopsService{ + ObjectMeta: v1.ObjectMeta{ + Name: serviceName, + }, + Spec: pipelinesv1alpha1.GitopsServiceSpec{ + RunOnInfra: true, + Tolerations: deploymentDefaultTolerations(), + }, + } + fakeClient := fake.NewFakeClient(gitopsService) + reconciler := newReconcileGitOpsService(fakeClient, s) + + _, err := reconciler.Reconcile(context.TODO(), newRequest("test", "test")) + assertNoError(t, err) + + deployment := appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, &deployment) + assertNoError(t, err) + nSelector := common.InfraNodeSelector() + argoutil.AppendStringMap(nSelector, argocommon.DefaultNodeSelector()) + assert.DeepEqual(t, deployment.Spec.Template.Spec.NodeSelector, nSelector) + assert.DeepEqual(t, deployment.Spec.Template.Spec.Tolerations, deploymentDefaultTolerations()) + + argoCD := &argoapp.ArgoCD{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: common.ArgoCDInstanceName, Namespace: serviceNamespace}, + argoCD) + assertNoError(t, err) + assert.DeepEqual(t, argoCD.Spec.NodePlacement.NodeSelector, common.InfraNodeSelector()) + assert.DeepEqual(t, argoCD.Spec.NodePlacement.Tolerations, deploymentDefaultTolerations()) + +} + func TestReconcile_PSSLabels(t *testing.T) { logf.SetLogger(argocd.ZapLogger(true)) s := scheme.Scheme From c6ffed57daec611cfd8594e4ada862df00f2a924 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Wed, 17 Sep 2025 18:46:57 +0530 Subject: [PATCH 07/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- config/manager/kustomization.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index cb28eb6bac3..c7ac940f7d1 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -12,4 +12,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: quay.io/redhat-developer/gitops-operator \ No newline at end of file + newName: quay.io/redhat-developer/gitops-operator From 360bdba86edbb629e11ee219a2d94ac6541a4201 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Thu, 18 Sep 2025 17:58:39 +0530 Subject: [PATCH 08/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- controllers/consoleplugin.go | 4 - controllers/consoleplugin_test.go | 90 ++++++++++++++++++ controllers/gitopsservice_controller_test.go | 99 ++++++++++++++++++++ 3 files changed, 189 insertions(+), 4 deletions(-) diff --git a/controllers/consoleplugin.go b/controllers/consoleplugin.go index bc683c83e00..20691fdb683 100644 --- a/controllers/consoleplugin.go +++ b/controllers/consoleplugin.go @@ -292,10 +292,6 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop newPluginDeployment.Spec.Template.Spec.Tolerations = cr.Spec.Tolerations } - if cr.Spec.Resources != nil { - newPluginDeployment.Spec.Template.Spec.Resources = cr.Spec.Resources - } - // Check if this Deployment already exists existingPluginDeployment := &appsv1.Deployment{} diff --git a/controllers/consoleplugin_test.go b/controllers/consoleplugin_test.go index e990850f465..5196c3f82dd 100644 --- a/controllers/consoleplugin_test.go +++ b/controllers/consoleplugin_test.go @@ -1005,6 +1005,96 @@ func TestPlugin_reconcileDeployment(t *testing.T) { assertNoError(t, err) } +func TestPlugin_reconcileDeployment_ChangedResources(t *testing.T) { + s := scheme.Scheme + addKnownTypesToScheme(s) + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() + reconciler := newReconcileGitOpsService(fakeClient, s) + instance := &pipelinesv1alpha1.GitopsService{ + Spec: pipelinesv1alpha1.GitopsServiceSpec{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("256Mi"), + corev1.ResourceCPU: resourcev1.MustParse("500m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("512Mi"), + corev1.ResourceCPU: resourcev1.MustParse("1"), + }, + }, + }, + } + + _, err := reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) + assertNoError(t, err) + + deployment := &appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: gitopsPluginName, Namespace: serviceNamespace}, deployment) + assertNoError(t, err) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("256Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("500m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("512Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("1")) +} + +func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { + s := scheme.Scheme + addKnownTypesToScheme(s) + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() + reconciler := newReconcileGitOpsService(fakeClient, s) + instance := &pipelinesv1alpha1.GitopsService{ + Spec: pipelinesv1alpha1.GitopsServiceSpec{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("256Mi"), + corev1.ResourceCPU: resourcev1.MustParse("500m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("512Mi"), + corev1.ResourceCPU: resourcev1.MustParse("1"), + }, + }, + }, + } + + _, err := reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) + assertNoError(t, err) + + deployment := &appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: gitopsPluginName, Namespace: serviceNamespace}, deployment) + assertNoError(t, err) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("256Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("500m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("512Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("1")) + + // Update the resource values again + instance.Spec.Resources = &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("128Mi"), + corev1.ResourceCPU: resourcev1.MustParse("250m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("256Mi"), + corev1.ResourceCPU: resourcev1.MustParse("500m"), + }, + } + + _, err = reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) + assertNoError(t, err) + + deployment = &appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: gitopsPluginName, Namespace: serviceNamespace}, deployment) + assertNoError(t, err) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("128Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("250m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("256Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("500m")) + +} + func TestPlugin_reconcileService(t *testing.T) { s := scheme.Scheme addKnownTypesToScheme(s) diff --git a/controllers/gitopsservice_controller_test.go b/controllers/gitopsservice_controller_test.go index e1bbc300588..a4259d0ee0f 100644 --- a/controllers/gitopsservice_controller_test.go +++ b/controllers/gitopsservice_controller_test.go @@ -741,6 +741,105 @@ func TestReconcile_PSSLabels(t *testing.T) { } } +func TestReconcileBackend_ResourceRequestsAndLimits(t *testing.T) { + logf.SetLogger(argocd.ZapLogger(true)) + s := scheme.Scheme + addKnownTypesToScheme(s) + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() + reconciler := newReconcileGitOpsService(fakeClient, s) + instance := &pipelinesv1alpha1.GitopsService{ + Spec: pipelinesv1alpha1.GitopsServiceSpec{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("256Mi"), + corev1.ResourceCPU: resourcev1.MustParse("500m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("512Mi"), + corev1.ResourceCPU: resourcev1.MustParse("1"), + }, + }, + }, + } + gitopsserviceNamespacedName := types.NamespacedName{ + Name: serviceName, + Namespace: serviceNamespace, + } + reqLogger := logs.WithValues("Request.Namespace", "test", "Request.Name", "test") + _, err := reconciler.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger) + assertNoError(t, err) + + // verify whether backend deployment is created with user defined resource requests and limits + deployment := &appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deployment) + assertNoError(t, err) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("256Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("500m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("512Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("1")) +} + +func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *testing.T) { + + logf.SetLogger(argocd.ZapLogger(true)) + s := scheme.Scheme + addKnownTypesToScheme(s) + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() + reconciler := newReconcileGitOpsService(fakeClient, s) + instance := &pipelinesv1alpha1.GitopsService{ + Spec: pipelinesv1alpha1.GitopsServiceSpec{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("256Mi"), + corev1.ResourceCPU: resourcev1.MustParse("500m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("512Mi"), + corev1.ResourceCPU: resourcev1.MustParse("1"), + }, + }, + }, + } + gitopsserviceNamespacedName := types.NamespacedName{ + Name: serviceName, + Namespace: serviceNamespace, + } + reqLogger := logs.WithValues("Request.Namespace", "test", "Request.Name", "test") + _, err := reconciler.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger) + assertNoError(t, err) + + // verify whether backend deployment is created with user defined resource requests and limits + deployment := &appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deployment) + assertNoError(t, err) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("256Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("500m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("512Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("1")) + + // Update resource requests and limits in GitopsService CR + instance.Spec.Resources = &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("128Mi"), + corev1.ResourceCPU: resourcev1.MustParse("250m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("256Mi"), + corev1.ResourceCPU: resourcev1.MustParse("500m"), + }, + } + _, err = reconciler.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger) + assertNoError(t, err) + + // verify whether backend deployment is updated with new resource requests and limits + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deployment) + assertNoError(t, err) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("128Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("250m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("256Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("500m")) +} + func addKnownTypesToScheme(scheme *runtime.Scheme) { scheme.AddKnownTypes(configv1.GroupVersion, &configv1.ClusterVersion{}) scheme.AddKnownTypes(pipelinesv1alpha1.GroupVersion, &pipelinesv1alpha1.GitopsService{}) From 1016289526dba4d922f24c041983cc3e5d04755b Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Thu, 18 Sep 2025 18:19:25 +0530 Subject: [PATCH 09/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- test/openshift/e2e/ginkgo/fixture/deployment/fixture.go | 4 ++-- ...1-120-validate_resource_constraints_gitopsservicee_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go b/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go index fb649bd0beb..dce7e6a9315 100644 --- a/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go +++ b/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go @@ -400,8 +400,8 @@ func HaveServiceAccountName(expectedServiceAccountName string) matcher.GomegaMat // HaveResourceRequirements validates if the deployment object contains the given resource requirements. func HaveResourceRequirements(requirements *corev1.ResourceRequirements) matcher.GomegaMatcher { return fetchDeployment(func(depl *appsv1.Deployment) bool { - GinkgoWriter.Println("Deployment HaveResourceRequirements:", "expected: ", requirements.String(), "actual: ", depl.Spec.Template.Spec.Resources.String()) - return reflect.DeepEqual(requirements, depl.Spec.Template.Spec.Resources) + GinkgoWriter.Println("Deployment HaveResourceRequirements:", "expected: ", requirements.String(), "actual: ", depl.Spec.Template.Spec.Containers[0].Resources.String()) + return reflect.DeepEqual(requirements, depl.Spec.Template.Spec.Containers[0].Resources) }) } diff --git a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go index 348b34b807d..3fb726b27b5 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go @@ -23,7 +23,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { }) It("validates that GitOpsService can take in custom resource constraints", func() { - + fixture.EnsureRunningOnOpenShift() By("enabling resource constraints on GitOpsService CR") gitopsService := &gitopsoperatorv1alpha1.GitopsService{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, From ac443934c3a117c05e95117f9e5f13d9cccf3177 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Thu, 18 Sep 2025 18:20:49 +0530 Subject: [PATCH 10/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- controllers/gitopsservice_controller.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/controllers/gitopsservice_controller.go b/controllers/gitopsservice_controller.go index 328b57489bb..2921a7a07bb 100644 --- a/controllers/gitopsservice_controller.go +++ b/controllers/gitopsservice_controller.go @@ -623,6 +623,9 @@ func (r *ReconcileGitopsService) reconcileBackend(gitopsserviceNamespacedName ty if len(instance.Spec.NodeSelector) > 0 { deploymentObj.Spec.Template.Spec.NodeSelector = argocdutil.AppendStringMap(deploymentObj.Spec.Template.Spec.NodeSelector, instance.Spec.NodeSelector) } + if len(instance.Spec.Tolerations) > 0 { + deploymentObj.Spec.Template.Spec.Tolerations = instance.Spec.Tolerations + } if instance.Spec.Resources != nil { deploymentObj.Spec.Template.Spec.Containers[0].Resources = *instance.Spec.Resources } From 2c259c6b576c53edc57fabf497219f551fdf9146 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Thu, 18 Sep 2025 19:14:03 +0530 Subject: [PATCH 11/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- ...esource_constraints_gitopsservicee_test.go | 179 +++++++++++++++--- 1 file changed, 154 insertions(+), 25 deletions(-) diff --git a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go index 3fb726b27b5..62aaf7c1946 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go @@ -1,17 +1,20 @@ package parallel import ( + "context" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" - deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" gitopsserviceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/gitopsservice" k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" ) var _ = Describe("GitOps Operator Parallel E2E Tests", func() { @@ -19,25 +22,124 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-120-validate_resource_constraints_gitopsservice_test", func() { BeforeEach(func() { fixture.EnsureSequentialCleanSlate() - }) It("validates that GitOpsService can take in custom resource constraints", func() { - fixture.EnsureRunningOnOpenShift() - By("enabling resource constraints on GitOpsService CR") + + By("ensuring the GitOpsService CR is created with Resource constraints set") + k8sClient, _ := utils.GetE2ETestKubeClient() + + // Clean up the GitOpsService CR so we can test patching it next + Expect(k8sClient.Delete(context.Background(), &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + Namespace: "openshift-gitops", + }, + })).To(Succeed()) + // Ensure the GitOpsService CR is deleted before proceeding + Eventually(func() bool { + gitopsService := &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + Namespace: "openshift-gitops", + }, + } + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsService), gitopsService) + return err != nil + }).Should(BeTrue()) + + gitops := &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + Namespace: "openshift-gitops", + }, + Spec: gitopsoperatorv1alpha1.GitopsServiceSpec{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, + }, + }, + } + + Expect(k8sClient.Create(context.Background(), gitops)).To(Succeed()) + Expect(gitops).To(k8sFixture.ExistByName()) + + // Ensure the change is reverted when the test exits + defer func() { + gitopsserviceFixture.Update(gitops, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.Resources = nil + }) + }() + By("verifying the openshift-gitops resources have honoured the resource constraints") + clusterDepl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + Namespace: "openshift-gitops", + }, + } + gitopsPluginDepl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "gitops-plugin", + Namespace: "openshift-gitops", + }, + } + // Verify the resource constraints are honoured for gitops-plugin deployment + Eventually(func() corev1.ResourceRequirements { + _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) + return gitopsPluginDepl.Spec.Template.Spec.Containers[0].Resources + }).Should(SatisfyAll( + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + })), + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + })), + )) + + // Verify the resource constraints are honoured for cluster deployment + Eventually(func() corev1.ResourceRequirements { + _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(clusterDepl), clusterDepl) + return clusterDepl.Spec.Template.Spec.Containers[0].Resources + }).Should(SatisfyAll( + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + })), + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + })), + )) + }) + + It("validates that GitOpsService can update resource constraints", func() { + By("enabling resource constraints on GitOpsService CR as a patch") gitopsService := &gitopsoperatorv1alpha1.GitopsService{ - ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + Namespace: "openshift-gitops", + }, } Expect(gitopsService).To(k8sFixture.ExistByName()) + + // Set resource constraints gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.Resources = &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - "cpu": resource.MustParse("200m"), - "memory": resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), }, Limits: corev1.ResourceList{ - "cpu": resource.MustParse("500m"), - "memory": resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), }, } }) @@ -49,22 +151,49 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { }) }() - By("verifying the openshift-gitops resources have honoured the resource constraints") - clusterDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}} - Eventually(clusterDepl).Should( - And( - deploymentFixture.HaveResourceRequirements(&corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - "cpu": resource.MustParse("200m"), - "memory": resource.MustParse("256Mi"), - }, - Limits: corev1.ResourceList{ - "cpu": resource.MustParse("500m"), - "memory": resource.MustParse("512Mi"), - }, - }), - ), - ) + k8sClient, _ := utils.GetE2ETestKubeClient() + By("verifying the openshift-gitops resources have honoured the resource constraints") + clusterDepl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + Namespace: "openshift-gitops", + }, + } + gitopsPluginDepl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "gitops-plugin", + Namespace: "openshift-gitops", + }, + } + // Verify the resource constraints are honoured for gitops-plugin deployment + Eventually(func() corev1.ResourceRequirements { + _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) + return gitopsPluginDepl.Spec.Template.Spec.Containers[0].Resources + }).Should(SatisfyAll( + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + })), + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + })), + )) + // Verify the resource constraints are honoured for cluster deployment + Eventually(func() corev1.ResourceRequirements { + _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(clusterDepl), clusterDepl) + return clusterDepl.Spec.Template.Spec.Containers[0].Resources + }).Should(SatisfyAll( + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + })), + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + })), + )) + }) }) }) From 1f4360263e7cab9929701e7dc10f8cfa31cc3db8 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Fri, 19 Sep 2025 12:13:20 +0530 Subject: [PATCH 12/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- controllers/consoleplugin_test.go | 70 ++++++++++++------- controllers/gitopsservice_controller_test.go | 66 +++++++++++------ ...esource_constraints_gitopsservicee_test.go | 4 +- 3 files changed, 94 insertions(+), 46 deletions(-) diff --git a/controllers/consoleplugin_test.go b/controllers/consoleplugin_test.go index 5196c3f82dd..c022d3d9ecf 100644 --- a/controllers/consoleplugin_test.go +++ b/controllers/consoleplugin_test.go @@ -1005,6 +1005,7 @@ func TestPlugin_reconcileDeployment(t *testing.T) { assertNoError(t, err) } +// Test to verify if the resource values are updated when the resource values are changed in the CR func TestPlugin_reconcileDeployment_ChangedResources(t *testing.T) { s := scheme.Scheme addKnownTypesToScheme(s) @@ -1015,12 +1016,12 @@ func TestPlugin_reconcileDeployment_ChangedResources(t *testing.T) { Spec: pipelinesv1alpha1.GitopsServiceSpec{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("256Mi"), - corev1.ResourceCPU: resourcev1.MustParse("500m"), + corev1.ResourceMemory: resourcev1.MustParse("123Mi"), + corev1.ResourceCPU: resourcev1.MustParse("234m"), }, Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("512Mi"), - corev1.ResourceCPU: resourcev1.MustParse("1"), + corev1.ResourceMemory: resourcev1.MustParse("456Mi"), + corev1.ResourceCPU: resourcev1.MustParse("5"), }, }, }, @@ -1032,12 +1033,33 @@ func TestPlugin_reconcileDeployment_ChangedResources(t *testing.T) { deployment := &appsv1.Deployment{} err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: gitopsPluginName, Namespace: serviceNamespace}, deployment) assertNoError(t, err) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("256Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("500m")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("512Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("1")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("123Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("234m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("456Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("5")) } +// Test to verify if the default resource values are set when no resource values are provided in the CR +func TestPlugin_ReconcileDeployment_DefaultResourceValues(t *testing.T) { + s := scheme.Scheme + addKnownTypesToScheme(s) + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() + reconciler := newReconcileGitOpsService(fakeClient, s) + instance := &pipelinesv1alpha1.GitopsService{} + _, err := reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) + assertNoError(t, err) + + deployment := &appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: gitopsPluginName, Namespace: serviceNamespace}, deployment) + assertNoError(t, err) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("128Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("250m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("256Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("500m")) +} + +// Test to verify if the resource values are updated when the resource values are changed in the CR func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { s := scheme.Scheme addKnownTypesToScheme(s) @@ -1048,12 +1070,12 @@ func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { Spec: pipelinesv1alpha1.GitopsServiceSpec{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("256Mi"), - corev1.ResourceCPU: resourcev1.MustParse("500m"), + corev1.ResourceMemory: resourcev1.MustParse("123i"), + corev1.ResourceCPU: resourcev1.MustParse("234m"), }, Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("512Mi"), - corev1.ResourceCPU: resourcev1.MustParse("1"), + corev1.ResourceMemory: resourcev1.MustParse("456Mi"), + corev1.ResourceCPU: resourcev1.MustParse("5"), }, }, }, @@ -1065,20 +1087,20 @@ func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { deployment := &appsv1.Deployment{} err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: gitopsPluginName, Namespace: serviceNamespace}, deployment) assertNoError(t, err) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("256Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("500m")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("512Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("1")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("123Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("234m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("456Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("5")) // Update the resource values again instance.Spec.Resources = &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("128Mi"), - corev1.ResourceCPU: resourcev1.MustParse("250m"), + corev1.ResourceMemory: resourcev1.MustParse("100Mi"), + corev1.ResourceCPU: resourcev1.MustParse("200m"), }, Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("256Mi"), - corev1.ResourceCPU: resourcev1.MustParse("500m"), + corev1.ResourceMemory: resourcev1.MustParse("300Mi"), + corev1.ResourceCPU: resourcev1.MustParse("400m"), }, } @@ -1088,10 +1110,10 @@ func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { deployment = &appsv1.Deployment{} err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: gitopsPluginName, Namespace: serviceNamespace}, deployment) assertNoError(t, err) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("128Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("250m")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("256Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("500m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("100Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("200m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("300Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("400m")) } diff --git a/controllers/gitopsservice_controller_test.go b/controllers/gitopsservice_controller_test.go index a4259d0ee0f..936d3f82925 100644 --- a/controllers/gitopsservice_controller_test.go +++ b/controllers/gitopsservice_controller_test.go @@ -741,6 +741,7 @@ func TestReconcile_PSSLabels(t *testing.T) { } } +// TestReconcileBackend_ResourceRequestsAndLimits tests whether backend deployment is created with user defined resource requests and limits func TestReconcileBackend_ResourceRequestsAndLimits(t *testing.T) { logf.SetLogger(argocd.ZapLogger(true)) s := scheme.Scheme @@ -751,12 +752,12 @@ func TestReconcileBackend_ResourceRequestsAndLimits(t *testing.T) { Spec: pipelinesv1alpha1.GitopsServiceSpec{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("256Mi"), - corev1.ResourceCPU: resourcev1.MustParse("500m"), + corev1.ResourceMemory: resourcev1.MustParse("123Mi"), + corev1.ResourceCPU: resourcev1.MustParse("234m"), }, Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("512Mi"), - corev1.ResourceCPU: resourcev1.MustParse("1"), + corev1.ResourceMemory: resourcev1.MustParse("456Mi"), + corev1.ResourceCPU: resourcev1.MustParse("5"), }, }, }, @@ -773,12 +774,13 @@ func TestReconcileBackend_ResourceRequestsAndLimits(t *testing.T) { deployment := &appsv1.Deployment{} err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deployment) assertNoError(t, err) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("256Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("500m")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("512Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("1")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("123Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("234m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("456Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("5")) } +// TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits tests whether backend deployment is updated with new resource requests and limits func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *testing.T) { logf.SetLogger(argocd.ZapLogger(true)) @@ -790,12 +792,12 @@ func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *tes Spec: pipelinesv1alpha1.GitopsServiceSpec{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("256Mi"), - corev1.ResourceCPU: resourcev1.MustParse("500m"), + corev1.ResourceMemory: resourcev1.MustParse("123Mi"), + corev1.ResourceCPU: resourcev1.MustParse("234m"), }, Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("512Mi"), - corev1.ResourceCPU: resourcev1.MustParse("1"), + corev1.ResourceMemory: resourcev1.MustParse("456Mi"), + corev1.ResourceCPU: resourcev1.MustParse("5"), }, }, }, @@ -812,20 +814,20 @@ func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *tes deployment := &appsv1.Deployment{} err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deployment) assertNoError(t, err) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("256Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("500m")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("512Mi")) - assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("1")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("123Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("234m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("456Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("5")) // Update resource requests and limits in GitopsService CR instance.Spec.Resources = &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("128Mi"), - corev1.ResourceCPU: resourcev1.MustParse("250m"), + corev1.ResourceMemory: resourcev1.MustParse("100Mi"), + corev1.ResourceCPU: resourcev1.MustParse("200m"), }, Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("256Mi"), - corev1.ResourceCPU: resourcev1.MustParse("500m"), + corev1.ResourceMemory: resourcev1.MustParse("300Mi"), + corev1.ResourceCPU: resourcev1.MustParse("400m"), }, } _, err = reconciler.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger) @@ -834,6 +836,30 @@ func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *tes // verify whether backend deployment is updated with new resource requests and limits err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deployment) assertNoError(t, err) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("100Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("200m")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("300Mi")) + assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("400m")) +} + +func TestReconcileBackend_DefaultRequestsAndLimits(t *testing.T) { + logf.SetLogger(argocd.ZapLogger(true)) + s := scheme.Scheme + addKnownTypesToScheme(s) + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() + reconciler := newReconcileGitOpsService(fakeClient, s) + instance := &pipelinesv1alpha1.GitopsService{} + gitopsserviceNamespacedName := types.NamespacedName{ + Name: serviceName, + Namespace: serviceNamespace, + } + reqLogger := logs.WithValues("Request.Namespace", "test", "Request.Name", "test") + _, err := reconciler.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger) + assertNoError(t, err) + // verify whether backend deployment is created with default resource requests and limits + deployment := &appsv1.Deployment{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deployment) + assertNoError(t, err) assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["memory"], resourcev1.MustParse("128Mi")) assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Requests["cpu"], resourcev1.MustParse("250m")) assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["memory"], resourcev1.MustParse("256Mi")) diff --git a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go index 62aaf7c1946..89e4fed3643 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go @@ -21,14 +21,14 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-120-validate_resource_constraints_gitopsservice_test", func() { BeforeEach(func() { - fixture.EnsureSequentialCleanSlate() + fixture.EnsureParallelCleanSlate() }) It("validates that GitOpsService can take in custom resource constraints", func() { By("ensuring the GitOpsService CR is created with Resource constraints set") k8sClient, _ := utils.GetE2ETestKubeClient() - + fixture.EnsureRunningOnOpenShift() // Clean up the GitOpsService CR so we can test patching it next Expect(k8sClient.Delete(context.Background(), &gitopsoperatorv1alpha1.GitopsService{ ObjectMeta: metav1.ObjectMeta{ From 3fe27d884b532f9c2d40e5702e0297803d49bbeb Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Fri, 19 Sep 2025 12:18:06 +0530 Subject: [PATCH 13/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- controllers/consoleplugin_test.go | 2 +- ...esource_constraints_gitopsservicee_test.go | 48 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/controllers/consoleplugin_test.go b/controllers/consoleplugin_test.go index c022d3d9ecf..0cbeb0e89ea 100644 --- a/controllers/consoleplugin_test.go +++ b/controllers/consoleplugin_test.go @@ -1070,7 +1070,7 @@ func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { Spec: pipelinesv1alpha1.GitopsServiceSpec{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("123i"), + corev1.ResourceMemory: resourcev1.MustParse("123Mi"), corev1.ResourceCPU: resourcev1.MustParse("234m"), }, Limits: corev1.ResourceList{ diff --git a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go index 89e4fed3643..985bac523fa 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go @@ -56,12 +56,12 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Spec: gitopsoperatorv1alpha1.GitopsServiceSpec{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), }, Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), }, }, }, @@ -95,12 +95,12 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { return gitopsPluginDepl.Spec.Template.Spec.Containers[0].Resources }).Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), })), WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), })), )) @@ -110,12 +110,12 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { return clusterDepl.Spec.Template.Spec.Containers[0].Resources }).Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), })), WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), })), )) }) @@ -134,12 +134,12 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.Resources = &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), }, Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), }, } }) @@ -171,12 +171,12 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { return gitopsPluginDepl.Spec.Template.Spec.Containers[0].Resources }).Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), })), WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), })), )) // Verify the resource constraints are honoured for cluster deployment @@ -185,12 +185,12 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { return clusterDepl.Spec.Template.Spec.Containers[0].Resources }).Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), })), WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), })), )) From 05c5764af8e5611c2b0f1c01c749b7d4e4a09225 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Fri, 19 Sep 2025 13:06:08 +0530 Subject: [PATCH 14/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- ... 1-121-validate_resource_constraints_gitopsservicee_test.go} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/openshift/e2e/ginkgo/parallel/{1-120-validate_resource_constraints_gitopsservicee_test.go => 1-121-validate_resource_constraints_gitopsservicee_test.go} (99%) diff --git a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go similarity index 99% rename from test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go rename to test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go index 985bac523fa..027a6c61691 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-120-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go @@ -19,7 +19,7 @@ import ( var _ = Describe("GitOps Operator Parallel E2E Tests", func() { - Context("1-120-validate_resource_constraints_gitopsservice_test", func() { + Context("1-121-validate_resource_constraints_gitopsservice_test", func() { BeforeEach(func() { fixture.EnsureParallelCleanSlate() }) From c6e49f3660cb99f1696527fb6fa62edcae698d42 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Fri, 19 Sep 2025 18:31:42 +0530 Subject: [PATCH 15/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- .../1-121-validate_resource_constraints_gitopsservicee_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go index 027a6c61691..f9ce997c866 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go @@ -28,7 +28,6 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { By("ensuring the GitOpsService CR is created with Resource constraints set") k8sClient, _ := utils.GetE2ETestKubeClient() - fixture.EnsureRunningOnOpenShift() // Clean up the GitOpsService CR so we can test patching it next Expect(k8sClient.Delete(context.Background(), &gitopsoperatorv1alpha1.GitopsService{ ObjectMeta: metav1.ObjectMeta{ From 5bbd786a329509f0c08b54bf5c9a92441ce19d3e Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Fri, 19 Sep 2025 18:45:31 +0530 Subject: [PATCH 16/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- ...-121-validate_resource_constraints_gitopsservicee_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go index f9ce997c866..7f77e42a22d 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go @@ -7,6 +7,7 @@ import ( . "github.com/onsi/gomega" gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" gitopsserviceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/gitopsservice" k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" @@ -88,6 +89,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Namespace: "openshift-gitops", }, } + Eventually(clusterDepl, "5m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(gitopsPluginDepl, "5m", "5s").Should(argocdFixture.BeAvailable()) // Verify the resource constraints are honoured for gitops-plugin deployment Eventually(func() corev1.ResourceRequirements { _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) @@ -164,6 +167,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Namespace: "openshift-gitops", }, } + Eventually(clusterDepl, "5m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(gitopsPluginDepl, "5m", "5s").Should(argocdFixture.BeAvailable()) // Verify the resource constraints are honoured for gitops-plugin deployment Eventually(func() corev1.ResourceRequirements { _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) From 7b11d5c6af500843e97b728f622b7c6331bee681 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Mon, 22 Sep 2025 15:50:36 +0530 Subject: [PATCH 17/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- ...date_resource_constraints_gitopsservicee_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go index 7f77e42a22d..02b5eea061f 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go @@ -2,12 +2,13 @@ package parallel import ( "context" + "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" - argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" gitopsserviceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/gitopsservice" k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" @@ -70,6 +71,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Expect(k8sClient.Create(context.Background(), gitops)).To(Succeed()) Expect(gitops).To(k8sFixture.ExistByName()) + time.Sleep(60 * time.Second) // Give some time for the operator to react to the new CR // Ensure the change is reverted when the test exits defer func() { gitopsserviceFixture.Update(gitops, func(gs *gitopsoperatorv1alpha1.GitopsService) { @@ -89,8 +91,9 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Namespace: "openshift-gitops", }, } - Eventually(clusterDepl, "5m", "5s").Should(argocdFixture.BeAvailable()) - Eventually(gitopsPluginDepl, "5m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(clusterDepl, "4m", "5s").Should(deployment.HaveAvailableReplicas(1)) + Eventually(gitopsPluginDepl, "4m", "5s").Should(deployment.HaveAvailableReplicas(1)) + // Verify the resource constraints are honoured for gitops-plugin deployment Eventually(func() corev1.ResourceRequirements { _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) @@ -167,8 +170,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Namespace: "openshift-gitops", }, } - Eventually(clusterDepl, "5m", "5s").Should(argocdFixture.BeAvailable()) - Eventually(gitopsPluginDepl, "5m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(clusterDepl, "4m", "5s").Should(deployment.HaveAvailableReplicas(1)) + Eventually(gitopsPluginDepl, "4m", "5s").Should(deployment.HaveAvailableReplicas(1)) // Verify the resource constraints are honoured for gitops-plugin deployment Eventually(func() corev1.ResourceRequirements { _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) From e5a8fcdc43f5bd5da5b4e7141d926f9bc9f0ce99 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Tue, 23 Sep 2025 14:57:42 +0530 Subject: [PATCH 18/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- ...esource_constraints_gitopsservice_test.go} | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) rename test/openshift/e2e/ginkgo/{parallel/1-121-validate_resource_constraints_gitopsservicee_test.go => sequential/1-121-valiate_resource_constraints_gitopsservice_test.go} (88%) diff --git a/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go similarity index 88% rename from test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go rename to test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go index 02b5eea061f..b32350e8f03 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-121-validate_resource_constraints_gitopsservicee_test.go +++ b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go @@ -1,4 +1,4 @@ -package parallel +package sequential import ( "context" @@ -8,7 +8,6 @@ import ( . "github.com/onsi/gomega" gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" - "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" gitopsserviceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/gitopsservice" k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" @@ -19,11 +18,11 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -var _ = Describe("GitOps Operator Parallel E2E Tests", func() { +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { Context("1-121-validate_resource_constraints_gitopsservice_test", func() { BeforeEach(func() { - fixture.EnsureParallelCleanSlate() + fixture.EnsureSequentialCleanSlate() }) It("validates that GitOpsService can take in custom resource constraints", func() { @@ -91,14 +90,15 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Namespace: "openshift-gitops", }, } - Eventually(clusterDepl, "4m", "5s").Should(deployment.HaveAvailableReplicas(1)) - Eventually(gitopsPluginDepl, "4m", "5s").Should(deployment.HaveAvailableReplicas(1)) - // Verify the resource constraints are honoured for gitops-plugin deployment Eventually(func() corev1.ResourceRequirements { _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) - return gitopsPluginDepl.Spec.Template.Spec.Containers[0].Resources - }).Should(SatisfyAll( + containers := gitopsPluginDepl.Spec.Template.Spec.Containers + if len(containers) == 0 { + return corev1.ResourceRequirements{} + } + return containers[0].Resources + }, "2m", "5s").Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), corev1.ResourceMemory: resource.MustParse("200Mi"), @@ -112,8 +112,12 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { // Verify the resource constraints are honoured for cluster deployment Eventually(func() corev1.ResourceRequirements { _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(clusterDepl), clusterDepl) - return clusterDepl.Spec.Template.Spec.Containers[0].Resources - }).Should(SatisfyAll( + containers := clusterDepl.Spec.Template.Spec.Containers + if len(containers) == 0 { + return corev1.ResourceRequirements{} + } + return containers[0].Resources + }, "2m", "5s").Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), corev1.ResourceMemory: resource.MustParse("200Mi"), @@ -170,12 +174,15 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Namespace: "openshift-gitops", }, } - Eventually(clusterDepl, "4m", "5s").Should(deployment.HaveAvailableReplicas(1)) - Eventually(gitopsPluginDepl, "4m", "5s").Should(deployment.HaveAvailableReplicas(1)) + // Now you can safely check for available replicas and resource requirements // Verify the resource constraints are honoured for gitops-plugin deployment Eventually(func() corev1.ResourceRequirements { _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) - return gitopsPluginDepl.Spec.Template.Spec.Containers[0].Resources + containers := gitopsPluginDepl.Spec.Template.Spec.Containers + if len(containers) == 0 { + return corev1.ResourceRequirements{} + } + return containers[0].Resources }).Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), @@ -189,7 +196,11 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { // Verify the resource constraints are honoured for cluster deployment Eventually(func() corev1.ResourceRequirements { _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(clusterDepl), clusterDepl) - return clusterDepl.Spec.Template.Spec.Containers[0].Resources + containers := clusterDepl.Spec.Template.Spec.Containers + if len(containers) == 0 { + return corev1.ResourceRequirements{} + } + return containers[0].Resources }).Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), From 87bf422407f8a02339f7ed9d75b460a9b584656c Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Wed, 24 Sep 2025 14:31:25 +0530 Subject: [PATCH 19/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- api/v1alpha1/gitopsservice_types.go | 21 +- api/v1alpha1/zz_generated.deepcopy.go | 63 +++++- ...pipelines.openshift.io_gitopsservices.yaml | 199 ++++++++++++------ controllers/consoleplugin.go | 4 +- controllers/consoleplugin_test.go | 48 ++--- controllers/gitopsservice_controller.go | 4 +- controllers/gitopsservice_controller_test.go | 47 +++-- ...resource_constraints_gitopsservice_test.go | 194 ++++++++++++++--- 8 files changed, 433 insertions(+), 147 deletions(-) diff --git a/api/v1alpha1/gitopsservice_types.go b/api/v1alpha1/gitopsservice_types.go index d2cd0c77af9..edf6fd1aff8 100644 --- a/api/v1alpha1/gitopsservice_types.go +++ b/api/v1alpha1/gitopsservice_types.go @@ -32,8 +32,27 @@ type GitopsServiceSpec struct { Tolerations []corev1.Toleration `json:"tolerations,omitempty"` // NodeSelector is a map of key value pairs used for node selection in the default workloads NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // ConsolePlugin defines the Resource configuration for the Console Plugin components + ConsolePlugin ConsolePluginResourceStruct `json:"consolePlugin,omitempty"` +} + +type ConsolePluginResourceStruct struct { + // Enable indicates whether to deploy the console plugin resources + Enable bool `json:"enable,omitempty"` + + // Backend defines the resource requests and limits for the backend service + Backend BackendResourceStruct `json:"backend,omitempty"` + // GitopsPlugin defines the resource requests and limits for the gitops plugin service + GitopsPlugin GitopsPluginResourceStruct `json:"gitopsPlugin,omitempty"` +} + +type BackendResourceStruct struct { + // Resources defines the resource requests and limits for the backend service + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` +} - // Resources defines the Compute Resources required by the console-plugin and gitops-backend pods. +type GitopsPluginResourceStruct struct { + // Resources defines the resource requests and limits for the gitops plugin service Resources *corev1.ResourceRequirements `json:"resources,omitempty"` } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index a5d7ce72bde..03fe4b1c7b8 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -25,6 +25,63 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackendResourceStruct) DeepCopyInto(out *BackendResourceStruct) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = new(v1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendResourceStruct. +func (in *BackendResourceStruct) DeepCopy() *BackendResourceStruct { + if in == nil { + return nil + } + out := new(BackendResourceStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConsolePluginResourceStruct) DeepCopyInto(out *ConsolePluginResourceStruct) { + *out = *in + in.Backend.DeepCopyInto(&out.Backend) + in.GitopsPlugin.DeepCopyInto(&out.GitopsPlugin) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsolePluginResourceStruct. +func (in *ConsolePluginResourceStruct) DeepCopy() *ConsolePluginResourceStruct { + if in == nil { + return nil + } + out := new(ConsolePluginResourceStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitopsPluginResourceStruct) DeepCopyInto(out *GitopsPluginResourceStruct) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = new(v1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitopsPluginResourceStruct. +func (in *GitopsPluginResourceStruct) DeepCopy() *GitopsPluginResourceStruct { + if in == nil { + return nil + } + out := new(GitopsPluginResourceStruct) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GitopsService) DeepCopyInto(out *GitopsService) { *out = *in @@ -101,11 +158,7 @@ func (in *GitopsServiceSpec) DeepCopyInto(out *GitopsServiceSpec) { (*out)[key] = val } } - if in.Resources != nil { - in, out := &in.Resources, &out.Resources - *out = new(v1.ResourceRequirements) - (*in).DeepCopyInto(*out) - } + in.ConsolePlugin.DeepCopyInto(&out.ConsolePlugin) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitopsServiceSpec. diff --git a/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml b/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml index 16d39d37a69..337793b889c 100644 --- a/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml +++ b/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml @@ -39,72 +39,151 @@ spec: spec: description: GitopsServiceSpec defines the desired state of GitopsService properties: - nodeSelector: - additionalProperties: - type: string - description: NodeSelector is a map of key value pairs used for node - selection in the default workloads - type: object - resources: - description: Resources defines the Compute Resources required by the - console-plugin and gitops-backend pods. + consolePlugin: + description: ConsolePlugin defines the Resource configuration for + the Console Plugin components properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. + backend: + description: Backend defines the resource requests and limits + for the backend service + properties: + resources: + description: Resources defines the resource requests and limits + for the backend service + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + enable: + description: Enable indicates whether to deploy the console plugin + resources + type: boolean + gitopsPlugin: + description: GitopsPlugin defines the resource requests and limits + for the gitops plugin service + properties: + resources: + description: Resources defines the resource requests and limits + for the gitops plugin service + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object type: object type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector is a map of key value pairs used for node + selection in the default workloads + type: object runOnInfra: description: InfraNodeEnabled will add infra NodeSelector to all the default workloads of gitops operator diff --git a/controllers/consoleplugin.go b/controllers/consoleplugin.go index 20691fdb683..0e2f440f32e 100644 --- a/controllers/consoleplugin.go +++ b/controllers/consoleplugin.go @@ -284,8 +284,8 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop newPluginDeployment.Spec.Template.Spec.NodeSelector = argocdutil.AppendStringMap(newPluginDeployment.Spec.Template.Spec.NodeSelector, cr.Spec.NodeSelector) } - if cr.Spec.Resources != nil { - newPluginDeployment.Spec.Template.Spec.Containers[0].Resources = *cr.Spec.Resources + if cr.Spec.ConsolePlugin.GitopsPlugin.Resources != nil { + newPluginDeployment.Spec.Template.Spec.Containers[0].Resources = *cr.Spec.ConsolePlugin.GitopsPlugin.Resources } if len(cr.Spec.Tolerations) > 0 { diff --git a/controllers/consoleplugin_test.go b/controllers/consoleplugin_test.go index 0cbeb0e89ea..388a4fbaca2 100644 --- a/controllers/consoleplugin_test.go +++ b/controllers/consoleplugin_test.go @@ -1013,19 +1013,19 @@ func TestPlugin_reconcileDeployment_ChangedResources(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() reconciler := newReconcileGitOpsService(fakeClient, s) instance := &pipelinesv1alpha1.GitopsService{ - Spec: pipelinesv1alpha1.GitopsServiceSpec{ - Resources: &corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("123Mi"), - corev1.ResourceCPU: resourcev1.MustParse("234m"), - }, - Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("456Mi"), - corev1.ResourceCPU: resourcev1.MustParse("5"), - }, - }, + Spec: pipelinesv1alpha1.GitopsServiceSpec{}, + } + Resources := &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("123Mi"), + corev1.ResourceCPU: resourcev1.MustParse("234m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("456Mi"), + corev1.ResourceCPU: resourcev1.MustParse("5"), }, } + instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = Resources, Resources _, err := reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) assertNoError(t, err) @@ -1067,20 +1067,19 @@ func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() reconciler := newReconcileGitOpsService(fakeClient, s) instance := &pipelinesv1alpha1.GitopsService{ - Spec: pipelinesv1alpha1.GitopsServiceSpec{ - Resources: &corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("123Mi"), - corev1.ResourceCPU: resourcev1.MustParse("234m"), - }, - Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("456Mi"), - corev1.ResourceCPU: resourcev1.MustParse("5"), - }, - }, + Spec: pipelinesv1alpha1.GitopsServiceSpec{}, + } + Resources := &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("123Mi"), + corev1.ResourceCPU: resourcev1.MustParse("234m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("456Mi"), + corev1.ResourceCPU: resourcev1.MustParse("5"), }, } - + instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = Resources, Resources _, err := reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) assertNoError(t, err) @@ -1093,7 +1092,7 @@ func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("5")) // Update the resource values again - instance.Spec.Resources = &corev1.ResourceRequirements{ + updatedResources := &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceMemory: resourcev1.MustParse("100Mi"), corev1.ResourceCPU: resourcev1.MustParse("200m"), @@ -1103,6 +1102,7 @@ func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { corev1.ResourceCPU: resourcev1.MustParse("400m"), }, } + instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = updatedResources, updatedResources _, err = reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) assertNoError(t, err) diff --git a/controllers/gitopsservice_controller.go b/controllers/gitopsservice_controller.go index 2921a7a07bb..52f7cbc756c 100644 --- a/controllers/gitopsservice_controller.go +++ b/controllers/gitopsservice_controller.go @@ -626,8 +626,8 @@ func (r *ReconcileGitopsService) reconcileBackend(gitopsserviceNamespacedName ty if len(instance.Spec.Tolerations) > 0 { deploymentObj.Spec.Template.Spec.Tolerations = instance.Spec.Tolerations } - if instance.Spec.Resources != nil { - deploymentObj.Spec.Template.Spec.Containers[0].Resources = *instance.Spec.Resources + if instance.Spec.ConsolePlugin.Backend.Resources != nil { + deploymentObj.Spec.Template.Spec.Containers[0].Resources = *instance.Spec.ConsolePlugin.Backend.Resources } // Check if this Deployment already exists found := &appsv1.Deployment{} diff --git a/controllers/gitopsservice_controller_test.go b/controllers/gitopsservice_controller_test.go index 936d3f82925..95cd02e21bb 100644 --- a/controllers/gitopsservice_controller_test.go +++ b/controllers/gitopsservice_controller_test.go @@ -749,19 +749,19 @@ func TestReconcileBackend_ResourceRequestsAndLimits(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() reconciler := newReconcileGitOpsService(fakeClient, s) instance := &pipelinesv1alpha1.GitopsService{ - Spec: pipelinesv1alpha1.GitopsServiceSpec{ - Resources: &corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("123Mi"), - corev1.ResourceCPU: resourcev1.MustParse("234m"), - }, - Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("456Mi"), - corev1.ResourceCPU: resourcev1.MustParse("5"), - }, - }, + Spec: pipelinesv1alpha1.GitopsServiceSpec{}, + } + Resources := &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("123Mi"), + corev1.ResourceCPU: resourcev1.MustParse("234m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("456Mi"), + corev1.ResourceCPU: resourcev1.MustParse("5"), }, } + instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = Resources, Resources gitopsserviceNamespacedName := types.NamespacedName{ Name: serviceName, Namespace: serviceNamespace, @@ -789,19 +789,19 @@ func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *tes fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(newGitopsService()).Build() reconciler := newReconcileGitOpsService(fakeClient, s) instance := &pipelinesv1alpha1.GitopsService{ - Spec: pipelinesv1alpha1.GitopsServiceSpec{ - Resources: &corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("123Mi"), - corev1.ResourceCPU: resourcev1.MustParse("234m"), - }, - Limits: corev1.ResourceList{ - corev1.ResourceMemory: resourcev1.MustParse("456Mi"), - corev1.ResourceCPU: resourcev1.MustParse("5"), - }, - }, + Spec: pipelinesv1alpha1.GitopsServiceSpec{}, + } + Resources := &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("123Mi"), + corev1.ResourceCPU: resourcev1.MustParse("234m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resourcev1.MustParse("456Mi"), + corev1.ResourceCPU: resourcev1.MustParse("5"), }, } + instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = Resources, Resources gitopsserviceNamespacedName := types.NamespacedName{ Name: serviceName, Namespace: serviceNamespace, @@ -820,7 +820,7 @@ func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *tes assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"], resourcev1.MustParse("5")) // Update resource requests and limits in GitopsService CR - instance.Spec.Resources = &corev1.ResourceRequirements{ + updatedResource := &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceMemory: resourcev1.MustParse("100Mi"), corev1.ResourceCPU: resourcev1.MustParse("200m"), @@ -830,6 +830,7 @@ func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *tes corev1.ResourceCPU: resourcev1.MustParse("400m"), }, } + instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = updatedResource, updatedResource _, err = reconciler.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger) assertNoError(t, err) diff --git a/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go index b32350e8f03..4c7c0c87a32 100644 --- a/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go +++ b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go @@ -54,27 +54,43 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { Namespace: "openshift-gitops", }, Spec: gitopsoperatorv1alpha1.GitopsServiceSpec{ - Resources: &corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("200Mi"), + ConsolePlugin: gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ + Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), + }, + }, }, - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("300m"), - corev1.ResourceMemory: resource.MustParse("400Mi"), + GitopsPlugin: gitopsoperatorv1alpha1.GitopsPluginResourceStruct{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), + }, + }, }, }, }, } - Expect(k8sClient.Create(context.Background(), gitops)).To(Succeed()) Expect(gitops).To(k8sFixture.ExistByName()) - time.Sleep(60 * time.Second) // Give some time for the operator to react to the new CR + time.Sleep(90 * time.Second) // Increased time for the operator to react to the new CR // Ensure the change is reverted when the test exits defer func() { gitopsserviceFixture.Update(gitops, func(gs *gitopsoperatorv1alpha1.GitopsService) { - gs.Spec.Resources = nil + gs.Spec.ConsolePlugin.Backend.Resources = nil + gs.Spec.ConsolePlugin.GitopsPlugin.Resources = nil }) }() By("verifying the openshift-gitops resources have honoured the resource constraints") @@ -98,7 +114,7 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { return corev1.ResourceRequirements{} } return containers[0].Resources - }, "2m", "5s").Should(SatisfyAll( + }, "3m", "5s").Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), corev1.ResourceMemory: resource.MustParse("200Mi"), @@ -117,7 +133,7 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { return corev1.ResourceRequirements{} } return containers[0].Resources - }, "2m", "5s").Should(SatisfyAll( + }, "3m", "5s").Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), corev1.ResourceMemory: resource.MustParse("200Mi"), @@ -141,22 +157,40 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { // Set resource constraints gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { - gs.Spec.Resources = &corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("200Mi"), + gs.Spec.ConsolePlugin = gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ + Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("123m"), + corev1.ResourceMemory: resource.MustParse("234Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("345m"), + corev1.ResourceMemory: resource.MustParse("456Mi"), + }, + }, }, - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("300m"), - corev1.ResourceMemory: resource.MustParse("400Mi"), + GitopsPlugin: gitopsoperatorv1alpha1.GitopsPluginResourceStruct{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("123m"), + corev1.ResourceMemory: resource.MustParse("234Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("345m"), + corev1.ResourceMemory: resource.MustParse("456Mi"), + }, + }, }, } }) + time.Sleep(90 * time.Second) // Increased time for the operator to react to the new CR // Ensure the change is reverted when the test exits defer func() { gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { - gs.Spec.Resources = nil + gs.Spec.ConsolePlugin.Backend.Resources = nil + gs.Spec.ConsolePlugin.GitopsPlugin.Resources = nil }) }() @@ -183,14 +217,14 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { return corev1.ResourceRequirements{} } return containers[0].Resources - }).Should(SatisfyAll( + }, "3m", "5s").Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("200Mi"), + corev1.ResourceCPU: resource.MustParse("123m"), + corev1.ResourceMemory: resource.MustParse("234Mi"), })), WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("300m"), - corev1.ResourceMemory: resource.MustParse("400Mi"), + corev1.ResourceCPU: resource.MustParse("345m"), + corev1.ResourceMemory: resource.MustParse("456Mi"), })), )) // Verify the resource constraints are honoured for cluster deployment @@ -201,17 +235,117 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { return corev1.ResourceRequirements{} } return containers[0].Resources - }).Should(SatisfyAll( + }, "3m", "5s").Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("200Mi"), + corev1.ResourceCPU: resource.MustParse("123m"), + corev1.ResourceMemory: resource.MustParse("234Mi"), })), WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("300m"), - corev1.ResourceMemory: resource.MustParse("400Mi"), + corev1.ResourceCPU: resource.MustParse("345m"), + corev1.ResourceMemory: resource.MustParse("456Mi"), })), )) }) + It("validates gitops plugin and backend can have different resource constraints", func() { + By("enabling resource constraints on GitOpsService CR as a patch") + gitopsService := &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + Namespace: "openshift-gitops", + }, + } + Expect(gitopsService).To(k8sFixture.ExistByName()) + + // Set resource constraints + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.ConsolePlugin = gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ + Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("123m"), + corev1.ResourceMemory: resource.MustParse("234Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("345m"), + corev1.ResourceMemory: resource.MustParse("456Mi"), + }, + }, + }, + GitopsPlugin: gitopsoperatorv1alpha1.GitopsPluginResourceStruct{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("223m"), + corev1.ResourceMemory: resource.MustParse("334Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("445m"), + corev1.ResourceMemory: resource.MustParse("556Mi"), + }, + }, + }, + } + }) + + time.Sleep(90 * time.Second) // Increased time for the operator to react to the new CR + // Ensure the change is reverted when the test exits + defer func() { + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.ConsolePlugin.Backend.Resources = nil + gs.Spec.ConsolePlugin.GitopsPlugin.Resources = nil + }) + }() + k8sClient, _ := utils.GetE2ETestKubeClient() + By("verifying the openshift-gitops resources have honoured the resource constraints") + clusterDepl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster", + Namespace: "openshift-gitops", + }, + } + gitopsPluginDepl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "gitops-plugin", + Namespace: "openshift-gitops", + }, + } + // Now you can safely check for available replicas and resource requirements + // Verify the resource constraints are honoured for gitops-plugin deployment + Eventually(func() corev1.ResourceRequirements { + _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) + containers := gitopsPluginDepl.Spec.Template.Spec.Containers + if len(containers) == 0 { + return corev1.ResourceRequirements{} + } + return containers[0].Resources + }, "3m", "5s").Should(SatisfyAll( + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("223m"), + corev1.ResourceMemory: resource.MustParse("334Mi"), + })), + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("445m"), + corev1.ResourceMemory: resource.MustParse("556Mi"), + })), + )) + // Verify the resource constraints are honoured for cluster deployment + Eventually(func() corev1.ResourceRequirements { + _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(clusterDepl), clusterDepl) + containers := clusterDepl.Spec.Template.Spec.Containers + if len(containers) == 0 { + return corev1.ResourceRequirements{} + } + return containers[0].Resources + }, "3m", "5s").Should(SatisfyAll( + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("123m"), + corev1.ResourceMemory: resource.MustParse("234Mi"), + })), + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("345m"), + corev1.ResourceMemory: resource.MustParse("456Mi"), + })), + )) + }) }) }) From b139e6e7ef74a532c50f07dbc9ac0f09002a402d Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Wed, 24 Sep 2025 14:42:57 +0530 Subject: [PATCH 20/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- api/v1alpha1/gitopsservice_types.go | 3 + ...gitops-operator.clusterserviceversion.yaml | 2 +- ...pipelines.openshift.io_gitopsservices.yaml | 199 ++++++++++++------ 3 files changed, 143 insertions(+), 61 deletions(-) diff --git a/api/v1alpha1/gitopsservice_types.go b/api/v1alpha1/gitopsservice_types.go index edf6fd1aff8..9625955e2bc 100644 --- a/api/v1alpha1/gitopsservice_types.go +++ b/api/v1alpha1/gitopsservice_types.go @@ -36,6 +36,7 @@ type GitopsServiceSpec struct { ConsolePlugin ConsolePluginResourceStruct `json:"consolePlugin,omitempty"` } +// ConsolePluginResourceStruct defines the resource configuration for the Console Plugin components type ConsolePluginResourceStruct struct { // Enable indicates whether to deploy the console plugin resources Enable bool `json:"enable,omitempty"` @@ -46,11 +47,13 @@ type ConsolePluginResourceStruct struct { GitopsPlugin GitopsPluginResourceStruct `json:"gitopsPlugin,omitempty"` } +// BackendResourceStruct defines the resource configuration for the Backend components type BackendResourceStruct struct { // Resources defines the resource requests and limits for the backend service Resources *corev1.ResourceRequirements `json:"resources,omitempty"` } +// GitopsPluginResourceStruct defines the resource configuration for the Gitops Plugin components type GitopsPluginResourceStruct struct { // Resources defines the resource requests and limits for the gitops plugin service Resources *corev1.ResourceRequirements `json:"resources,omitempty"` diff --git a/bundle/manifests/gitops-operator.clusterserviceversion.yaml b/bundle/manifests/gitops-operator.clusterserviceversion.yaml index 8eab92b978c..716d304c728 100644 --- a/bundle/manifests/gitops-operator.clusterserviceversion.yaml +++ b/bundle/manifests/gitops-operator.clusterserviceversion.yaml @@ -180,7 +180,7 @@ metadata: capabilities: Deep Insights console.openshift.io/plugins: '["gitops-plugin"]' containerImage: quay.io/redhat-developer/gitops-operator - createdAt: "2025-09-16T07:12:34Z" + createdAt: "2025-09-24T09:12:43Z" description: Enables teams to adopt GitOps principles for managing cluster configurations and application delivery across hybrid multi-cluster Kubernetes environments. features.operators.openshift.io/disconnected: "true" diff --git a/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml b/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml index 275d8dfb660..c2d6c7814b2 100644 --- a/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml +++ b/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml @@ -39,72 +39,151 @@ spec: spec: description: GitopsServiceSpec defines the desired state of GitopsService properties: - nodeSelector: - additionalProperties: - type: string - description: NodeSelector is a map of key value pairs used for node - selection in the default workloads - type: object - resources: - description: Resources defines the Compute Resources required by the - console-plugin and gitops-backend pods. + consolePlugin: + description: ConsolePlugin defines the Resource configuration for + the Console Plugin components properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. + backend: + description: Backend defines the resource requests and limits + for the backend service + properties: + resources: + description: Resources defines the resource requests and limits + for the backend service + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + enable: + description: Enable indicates whether to deploy the console plugin + resources + type: boolean + gitopsPlugin: + description: GitopsPlugin defines the resource requests and limits + for the gitops plugin service + properties: + resources: + description: Resources defines the resource requests and limits + for the gitops plugin service + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object type: object type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector is a map of key value pairs used for node + selection in the default workloads + type: object runOnInfra: description: InfraNodeEnabled will add infra NodeSelector to all the default workloads of gitops operator From 2b9b19aae5c103a240b23dd1de93e6d60a01f248 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Fri, 26 Sep 2025 15:14:17 +0530 Subject: [PATCH 21/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- ...resource_constraints_gitopsservice_test.go | 320 ++++++++---------- 1 file changed, 146 insertions(+), 174 deletions(-) diff --git a/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go index 4c7c0c87a32..9533212e55b 100644 --- a/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go +++ b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go @@ -2,14 +2,19 @@ package sequential import ( "context" + "strings" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + clusterserviceversionFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/clusterserviceversion" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" gitopsserviceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/gitopsservice" k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -18,41 +23,99 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) +// --- Helper Functions --- + +func getCSV(ctx context.Context, k8sClient client.Client) *olmv1alpha1.ClusterServiceVersion { + var csvList olmv1alpha1.ClusterServiceVersionList + Expect(k8sClient.List(ctx, &csvList, client.InNamespace("openshift-gitops-operator"))).To(Succeed()) + for idx := range csvList.Items { + idxCSV := csvList.Items[idx] + if strings.Contains(idxCSV.Name, "gitops-operator") { + return &idxCSV + } + } + return nil +} + +func getOCPVersion() string { + output, err := osFixture.ExecCommand("oc", "version") + Expect(err).ToNot(HaveOccurred()) + for _, line := range strings.Split(output, "\n") { + if strings.Contains(line, "Server Version:") { + return strings.TrimSpace(line[strings.Index(line, ":")+1:]) + } + } + return "" +} + +func addDynamicPluginEnv(csv *olmv1alpha1.ClusterServiceVersion, ocVersion string) { + clusterserviceversionFixture.Update(csv, func(csv *olmv1alpha1.ClusterServiceVersion) { + envList := csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Env + envList = append(envList, corev1.EnvVar{Name: "DYNAMIC_PLUGIN_START_OCP_VERSION", Value: ocVersion}) + csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Env = envList + }) +} + +func verifyResourceConstraints(k8sClient client.Client, deplName string, expectedReq, expectedLim corev1.ResourceList) { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deplName, Namespace: "openshift-gitops"}} + Eventually(func() corev1.ResourceRequirements { + _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(depl), depl) + containers := depl.Spec.Template.Spec.Containers + if len(containers) == 0 { + return corev1.ResourceRequirements{} + } + return containers[0].Resources + }, "3m", "5s").Should(SatisfyAll( + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(expectedReq)), + WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(expectedLim)), + )) +} + +// --- Test Suite --- + var _ = Describe("GitOps Operator Sequential E2E Tests", func() { Context("1-121-validate_resource_constraints_gitopsservice_test", func() { + var ( + ctx context.Context + k8sClient client.Client + ) BeforeEach(func() { fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() }) It("validates that GitOpsService can take in custom resource constraints", func() { + csv := getCSV(ctx, k8sClient) + Expect(csv).ToNot(BeNil()) + defer func() { Expect(fixture.RemoveDynamicPluginFromCSV(ctx, k8sClient)).To(Succeed()) }() + + ocVersion := getOCPVersion() + Expect(ocVersion).ToNot(BeEmpty()) + if strings.Contains(ocVersion, "4.15.") { + Skip("skipping this test as OCP version is 4.15") + return + } + addDynamicPluginEnv(csv, ocVersion) + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "gitops-plugin", Namespace: "openshift-gitops"}} + Eventually(depl, "3m", "5s").Should(k8sFixture.ExistByName()) + Eventually(depl, "60s", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) - By("ensuring the GitOpsService CR is created with Resource constraints set") - k8sClient, _ := utils.GetE2ETestKubeClient() - // Clean up the GitOpsService CR so we can test patching it next Expect(k8sClient.Delete(context.Background(), &gitopsoperatorv1alpha1.GitopsService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster", - Namespace: "openshift-gitops", - }, + ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}, })).To(Succeed()) - // Ensure the GitOpsService CR is deleted before proceeding Eventually(func() bool { gitopsService := &gitopsoperatorv1alpha1.GitopsService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster", - Namespace: "openshift-gitops", - }, + ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}, } err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsService), gitopsService) return err != nil }).Should(BeTrue()) gitops := &gitopsoperatorv1alpha1.GitopsService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster", - Namespace: "openshift-gitops", - }, + ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}, Spec: gitopsoperatorv1alpha1.GitopsServiceSpec{ ConsolePlugin: gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ @@ -85,77 +148,48 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { Expect(k8sClient.Create(context.Background(), gitops)).To(Succeed()) Expect(gitops).To(k8sFixture.ExistByName()) - time.Sleep(90 * time.Second) // Increased time for the operator to react to the new CR - // Ensure the change is reverted when the test exits + time.Sleep(90 * time.Second) defer func() { gitopsserviceFixture.Update(gitops, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.ConsolePlugin.Backend.Resources = nil gs.Spec.ConsolePlugin.GitopsPlugin.Resources = nil }) }() - By("verifying the openshift-gitops resources have honoured the resource constraints") - clusterDepl := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster", - Namespace: "openshift-gitops", - }, + + expectedReq := corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), } - gitopsPluginDepl := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gitops-plugin", - Namespace: "openshift-gitops", - }, + expectedLim := corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("300m"), + corev1.ResourceMemory: resource.MustParse("400Mi"), } - // Verify the resource constraints are honoured for gitops-plugin deployment - Eventually(func() corev1.ResourceRequirements { - _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) - containers := gitopsPluginDepl.Spec.Template.Spec.Containers - if len(containers) == 0 { - return corev1.ResourceRequirements{} - } - return containers[0].Resources - }, "3m", "5s").Should(SatisfyAll( - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("200Mi"), - })), - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("300m"), - corev1.ResourceMemory: resource.MustParse("400Mi"), - })), - )) - - // Verify the resource constraints are honoured for cluster deployment - Eventually(func() corev1.ResourceRequirements { - _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(clusterDepl), clusterDepl) - containers := clusterDepl.Spec.Template.Spec.Containers - if len(containers) == 0 { - return corev1.ResourceRequirements{} - } - return containers[0].Resources - }, "3m", "5s").Should(SatisfyAll( - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("200Mi"), - })), - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("300m"), - corev1.ResourceMemory: resource.MustParse("400Mi"), - })), - )) + verifyResourceConstraints(k8sClient, "gitops-plugin", expectedReq, expectedLim) + verifyResourceConstraints(k8sClient, "cluster", expectedReq, expectedLim) }) It("validates that GitOpsService can update resource constraints", func() { - By("enabling resource constraints on GitOpsService CR as a patch") + csv := getCSV(ctx, k8sClient) + Expect(csv).ToNot(BeNil()) + defer func() { Expect(fixture.RemoveDynamicPluginFromCSV(ctx, k8sClient)).To(Succeed()) }() + + ocVersion := getOCPVersion() + Expect(ocVersion).ToNot(BeEmpty()) + if strings.Contains(ocVersion, "4.15.") { + Skip("skipping this test as OCP version is 4.15") + return + } + addDynamicPluginEnv(csv, ocVersion) + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "gitops-plugin", Namespace: "openshift-gitops"}} + Eventually(depl, "3m", "5s").Should(k8sFixture.ExistByName()) + Eventually(depl, "60s", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + gitopsService := &gitopsoperatorv1alpha1.GitopsService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster", - Namespace: "openshift-gitops", - }, + ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}, } Expect(gitopsService).To(k8sFixture.ExistByName()) - // Set resource constraints gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.ConsolePlugin = gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ @@ -184,9 +218,7 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { }, } }) - time.Sleep(90 * time.Second) // Increased time for the operator to react to the new CR - - // Ensure the change is reverted when the test exits + time.Sleep(90 * time.Second) defer func() { gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.ConsolePlugin.Backend.Resources = nil @@ -195,69 +227,40 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { }() k8sClient, _ := utils.GetE2ETestKubeClient() - By("verifying the openshift-gitops resources have honoured the resource constraints") - clusterDepl := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster", - Namespace: "openshift-gitops", - }, + expectedReq := corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("123m"), + corev1.ResourceMemory: resource.MustParse("234Mi"), } - gitopsPluginDepl := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gitops-plugin", - Namespace: "openshift-gitops", - }, + expectedLim := corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("345m"), + corev1.ResourceMemory: resource.MustParse("456Mi"), } - // Now you can safely check for available replicas and resource requirements - // Verify the resource constraints are honoured for gitops-plugin deployment - Eventually(func() corev1.ResourceRequirements { - _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) - containers := gitopsPluginDepl.Spec.Template.Spec.Containers - if len(containers) == 0 { - return corev1.ResourceRequirements{} - } - return containers[0].Resources - }, "3m", "5s").Should(SatisfyAll( - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("123m"), - corev1.ResourceMemory: resource.MustParse("234Mi"), - })), - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("345m"), - corev1.ResourceMemory: resource.MustParse("456Mi"), - })), - )) - // Verify the resource constraints are honoured for cluster deployment - Eventually(func() corev1.ResourceRequirements { - _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(clusterDepl), clusterDepl) - containers := clusterDepl.Spec.Template.Spec.Containers - if len(containers) == 0 { - return corev1.ResourceRequirements{} - } - return containers[0].Resources - }, "3m", "5s").Should(SatisfyAll( - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("123m"), - corev1.ResourceMemory: resource.MustParse("234Mi"), - })), - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("345m"), - corev1.ResourceMemory: resource.MustParse("456Mi"), - })), - )) - + verifyResourceConstraints(k8sClient, "gitops-plugin", expectedReq, expectedLim) + verifyResourceConstraints(k8sClient, "cluster", expectedReq, expectedLim) }) + It("validates gitops plugin and backend can have different resource constraints", func() { - By("enabling resource constraints on GitOpsService CR as a patch") + csv := getCSV(ctx, k8sClient) + Expect(csv).ToNot(BeNil()) + defer func() { Expect(fixture.RemoveDynamicPluginFromCSV(ctx, k8sClient)).To(Succeed()) }() + + ocVersion := getOCPVersion() + Expect(ocVersion).ToNot(BeEmpty()) + if strings.Contains(ocVersion, "4.15.") { + Skip("skipping this test as OCP version is 4.15") + return + } + addDynamicPluginEnv(csv, ocVersion) + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "gitops-plugin", Namespace: "openshift-gitops"}} + Eventually(depl, "3m", "5s").Should(k8sFixture.ExistByName()) + Eventually(depl, "60s", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + gitopsService := &gitopsoperatorv1alpha1.GitopsService{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster", - Namespace: "openshift-gitops", - }, + ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}, } Expect(gitopsService).To(k8sFixture.ExistByName()) - // Set resource constraints gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.ConsolePlugin = gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ @@ -287,8 +290,7 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { } }) - time.Sleep(90 * time.Second) // Increased time for the operator to react to the new CR - // Ensure the change is reverted when the test exits + time.Sleep(90 * time.Second) defer func() { gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.ConsolePlugin.Backend.Resources = nil @@ -296,56 +298,26 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { }) }() k8sClient, _ := utils.GetE2ETestKubeClient() - By("verifying the openshift-gitops resources have honoured the resource constraints") - clusterDepl := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cluster", - Namespace: "openshift-gitops", - }, - } - gitopsPluginDepl := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gitops-plugin", - Namespace: "openshift-gitops", - }, - } - // Now you can safely check for available replicas and resource requirements - // Verify the resource constraints are honoured for gitops-plugin deployment - Eventually(func() corev1.ResourceRequirements { - _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(gitopsPluginDepl), gitopsPluginDepl) - containers := gitopsPluginDepl.Spec.Template.Spec.Containers - if len(containers) == 0 { - return corev1.ResourceRequirements{} - } - return containers[0].Resources - }, "3m", "5s").Should(SatisfyAll( - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ + verifyResourceConstraints(k8sClient, "gitops-plugin", + corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("223m"), corev1.ResourceMemory: resource.MustParse("334Mi"), - })), - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ + }, + corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("445m"), corev1.ResourceMemory: resource.MustParse("556Mi"), - })), - )) - // Verify the resource constraints are honoured for cluster deployment - Eventually(func() corev1.ResourceRequirements { - _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(clusterDepl), clusterDepl) - containers := clusterDepl.Spec.Template.Spec.Containers - if len(containers) == 0 { - return corev1.ResourceRequirements{} - } - return containers[0].Resources - }, "3m", "5s").Should(SatisfyAll( - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(corev1.ResourceList{ + }, + ) + verifyResourceConstraints(k8sClient, "cluster", + corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("123m"), corev1.ResourceMemory: resource.MustParse("234Mi"), - })), - WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(corev1.ResourceList{ + }, + corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("345m"), corev1.ResourceMemory: resource.MustParse("456Mi"), - })), - )) + }, + ) }) }) }) From 652f9c8356a6ff3ff3562f551a24f44e21474a29 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Wed, 1 Oct 2025 14:36:04 +0530 Subject: [PATCH 22/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- api/v1alpha1/gitopsservice_types.go | 21 ++++------ api/v1alpha1/zz_generated.deepcopy.go | 42 ++++++++++++------- ...gitops-operator.clusterserviceversion.yaml | 2 +- ...pipelines.openshift.io_gitopsservices.yaml | 4 -- ...pipelines.openshift.io_gitopsservices.yaml | 4 -- ...resource_constraints_gitopsservice_test.go | 18 ++++---- 6 files changed, 46 insertions(+), 45 deletions(-) diff --git a/api/v1alpha1/gitopsservice_types.go b/api/v1alpha1/gitopsservice_types.go index 9625955e2bc..7c76b65eccb 100644 --- a/api/v1alpha1/gitopsservice_types.go +++ b/api/v1alpha1/gitopsservice_types.go @@ -33,28 +33,25 @@ type GitopsServiceSpec struct { // NodeSelector is a map of key value pairs used for node selection in the default workloads NodeSelector map[string]string `json:"nodeSelector,omitempty"` // ConsolePlugin defines the Resource configuration for the Console Plugin components - ConsolePlugin ConsolePluginResourceStruct `json:"consolePlugin,omitempty"` + ConsolePlugin *ConsolePluginStruct `json:"consolePlugin,omitempty"` } -// ConsolePluginResourceStruct defines the resource configuration for the Console Plugin components -type ConsolePluginResourceStruct struct { - // Enable indicates whether to deploy the console plugin resources - Enable bool `json:"enable,omitempty"` - +// ConsolePluginStruct defines the resource configuration for the Console Plugin components +type ConsolePluginStruct struct { // Backend defines the resource requests and limits for the backend service - Backend BackendResourceStruct `json:"backend,omitempty"` + Backend *BackendStruct `json:"backend,omitempty"` // GitopsPlugin defines the resource requests and limits for the gitops plugin service - GitopsPlugin GitopsPluginResourceStruct `json:"gitopsPlugin,omitempty"` + GitopsPlugin *GitopsPluginStruct `json:"gitopsPlugin,omitempty"` } -// BackendResourceStruct defines the resource configuration for the Backend components -type BackendResourceStruct struct { +// BackendStruct defines the resource configuration for the Backend components +type BackendStruct struct { // Resources defines the resource requests and limits for the backend service Resources *corev1.ResourceRequirements `json:"resources,omitempty"` } -// GitopsPluginResourceStruct defines the resource configuration for the Gitops Plugin components -type GitopsPluginResourceStruct struct { +// GitopsPluginStruct defines the resource configuration for the Gitops Plugin components +type GitopsPluginStruct struct { // Resources defines the resource requests and limits for the gitops plugin service Resources *corev1.ResourceRequirements `json:"resources,omitempty"` } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 03fe4b1c7b8..e653c3054e3 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -26,7 +26,7 @@ import ( ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BackendResourceStruct) DeepCopyInto(out *BackendResourceStruct) { +func (in *BackendStruct) DeepCopyInto(out *BackendStruct) { *out = *in if in.Resources != nil { in, out := &in.Resources, &out.Resources @@ -35,35 +35,43 @@ func (in *BackendResourceStruct) DeepCopyInto(out *BackendResourceStruct) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendResourceStruct. -func (in *BackendResourceStruct) DeepCopy() *BackendResourceStruct { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendStruct. +func (in *BackendStruct) DeepCopy() *BackendStruct { if in == nil { return nil } - out := new(BackendResourceStruct) + out := new(BackendStruct) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ConsolePluginResourceStruct) DeepCopyInto(out *ConsolePluginResourceStruct) { +func (in *ConsolePluginStruct) DeepCopyInto(out *ConsolePluginStruct) { *out = *in - in.Backend.DeepCopyInto(&out.Backend) - in.GitopsPlugin.DeepCopyInto(&out.GitopsPlugin) + if in.Backend != nil { + in, out := &in.Backend, &out.Backend + *out = new(BackendStruct) + (*in).DeepCopyInto(*out) + } + if in.GitopsPlugin != nil { + in, out := &in.GitopsPlugin, &out.GitopsPlugin + *out = new(GitopsPluginStruct) + (*in).DeepCopyInto(*out) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsolePluginResourceStruct. -func (in *ConsolePluginResourceStruct) DeepCopy() *ConsolePluginResourceStruct { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsolePluginStruct. +func (in *ConsolePluginStruct) DeepCopy() *ConsolePluginStruct { if in == nil { return nil } - out := new(ConsolePluginResourceStruct) + out := new(ConsolePluginStruct) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitopsPluginResourceStruct) DeepCopyInto(out *GitopsPluginResourceStruct) { +func (in *GitopsPluginStruct) DeepCopyInto(out *GitopsPluginStruct) { *out = *in if in.Resources != nil { in, out := &in.Resources, &out.Resources @@ -72,12 +80,12 @@ func (in *GitopsPluginResourceStruct) DeepCopyInto(out *GitopsPluginResourceStru } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitopsPluginResourceStruct. -func (in *GitopsPluginResourceStruct) DeepCopy() *GitopsPluginResourceStruct { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitopsPluginStruct. +func (in *GitopsPluginStruct) DeepCopy() *GitopsPluginStruct { if in == nil { return nil } - out := new(GitopsPluginResourceStruct) + out := new(GitopsPluginStruct) in.DeepCopyInto(out) return out } @@ -158,7 +166,11 @@ func (in *GitopsServiceSpec) DeepCopyInto(out *GitopsServiceSpec) { (*out)[key] = val } } - in.ConsolePlugin.DeepCopyInto(&out.ConsolePlugin) + if in.ConsolePlugin != nil { + in, out := &in.ConsolePlugin, &out.ConsolePlugin + *out = new(ConsolePluginStruct) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitopsServiceSpec. diff --git a/bundle/manifests/gitops-operator.clusterserviceversion.yaml b/bundle/manifests/gitops-operator.clusterserviceversion.yaml index 716d304c728..e56aed13841 100644 --- a/bundle/manifests/gitops-operator.clusterserviceversion.yaml +++ b/bundle/manifests/gitops-operator.clusterserviceversion.yaml @@ -180,7 +180,7 @@ metadata: capabilities: Deep Insights console.openshift.io/plugins: '["gitops-plugin"]' containerImage: quay.io/redhat-developer/gitops-operator - createdAt: "2025-09-24T09:12:43Z" + createdAt: "2025-10-01T09:01:02Z" description: Enables teams to adopt GitOps principles for managing cluster configurations and application delivery across hybrid multi-cluster Kubernetes environments. features.operators.openshift.io/disconnected: "true" diff --git a/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml b/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml index c2d6c7814b2..792cc853bcb 100644 --- a/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml +++ b/bundle/manifests/pipelines.openshift.io_gitopsservices.yaml @@ -108,10 +108,6 @@ spec: type: object type: object type: object - enable: - description: Enable indicates whether to deploy the console plugin - resources - type: boolean gitopsPlugin: description: GitopsPlugin defines the resource requests and limits for the gitops plugin service diff --git a/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml b/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml index 337793b889c..1dd2f77a973 100644 --- a/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml +++ b/config/crd/bases/pipelines.openshift.io_gitopsservices.yaml @@ -108,10 +108,6 @@ spec: type: object type: object type: object - enable: - description: Enable indicates whether to deploy the console plugin - resources - type: boolean gitopsPlugin: description: GitopsPlugin defines the resource requests and limits for the gitops plugin service diff --git a/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go index 9533212e55b..fcfb30c837a 100644 --- a/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go +++ b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go @@ -117,8 +117,8 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { gitops := &gitopsoperatorv1alpha1.GitopsService{ ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}, Spec: gitopsoperatorv1alpha1.GitopsServiceSpec{ - ConsolePlugin: gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ - Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ + ConsolePlugin: &gitopsoperatorv1alpha1.ConsolePluginStruct{ + Backend: &gitopsoperatorv1alpha1.BackendStruct{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), @@ -130,7 +130,7 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { }, }, }, - GitopsPlugin: gitopsoperatorv1alpha1.GitopsPluginResourceStruct{ + GitopsPlugin: &gitopsoperatorv1alpha1.GitopsPluginStruct{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), @@ -191,8 +191,8 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { Expect(gitopsService).To(k8sFixture.ExistByName()) gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { - gs.Spec.ConsolePlugin = gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ - Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ + gs.Spec.ConsolePlugin = &gitopsoperatorv1alpha1.ConsolePluginStruct{ + Backend: &gitopsoperatorv1alpha1.BackendStruct{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("123m"), @@ -204,7 +204,7 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { }, }, }, - GitopsPlugin: gitopsoperatorv1alpha1.GitopsPluginResourceStruct{ + GitopsPlugin: &gitopsoperatorv1alpha1.GitopsPluginStruct{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("123m"), @@ -262,8 +262,8 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { Expect(gitopsService).To(k8sFixture.ExistByName()) gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { - gs.Spec.ConsolePlugin = gitopsoperatorv1alpha1.ConsolePluginResourceStruct{ - Backend: gitopsoperatorv1alpha1.BackendResourceStruct{ + gs.Spec.ConsolePlugin = &gitopsoperatorv1alpha1.ConsolePluginStruct{ + Backend: &gitopsoperatorv1alpha1.BackendStruct{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("123m"), @@ -275,7 +275,7 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { }, }, }, - GitopsPlugin: gitopsoperatorv1alpha1.GitopsPluginResourceStruct{ + GitopsPlugin: &gitopsoperatorv1alpha1.GitopsPluginStruct{ Resources: &corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("223m"), From 0198d6e5f640f1fc2014375ed4bc588ab62fd289 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Wed, 1 Oct 2025 15:22:52 +0530 Subject: [PATCH 23/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- controllers/consoleplugin.go | 2 +- controllers/gitopsservice_controller.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/consoleplugin.go b/controllers/consoleplugin.go index 0e2f440f32e..4ad49ad88d1 100644 --- a/controllers/consoleplugin.go +++ b/controllers/consoleplugin.go @@ -284,7 +284,7 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop newPluginDeployment.Spec.Template.Spec.NodeSelector = argocdutil.AppendStringMap(newPluginDeployment.Spec.Template.Spec.NodeSelector, cr.Spec.NodeSelector) } - if cr.Spec.ConsolePlugin.GitopsPlugin.Resources != nil { + if cr.Spec.ConsolePlugin != nil && cr.Spec.ConsolePlugin.GitopsPlugin != nil && cr.Spec.ConsolePlugin.GitopsPlugin.Resources != nil { newPluginDeployment.Spec.Template.Spec.Containers[0].Resources = *cr.Spec.ConsolePlugin.GitopsPlugin.Resources } diff --git a/controllers/gitopsservice_controller.go b/controllers/gitopsservice_controller.go index 52f7cbc756c..4eed23e575a 100644 --- a/controllers/gitopsservice_controller.go +++ b/controllers/gitopsservice_controller.go @@ -626,7 +626,7 @@ func (r *ReconcileGitopsService) reconcileBackend(gitopsserviceNamespacedName ty if len(instance.Spec.Tolerations) > 0 { deploymentObj.Spec.Template.Spec.Tolerations = instance.Spec.Tolerations } - if instance.Spec.ConsolePlugin.Backend.Resources != nil { + if instance.Spec.ConsolePlugin != nil && instance.Spec.ConsolePlugin.Backend != nil && instance.Spec.ConsolePlugin.Backend.Resources != nil { deploymentObj.Spec.Template.Spec.Containers[0].Resources = *instance.Spec.ConsolePlugin.Backend.Resources } // Check if this Deployment already exists From 4d2914bb99b35c82065aa7ebbc2398ae9b1dcfaa Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Wed, 1 Oct 2025 15:28:27 +0530 Subject: [PATCH 24/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- controllers/consoleplugin_test.go | 18 +++++++++++-- controllers/gitopsservice_controller_test.go | 28 +++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/controllers/consoleplugin_test.go b/controllers/consoleplugin_test.go index 388a4fbaca2..872e3d0c85c 100644 --- a/controllers/consoleplugin_test.go +++ b/controllers/consoleplugin_test.go @@ -1025,7 +1025,14 @@ func TestPlugin_reconcileDeployment_ChangedResources(t *testing.T) { corev1.ResourceCPU: resourcev1.MustParse("5"), }, } - instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = Resources, Resources + instance.Spec.ConsolePlugin = &pipelinesv1alpha1.ConsolePluginStruct{ + Backend: &pipelinesv1alpha1.BackendStruct{ + Resources: Resources, + }, + GitopsPlugin: &pipelinesv1alpha1.GitopsPluginStruct{ + Resources: Resources, + }, + } _, err := reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) assertNoError(t, err) @@ -1079,7 +1086,14 @@ func TestPlugin_ReconcileDeployment_ChangeExistingResourceValues(t *testing.T) { corev1.ResourceCPU: resourcev1.MustParse("5"), }, } - instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = Resources, Resources + instance.Spec.ConsolePlugin = &pipelinesv1alpha1.ConsolePluginStruct{ + Backend: &pipelinesv1alpha1.BackendStruct{ + Resources: Resources, + }, + GitopsPlugin: &pipelinesv1alpha1.GitopsPluginStruct{ + Resources: Resources, + }, + } _, err := reconciler.reconcileDeployment(instance, newRequest(serviceNamespace, gitopsPluginName)) assertNoError(t, err) diff --git a/controllers/gitopsservice_controller_test.go b/controllers/gitopsservice_controller_test.go index 95cd02e21bb..f1cb3742693 100644 --- a/controllers/gitopsservice_controller_test.go +++ b/controllers/gitopsservice_controller_test.go @@ -761,7 +761,15 @@ func TestReconcileBackend_ResourceRequestsAndLimits(t *testing.T) { corev1.ResourceCPU: resourcev1.MustParse("5"), }, } - instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = Resources, Resources + instance.Spec.ConsolePlugin = &pipelinesv1alpha1.ConsolePluginStruct{ + Backend: &pipelinesv1alpha1.BackendStruct{ + Resources: Resources, + }, + GitopsPlugin: &pipelinesv1alpha1.GitopsPluginStruct{ + Resources: Resources, + }, + } + gitopsserviceNamespacedName := types.NamespacedName{ Name: serviceName, Namespace: serviceNamespace, @@ -801,7 +809,14 @@ func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *tes corev1.ResourceCPU: resourcev1.MustParse("5"), }, } - instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = Resources, Resources + instance.Spec.ConsolePlugin = &pipelinesv1alpha1.ConsolePluginStruct{ + Backend: &pipelinesv1alpha1.BackendStruct{ + Resources: Resources, + }, + GitopsPlugin: &pipelinesv1alpha1.GitopsPluginStruct{ + Resources: Resources, + }, + } gitopsserviceNamespacedName := types.NamespacedName{ Name: serviceName, Namespace: serviceNamespace, @@ -830,7 +845,14 @@ func TestReconcileBackend_ModifyExistingValuesOfResourceRequestsAndLimits(t *tes corev1.ResourceCPU: resourcev1.MustParse("400m"), }, } - instance.Spec.ConsolePlugin.Backend.Resources, instance.Spec.ConsolePlugin.GitopsPlugin.Resources = updatedResource, updatedResource + instance.Spec.ConsolePlugin = &pipelinesv1alpha1.ConsolePluginStruct{ + Backend: &pipelinesv1alpha1.BackendStruct{ + Resources: updatedResource, + }, + GitopsPlugin: &pipelinesv1alpha1.GitopsPluginStruct{ + Resources: updatedResource, + }, + } _, err = reconciler.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger) assertNoError(t, err) From fa4c7c27990d7127bb27acd8592e46020b8906bd Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Mon, 13 Oct 2025 12:12:28 +0530 Subject: [PATCH 25/25] Resource requests and limits configurable Signed-off-by: akhil nittala --- ...-121-valiate_resource_constraints_gitopsservice_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go index fcfb30c837a..611315e5871 100644 --- a/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go +++ b/test/openshift/e2e/ginkgo/sequential/1-121-valiate_resource_constraints_gitopsservice_test.go @@ -3,7 +3,6 @@ package sequential import ( "context" "strings" - "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -65,7 +64,7 @@ func verifyResourceConstraints(k8sClient client.Client, deplName string, expecte return corev1.ResourceRequirements{} } return containers[0].Resources - }, "3m", "5s").Should(SatisfyAll( + }, "2m", "5s").Should(SatisfyAll( WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Requests }, Equal(expectedReq)), WithTransform(func(r corev1.ResourceRequirements) corev1.ResourceList { return r.Limits }, Equal(expectedLim)), )) @@ -148,7 +147,6 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { Expect(k8sClient.Create(context.Background(), gitops)).To(Succeed()) Expect(gitops).To(k8sFixture.ExistByName()) - time.Sleep(90 * time.Second) defer func() { gitopsserviceFixture.Update(gitops, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.ConsolePlugin.Backend.Resources = nil @@ -218,7 +216,7 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { }, } }) - time.Sleep(90 * time.Second) + defer func() { gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.ConsolePlugin.Backend.Resources = nil @@ -290,7 +288,6 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { } }) - time.Sleep(90 * time.Second) defer func() { gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { gs.Spec.ConsolePlugin.Backend.Resources = nil