Skip to content

Enable resoure configuration via Kruize CR#67

Open
shreyabiradar07 wants to merge 12 commits intokruize:mvp_demofrom
shreyabiradar07:add_resource_config
Open

Enable resoure configuration via Kruize CR#67
shreyabiradar07 wants to merge 12 commits intokruize:mvp_demofrom
shreyabiradar07:add_resource_config

Conversation

@shreyabiradar07
Copy link
Copy Markdown
Contributor

@shreyabiradar07 shreyabiradar07 commented Feb 20, 2026

This PR makes CPU, memory, and storage resources configurable via the Kruize CR instead of being hardcoded in the operator.

Summary by Sourcery

Make Kruize CPU, memory, and storage resources configurable via the Kruize custom resource instead of being hardcoded, while preserving sensible defaults.

New Features:

  • Introduce a ResourceConfig section on the Kruize CRD to configure CPU, memory, and persistent volume settings for the Kruize and database components.
  • Allow the resource generator to consume per-component resource configuration from the Kruize CR and apply it to Deployments and persistent storage objects across OpenShift and Kubernetes clusters.

Enhancements:

  • Centralize default CPU, memory, and PV/PVC settings into constants and use helper methods in the resource generator to compute effective resources with fallback behavior.
  • Extend the resource generator to accept a context and log when invalid resource quantities are provided, falling back to defaults.
  • Refactor tests to use shared helpers and cover default, custom, and partial resource configuration for Deployments, PVs, PVCs, Pods, and Services.

Documentation:

  • Update the sample Kruize custom resource to document optional resource and persistent volume configuration fields.

Tests:

  • Add comprehensive unit tests validating custom and default resource behavior for Kruize and database Deployments, including partial overrides and error handling for invalid quantities.
  • Add tests verifying PV and PVC sizing, storage class, host path, and access modes when configured via the CRD and when using defaults on both OpenShift and Kubernetes.

Signed-off-by: Shreya Biradar <shbirada@ibm.com>
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Feb 20, 2026

Reviewer's Guide

Enables configuring CPU/memory and PV/PVC resources for Kruize and its database via new fields on the Kruize CRD, wires those values through the controller into the resource generator, centralizes defaults, and adds extensive tests for defaulting, overrides, and persistence config on both OpenShift and Kubernetes.

Sequence diagram for applying Kruize CR resource configuration

sequenceDiagram
    actor Admin
    participant KubeAPI as Kubernetes_API_Server
    participant KruizeController as KruizeReconciler
    participant Generator as KruizeResourceGenerator
    participant K8sResources as Kubernetes_Resources

    Admin->>KubeAPI: Apply Kruize_CR(spec.resources)
    KubeAPI-->>KruizeController: Watch event for Kruize

    KruizeController->>KruizeController: deployKruizeComponents(ctx, namespace, kruize)
    KruizeController->>Generator: NewKruizeResourceGenerator(namespace, autotuneImage, autotuneUIImage, clusterType, kruize.Spec.Resources, ctx)

    KruizeController->>Generator: kruizeDBDeployment()
    Generator->>Generator: getDBResources()
    alt Database_resources_configured
        Generator->>Generator: getResourceValue(overrides, defaults)
        Generator->>Generator: parseResourceQuantity(configured, default)
    else No_DB_overrides
        Generator->>Generator: use DefaultDB* constants
    end
    Generator-->>KruizeController: Deployment with DB resources

    KruizeController->>Generator: kruizeDeployment()
    Generator->>Generator: getKruizeResources()
    alt Kruize_resources_configured
        Generator->>Generator: getResourceValue(overrides, defaults)
        Generator->>Generator: parseResourceQuantity(configured, default)
    else No_Kruize_overrides
        Generator->>Generator: use DefaultKruize* constants
    end
    Generator-->>KruizeController: Deployment with Kruize resources

    KruizeController->>Generator: kruizeDBPersistentVolume()/Claim()
    alt PersistentVolume_configured
        Generator->>Generator: getPVConfigWithDefaults(overrides)
        Generator->>Generator: parseResourceQuantity(pvSize, defaults)
    else No_PV_overrides
        Generator->>Generator: getPVConfigWithDefaults(defaults)
    end
    Generator-->>KruizeController: PV and PVC specs

    KruizeController->>KubeAPI: Create/Update Deployments, PV, PVC
    KubeAPI-->>K8sResources: Persist resources
Loading

Class diagram for new Kruize resource configuration types

classDiagram
    class KruizeSpec {
        +string namespace
        +string autotune_image
        +string autotune_ui_image
        +ResourceConfig resources
    }

    class ResourceConfig {
        +ContainerResources database
        +ContainerResources kruize
        +PersistentVolumeConfig persistentVolume
    }

    class ContainerResources {
        +string cpuRequest
        +string cpuLimit
        +string memoryRequest
        +string memoryLimit
    }

    class PersistentVolumeConfig {
        +string pvStorageSize
        +string pvcStorageSize
        +string storageClassName
        +string hostPath
        +PersistentVolumeAccessMode[] accessModes
    }

    class PersistentVolumeAccessMode {
        <<enum>>
        ReadWriteOnce
        ReadOnlyMany
        ReadWriteMany
        ReadWriteOncePod
    }

    KruizeSpec --> ResourceConfig : owns
    ResourceConfig --> ContainerResources : database
    ResourceConfig --> ContainerResources : kruize
    ResourceConfig --> PersistentVolumeConfig : persistentVolume
    PersistentVolumeConfig --> PersistentVolumeAccessMode : uses
Loading

Class diagram for updated KruizeResourceGenerator and defaults

classDiagram
    class KruizeResourceGenerator {
        +string Namespace
        +string Autotune_image
        +string Autotune_ui_image
        +string ClusterType
        +ResourceConfig ResourceConfig
        +context_Ctx Ctx
        +NewKruizeResourceGenerator(namespace autotuneImage autotuneUIImage clusterType resourceConfig ctx) KruizeResourceGenerator
        +ClusterScopedResources() []client_Object
        +ManualStorageClass() *storagev1_StorageClass
        +kruizeDBPersistentVolume() *corev1_PersistentVolume
        +kruizeDBPersistentVolumeClaim() *corev1_PersistentVolumeClaim
        +kruizeDBDeployment() *appsv1_Deployment
        +kruizeDeployment() *appsv1_Deployment
        +kruizeDBPersistentVolumeKubernetes() *corev1_PersistentVolume
        +kruizeDBPersistentVolumeClaimKubernetes() *corev1_PersistentVolumeClaim
        +kruizeDBDeploymentKubernetes() *appsv1_Deployment
        +kruizeDeploymentKubernetes() *appsv1_Deployment
        -getResourceValue(configValue defaultValue string) string
        -parseResourceQuantity(value defaultValue string) resource_Quantity
        -getDBResources() corev1_ResourceRequirements
        -getKruizeResources() corev1_ResourceRequirements
        -isValidAccessMode(mode string) bool
        -getPVConfigWithDefaults(defaultPVStorageSize defaultStorageClassName defaultHostPath string, defaultAccessModes []corev1_PersistentVolumeAccessMode) (pvStorageSize pvcStorageSize storageClassName hostPath string, accessModes []corev1_PersistentVolumeAccessMode)
        -getPVConfig() (pvStorageSize pvcStorageSize storageClassName hostPath string, accessModes []corev1_PersistentVolumeAccessMode)
        -getPVConfigKubernetes() (pvStorageSize pvcStorageSize storageClassName hostPath string, accessModes []corev1_PersistentVolumeAccessMode)
    }

    class ResourceDefaultsConstants {
        <<static>>
        +string DefaultDBCPURequest
        +string DefaultDBCPULimit
        +string DefaultDBMemoryRequest
        +string DefaultDBMemoryLimit
        +string DefaultKruizeCPURequest
        +string DefaultKruizeCPULimit
        +string DefaultKruizeMemoryRequest
        +string DefaultKruizeMemoryLimit
        +string DefaultOpenShiftPVStorageSize
        +string DefaultOpenShiftStorageClassName
        +string DefaultOpenShiftHostPath
        +string DefaultKubernetesPVStorageSize
        +string DefaultKubernetesStorageClassName
        +string DefaultKubernetesHostPath
    }

    class ResourceConfig {
    }

    KruizeResourceGenerator --> ResourceConfig : reads
    KruizeResourceGenerator ..> ResourceDefaultsConstants : uses
Loading

File-Level Changes

Change Details Files
Wire ResourceConfig from Kruize CR into resource generation and extend tests to cover custom and default resource behavior.
  • Add getTestContext helper and extend findTypedResource to allow name-only lookups plus several helpers for deployments, PVs, PVCs and containers in controller tests.
  • Update all NewKruizeResourceGenerator call sites in tests to pass ResourceConfig (or nil) and context.
  • Add tests for full and partial CPU/memory overrides for Kruize and DB deployments and for default resource behavior on both OpenShift and Kubernetes.
  • Add tests for PV/PVC configuration, including custom sizes, access modes, hostPath, storageClassName, nil ResourceConfig behavior, and PV vs PVC size fallback semantics.
  • Refactor existing service, route, and image tests to use the new helpers and generator signature.
internal/controller/kruize_controller_test.go
Extend KruizeResourceGenerator to accept ResourceConfig and context, centralize defaults, and consume config for container resources and PV/PVCs.
  • Add ResourceConfig and Ctx fields to KruizeResourceGenerator and extend constructor to accept resourceConfig and context.
  • Introduce helper methods getResourceValue, parseResourceQuantity, getDBResources, getKruizeResources, getPVConfigWithDefaults, getPVConfig, and getPVConfigKubernetes to compute container ResourceRequirements and PV/PVC config with defaulting and logging on invalid quantities.
  • Replace hardcoded DB and Kruize container ResourceRequirements in both OpenShift and Kubernetes deployments with calls to getDBResources and getKruizeResources.
  • Refactor OpenShift and Kubernetes PV/PVC generators to use the shared PV config helpers, including support for custom storage sizes, storageClassName, hostPath, and accessModes plus PVC size fallback to PV size.
  • Wire storage class name into the Kubernetes PV/PVC, and use parseResourceQuantity for PV/PVC storage quantities with safe defaults.
internal/utils/kruize_generator.go
Extend Kruize API and CRD schema to support configurable CPU/memory and persistent volume settings via the Kruize spec.
  • Add Resources field to KruizeSpec, along with ResourceConfig, ContainerResources, PersistentVolumeAccessMode, and PersistentVolumeConfig types for database, Kruize, and PV/PVC configuration.
  • Generate DeepCopy methods for the new API types and update Kruize and KruizeSpec deepcopy logic to handle nested Resources.
  • Update CRD (kruize.io_kruizes.yaml) to describe the new resources section, including validation for PersistentVolumeAccessMode enum and accessModes list.
  • Document example resources configuration in the sample Kruize CR YAML, including CPU/memory and persistentVolume fields with comments about defaults and valid values.
api/v1alpha1/kruize_types.go
api/v1alpha1/zz_generated.deepcopy.go
config/crd/bases/kruize.io_kruizes.yaml
config/samples/v1alpha1_kruize.yaml
Wire ResourceConfig from the Kruize reconciler into the resource generator and add centralized default constants for resources and PV/PVCs.
  • Update KruizeReconciler.deployKruizeComponents to pass kruize.Spec.Resources and the reconcile context into NewKruizeResourceGenerator.
  • Add a new constants/resource_defaults.go file defining default CPU/memory for Kruize and DB containers and default PV/PVC sizes, storageClassName, and hostPath for OpenShift and Kubernetes.
internal/controller/kruize_controller.go
internal/constants/resource_defaults.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@shreyabiradar07 shreyabiradar07 self-assigned this Feb 20, 2026
@shreyabiradar07 shreyabiradar07 added the enhancement New feature or request label Feb 20, 2026
@shreyabiradar07 shreyabiradar07 moved this to In Progress in Monitoring Feb 20, 2026
@shreyabiradar07 shreyabiradar07 added this to the Kruize Operator 0.0.5 milestone Feb 20, 2026
Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 7 issues, and left some high level feedback:

  • The new helpers rely on resource.MustParse for user-supplied values; consider using resource.ParseQuantity with validation/error handling so an invalid CR value doesn’t cause a controller panic.
  • getPVConfig and getPVConfigKubernetes duplicate most of their logic with only different defaults and storage class handling; extracting a shared helper with injected defaults would simplify maintenance.
  • When converting PersistentVolumeConfig.AccessModes from []string to []corev1.PersistentVolumeAccessMode, you currently trust the input; adding validation (or constraining the CRD schema to allowed enum values) would help avoid invalid modes slipping through.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new helpers rely on resource.MustParse for user-supplied values; consider using resource.ParseQuantity with validation/error handling so an invalid CR value doesn’t cause a controller panic.
- getPVConfig and getPVConfigKubernetes duplicate most of their logic with only different defaults and storage class handling; extracting a shared helper with injected defaults would simplify maintenance.
- When converting PersistentVolumeConfig.AccessModes from []string to []corev1.PersistentVolumeAccessMode, you currently trust the input; adding validation (or constraining the CRD schema to allowed enum values) would help avoid invalid modes slipping through.

## Individual Comments

### Comment 1
<location> `internal/utils/kruize_generator.go:72-81` </location>
<code_context>
+}
+
+// getDBResources returns database resource requirements with defaults
+func (g *KruizeResourceGenerator) getDBResources() corev1.ResourceRequirements {
+	cpuRequest := constants.DefaultDBCPURequest
+	cpuLimit := constants.DefaultDBCPULimit
+	memoryRequest := constants.DefaultDBMemoryRequest
+	memoryLimit := constants.DefaultDBMemoryLimit
+
+	if g.ResourceConfig != nil && g.ResourceConfig.Database != nil {
+		cpuRequest = g.getResourceValue(g.ResourceConfig.Database.CPURequest, cpuRequest)
+		cpuLimit = g.getResourceValue(g.ResourceConfig.Database.CPULimit, cpuLimit)
+		memoryRequest = g.getResourceValue(g.ResourceConfig.Database.MemoryRequest, memoryRequest)
+		memoryLimit = g.getResourceValue(g.ResourceConfig.Database.MemoryLimit, memoryLimit)
+	}
+
+	return corev1.ResourceRequirements{
+		Requests: corev1.ResourceList{
+			corev1.ResourceMemory: resource.MustParse(memoryRequest),
</code_context>

<issue_to_address>
**issue (bug_risk):** Using resource.MustParse on user-provided values can panic and crash the operator.

These values were previously hardcoded and safe, but now come from the CR and may be invalid. Since `resource.MustParse` panics on bad input, a malformed CPU/Memory value can crash the controller. Please switch to `resource.ParseQuantity` and handle errors (e.g., defaulting or setting a Status condition) to avoid panics from user misconfiguration.
</issue_to_address>

### Comment 2
<location> `internal/utils/kruize_generator.go:98-85` </location>
<code_context>
+}
+
+// getKruizeResources returns Kruize application resource requirements with defaults
+func (g *KruizeResourceGenerator) getKruizeResources() corev1.ResourceRequirements {
+	cpuRequest := constants.DefaultKruizeCPURequest
+	cpuLimit := constants.DefaultKruizeCPULimit
+	memoryRequest := constants.DefaultKruizeMemoryRequest
+	memoryLimit := constants.DefaultKruizeMemoryLimit
+
+	if g.ResourceConfig != nil && g.ResourceConfig.Kruize != nil {
+		cpuRequest = g.getResourceValue(g.ResourceConfig.Kruize.CPURequest, cpuRequest)
+		cpuLimit = g.getResourceValue(g.ResourceConfig.Kruize.CPULimit, cpuLimit)
+		memoryRequest = g.getResourceValue(g.ResourceConfig.Kruize.MemoryRequest, memoryRequest)
+		memoryLimit = g.getResourceValue(g.ResourceConfig.Kruize.MemoryLimit, memoryLimit)
+	}
+
+	return corev1.ResourceRequirements{
+		Requests: corev1.ResourceList{
+			corev1.ResourceMemory: resource.MustParse(memoryRequest),
</code_context>

<issue_to_address>
**issue (bug_risk):** Same panic risk in Kruize container resources due to resource.MustParse on CR input.

Since these values now come directly from the CR, invalid cpu/memory strings will cause `resource.MustParse` to panic and crash the reconciler. Consider parsing with error handling (and defaulting or surfacing a configuration error) instead of using `MustParse` here.
</issue_to_address>

### Comment 3
<location> `internal/utils/kruize_generator.go:155-164` </location>
<code_context>
+func (g *KruizeResourceGenerator) getPVConfigKubernetes() (pvStorageSize, pvcStorageSize, hostPath string, accessModes []corev1.PersistentVolumeAccessMode) {
</code_context>

<issue_to_address>
**issue (bug_risk):** PersistentVolumeConfig.StorageClassName is ignored for the Kubernetes/Kind/Minikube PV/PVC path.

This creates a silent no-op for users on non-OpenShift clusters who set storageClassName in the CR. Please either propagate StorageClassName through getPVConfigKubernetes into the PV/PVC specs, or, if Kubernetes is not meant to honor it, adjust the CRD/interface to make that clear (e.g., omit or scope the field) to avoid confusion.
</issue_to_address>

### Comment 4
<location> `internal/controller/kruize_controller_test.go:300` </location>
<code_context>

 	Context("Resource generation", func() {
 		It("should generate cluster-scoped resources for OpenShift", func() {
-			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift)
+			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, nil)
</code_context>

<issue_to_address>
**suggestion (testing):** Add tests that validate ResourceConfig-driven overrides (CPU/memory) are applied to the generated deployments

Right now the tests only cover the `nil`/default `ResourceConfig` case. Please also add tests that construct a `Kruize` with non-nil `Spec.Resources.Database` and `Spec.Resources.Kruize`, pass it into `NewKruizeResourceGenerator`, and assert that the resulting DB and Kruize deployments have container `Resources.Requests`/`Limits` matching those configured CPU/memory values. A couple of extra `It` blocks or a small `DescribeTable` contrasting default vs custom resources would be sufficient.

Suggested implementation:

```golang
	Context("Resource generation", func() {
		It("should generate cluster-scoped resources for OpenShift", func() {
			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, nil)

			clusterResources := generator.ClusterScopedResources()
			Expect(clusterResources).NotTo(BeEmpty())
		})

		It("should generate namespaced resources for OpenShift", func() {
			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, nil)

			namespacedResources := generator.NamespacedResources()
		})

		It("should apply custom ResourceConfig to Kruize and Database deployments", func() {
			// NOTE: this test assumes the Kruize API types and deployment names already exist in the project.
			// Adjust the package alias and names if they differ in your codebase.

			cpuRequest := resource.MustParse("200m")
			cpuLimit := resource.MustParse("500m")
			memRequest := resource.MustParse("256Mi")
			memLimit := resource.MustParse("512Mi")

			kruize := &kruizev1alpha1.Kruize{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "test-kruize",
					Namespace: "test-namespace",
				},
				Spec: kruizev1alpha1.KruizeSpec{
					Resources: &kruizev1alpha1.ResourceConfig{
						Database: &kruizev1alpha1.ContainerResources{
							Requests: kruizev1alpha1.ResourceList{
								CPU:    cpuRequest.String(),
								Memory: memRequest.String(),
							},
							Limits: kruizev1alpha1.ResourceList{
								CPU:    cpuLimit.String(),
								Memory: memLimit.String(),
							},
						},
						Kruize: &kruizev1alpha1.ContainerResources{
							Requests: kruizev1alpha1.ResourceList{
								CPU:    cpuRequest.String(),
								Memory: memRequest.String(),
							},
							Limits: kruizev1alpha1.ResourceList{
								CPU:    cpuLimit.String(),
								Memory: memLimit.String(),
							},
						},
					},
				},
			}

			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, kruize)

			namespacedResources := generator.NamespacedResources()
			Expect(namespacedResources).NotTo(BeEmpty())

			var kruizeDeployment *appsv1.Deployment
			var dbDeployment *appsv1.Deployment

			for _, obj := range namespacedResources {
				deploy, ok := obj.(*appsv1.Deployment)
				if !ok {
					continue
				}
				switch deploy.Name {
				case "kruize":
					kruizeDeployment = deploy
				case "kruize-db":
					dbDeployment = deploy
				}
			}

			Expect(kruizeDeployment).NotTo(BeNil(), "expected Kruize deployment to be generated")
			Expect(dbDeployment).NotTo(BeNil(), "expected Database deployment to be generated")

			// Assuming single container per deployment; adjust index/name if needed.
			kruizeContainer := kruizeDeployment.Spec.Template.Spec.Containers[0]
			dbContainer := dbDeployment.Spec.Template.Spec.Containers[0]

			Expect(kruizeContainer.Resources.Requests.Cpu()).To(Equal(&cpuRequest))
			Expect(kruizeContainer.Resources.Limits.Cpu()).To(Equal(&cpuLimit))
			Expect(kruizeContainer.Resources.Requests.Memory()).To(Equal(&memRequest))
			Expect(kruizeContainer.Resources.Limits.Memory()).To(Equal(&memLimit))

			Expect(dbContainer.Resources.Requests.Cpu()).To(Equal(&cpuRequest))
			Expect(dbContainer.Resources.Limits.Cpu()).To(Equal(&cpuLimit))
			Expect(dbContainer.Resources.Requests.Memory()).To(Equal(&memRequest))
			Expect(dbContainer.Resources.Limits.Memory()).To(Equal(&memLimit))

```

To make this compile and work correctly, you’ll likely need to:

1. **Imports**: Ensure the test file imports the necessary packages (or adjust aliases to match your project):
   - `kruizev1alpha1` – your Kruize API package, e.g.:
     ```go
     kruizev1alpha1 "github.com/<org>/<repo>/api/v1alpha1"
     ```
   - Kubernetes types:
     ```go
     appsv1 "k8s.io/api/apps/v1"
     "k8s.io/apimachinery/pkg/api/resource"
     metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     ```
2. **Kruize types**: Adjust the `KruizeSpec`, `ResourceConfig`, `ContainerResources`, and `ResourceList` field names to match the actual CRD definitions in your code (for example, you may use `KruizeResources`, `DatabaseResources`, or plain `corev1.ResourceRequirements` instead of the placeholder types in this snippet).
3. **Deployment names**: Update `"kruize"` and `"kruize-db"` in the `switch deploy.Name` block to the actual deployment names (or use labels/owner references) that your `NewKruizeResourceGenerator` produces.
4. **Containers indexing**: If your deployments have more than one container, select the container by name rather than using index `[0]`, e.g. find by `container.Name == "kruize"` or `"kruize-db"`.
5. **Resource parsing**: If your `Kruize` CRD stores resource quantities differently (e.g. as `corev1.ResourceRequirements` instead of string maps), replace the construction of `kruize.Spec.Resources.*` accordingly and adapt the expectations to compare the appropriate types.
</issue_to_address>

### Comment 5
<location> `internal/controller/kruize_controller_test.go:316` </location>
<code_context>
 		})

 		It("should generate Kubernetes cluster-scoped resources", func() {
-			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeMinikube)
+			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeMinikube, nil)
</code_context>

<issue_to_address>
**suggestion (testing):** Add tests that cover PersistentVolume/PVC sizing and hostPath behavior from ResourceConfig for both OpenShift and Kubernetes

The new `getPVConfig`/`getPVConfigKubernetes` logic changes PV/PVC sizes, `storageClassName`, `hostPath`, and `accessModes` based on `ResourceConfig.PersistentVolume`, but current tests don’t assert these behaviors.

For both OpenShift and Kubernetes, please add tests that:
- Use a non-nil `ResourceConfig.PersistentVolume` with custom `PVStorageSize`, `PVCStorageSize`, `StorageClassName`, `HostPath`, and `AccessModes`.
- Verify the generated PV and PVC objects use these values.
- Include a case where `PVCStorageSize` is omitted to confirm it falls back to `PVStorageSize`.

This will exercise the new storage configuration end-to-end.

Suggested implementation:

```golang
		})

		It("should generate namespaced resources for OpenShift", func() {
			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, nil)

			namespacedResources := generator.NamespacedResources()
			Expect(namespacedResources).NotTo(BeEmpty())
		})

		It("should honor PersistentVolume config for OpenShift", func() {
			resourceConfig := &v1alpha1.ResourceConfig{
				PersistentVolume: &v1alpha1.PersistentVolumeConfig{
					PVStorageSize:    "10Gi",
					PVCStorageSize:   "5Gi",
					StorageClassName: "fast",
					HostPath:         "/data/kruize",
					AccessModes: []corev1.PersistentVolumeAccessMode{
						corev1.ReadWriteOnce,
						corev1.ReadOnlyMany,
					},
				},
			}

			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, resourceConfig)

			namespacedResources := generator.NamespacedResources()
			Expect(namespacedResources).NotTo(BeEmpty())

			var pv *corev1.PersistentVolume
			var pvc *corev1.PersistentVolumeClaim

			for _, r := range namespacedResources {
				switch o := r.(type) {
				case *corev1.PersistentVolume:
					pv = o
				case *corev1.PersistentVolumeClaim:
					pvc = o
				}
			}

			Expect(pv).NotTo(BeNil())
			Expect(pvc).NotTo(BeNil())

			Expect(pv.Spec.Capacity[corev1.ResourceStorage]).To(Equal(resource.MustParse("10Gi")))
			Expect(pv.Spec.PersistentVolumeSource.HostPath).NotTo(BeNil())
			Expect(pv.Spec.PersistentVolumeSource.HostPath.Path).To(Equal("/data/kruize"))

			Expect(pv.Spec.AccessModes).To(ContainElement(corev1.ReadWriteOnce))
			Expect(pv.Spec.AccessModes).To(ContainElement(corev1.ReadOnlyMany))

			if pv.Spec.StorageClassName != "" {
				Expect(pv.Spec.StorageClassName).To(Equal("fast"))
			} else if pv.Spec.StorageClassNamePtr != nil {
				Expect(*pv.Spec.StorageClassNamePtr).To(Equal("fast"))
			}

			Expect(pvc.Spec.Resources.Requests[corev1.ResourceStorage]).To(Equal(resource.MustParse("5Gi")))
			if pvc.Spec.StorageClassName != nil {
				Expect(*pvc.Spec.StorageClassName).To(Equal("fast"))
			}
			Expect(pvc.Spec.AccessModes).To(ContainElement(corev1.ReadWriteOnce))
			Expect(pvc.Spec.AccessModes).To(ContainElement(corev1.ReadOnlyMany))
		})

		It("should generate Kubernetes cluster-scoped resources", func() {
			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeMinikube, nil)

			clusterResources := generator.KubernetesClusterScopedResources()
			Expect(clusterResources).NotTo(BeEmpty())
		})

		It("should generate Kubernetes namespaced resources", func() {
			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeMinikube, nil)

			namespacedResources := generator.KubernetesNamespacedResources()
			Expect(namespacedResources).NotTo(BeEmpty())
		})

		It("should honor PersistentVolume config for Kubernetes and default PVC size", func() {
			resourceConfig := &v1alpha1.ResourceConfig{
				PersistentVolume: &v1alpha1.PersistentVolumeConfig{
					PVStorageSize:    "15Gi",
					StorageClassName: "standard",
					HostPath:         "/var/lib/kruize",
					AccessModes: []corev1.PersistentVolumeAccessMode{
						corev1.ReadWriteOnce,
					},
				},
			}

			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeMinikube, resourceConfig)

			clusterResources := generator.KubernetesClusterScopedResources()
			namespacedResources := generator.KubernetesNamespacedResources()

			var pv *corev1.PersistentVolume
			var pvc *corev1.PersistentVolumeClaim

			for _, r := range clusterResources {
				if o, ok := r.(*corev1.PersistentVolume); ok {
					pv = o
				}
			}
			for _, r := range namespacedResources {
				if o, ok := r.(*corev1.PersistentVolumeClaim); ok {
					pvc = o
				}
			}

			Expect(pv).NotTo(BeNil())
			Expect(pvc).NotTo(BeNil())

			Expect(pv.Spec.Capacity[corev1.ResourceStorage]).To(Equal(resource.MustParse("15Gi")))
			Expect(pv.Spec.PersistentVolumeSource.HostPath).NotTo(BeNil())
			Expect(pv.Spec.PersistentVolumeSource.HostPath.Path).To(Equal("/var/lib/kruize"))
			Expect(pv.Spec.AccessModes).To(ContainElement(corev1.ReadWriteOnce))

			if pv.Spec.StorageClassName != "" {
				Expect(pv.Spec.StorageClassName).To(Equal("standard"))
			} else if pv.Spec.StorageClassNamePtr != nil {
				Expect(*pv.Spec.StorageClassNamePtr).To(Equal("standard"))
			}

			// PVCStorageSize is omitted, so it should fall back to PVStorageSize (15Gi)
			Expect(pvc.Spec.Resources.Requests[corev1.ResourceStorage]).To(Equal(resource.MustParse("15Gi")))
			if pvc.Spec.StorageClassName != nil {
				Expect(*pvc.Spec.StorageClassName).To(Equal("standard"))
			}
			Expect(pvc.Spec.AccessModes).To(ContainElement(corev1.ReadWriteOnce))

```

1. Ensure the following imports exist at the top of `internal/controller/kruize_controller_test.go` (adjust package paths and aliases to match your project):
   - `v1alpha1` for `ResourceConfig` / `PersistentVolumeConfig` (for example: `optapiv1alpha1 "github.com/kruize/optimizer/api/v1alpha1"` and then use `optapiv1alpha1.ResourceConfig` in the tests, updating the code above accordingly).
   - `corev1 "k8s.io/api/core/v1"`
   - `resource "k8s.io/apimachinery/pkg/api/resource"`
2. The fields used on the PV (`StorageClassName` vs a pointer field) may differ in your actual types. Replace the conditional handling of `StorageClassName` / `StorageClassNamePtr` with whatever your `PersistentVolume` and `PersistentVolumeClaim` types actually expose (typically `*string StorageClassName` in `corev1`).
3. If `NewKruizeResourceGenerator` returns a different type for the resource slices (e.g. `[]runtime.Object` or `[]client.Object`), the type assertions (`r.(*corev1.PersistentVolume)`) are still valid, but you may need to change the loop variable type accordingly.
4. If your `PersistentVolumeConfig` or `ResourceConfig` type names or field names differ from `PVStorageSize`, `PVCStorageSize`, `StorageClassName`, `HostPath`, and `AccessModes`, rename them in the tests to match the actual struct definitions.
5. If PVs for OpenShift are created as cluster-scoped rather than namespaced in your generator, adjust the OpenShift test to inspect the appropriate resource slice (e.g. `ClusterScopedResources()` instead of `NamespacedResources()`).
</issue_to_address>

### Comment 6
<location> `internal/controller/kruize_controller_test.go:438` </location>
<code_context>
 	Context("Kruize deployment manifest generation", func() {
 		DescribeTable("should generate valid Kruize deployment manifest",
 			func(clusterType string, resourceMethod func(*utils.KruizeResourceGenerator) []client.Object) {
-				generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", clusterType)
</code_context>

<issue_to_address>
**suggestion (testing):** Extend deployment manifest tests to assert resource Requests/Limits for both default and custom ResourceConfig

The current table only verifies that a `Deployment` is created, but not that its container `Resources` reflect the new configurability.

Please:
- For each `clusterType`, assert the Kruize deployment container’s `Resources` match expected defaults when `Resources == nil`.
- Add a case (either another `Entry` or `DescribeTable`) that uses a non-nil `ResourceConfig.Kruize` and asserts the deployment uses those custom CPU/memory values.

This will validate that manifest generation actually applies the new resource configuration.
</issue_to_address>

### Comment 7
<location> `internal/controller/kruize_controller_test.go:511` </location>
<code_context>
 			Expect(kruizeUIPod.Spec.Containers).NotTo(BeEmpty())
 		})

 		It("should generate Kruize-db pod specification", func() {
-			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift)
+			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, nil)
</code_context>

<issue_to_address>
**suggestion (testing):** Add an edge-case test for partial ResourceConfig (e.g., only CPURequest set) to ensure defaulting logic works as intended

Because `getDBResources` / `getKruizeResources` only override non-empty fields, it’s important to confirm that a partially populated `ResourceConfig.Database` preserves defaults for unset values. Please add a test that uses a config with only `CPURequest` (or a single field) set and verifies that the resulting DB container has that custom value while still using defaults for CPU limit and memory request/limit, ensuring partial override semantics remain intact across refactors.

Suggested implementation:

```golang
		It("should generate namespaced resources for OpenShift", func() {
			generator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, nil)

			namespacedResources := generator.NamespacedResources()
		})

		It("should allow partial DB resource overrides while preserving defaults", func() {
			// First, generate resources with default configuration to capture default DB resources
			defaultGenerator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, nil)
			defaultNamespacedResources := defaultGenerator.NamespacedResources()

			// Helper closure to locate the Kruize DB container from the generated resources
			getDBContainer := func(resources []client.Object) *corev1.Container {
				for _, res := range resources {
					deploy, ok := res.(*appsv1.Deployment)
					if !ok {
						continue
					}

					// Adjust this name if the DB deployment is named differently in the manifests
					if deploy.Name != "kruize-db" {
						continue
					}

					for i, c := range deploy.Spec.Template.Spec.Containers {
						// Adjust this name if the DB container is named differently
						if c.Name == "kruize-db" {
							return &deploy.Spec.Template.Spec.Containers[i]
						}
					}
				}
				return nil
			}

			defaultDBContainer := getDBContainer(defaultNamespacedResources)
			Expect(defaultDBContainer).NotTo(BeNil(), "default DB container should exist")

			// Now, create a ResourceConfig that only overrides the CPU request for the DB
			customConfig := &config.ResourceConfig{
				Database: config.ContainerResourceConfig{
					CPURequest: "250m",
				},
			}

			customGenerator := utils.NewKruizeResourceGenerator("test-namespace", "", "", constants.ClusterTypeOpenShift, customConfig)
			customNamespacedResources := customGenerator.NamespacedResources()

			customDBContainer := getDBContainer(customNamespacedResources)
			Expect(customDBContainer).NotTo(BeNil(), "custom DB container should exist")

			// Verify that the CPU request was overridden
			Expect(customDBContainer.Resources.Requests[corev1.ResourceCPU]).To(Equal(resource.MustParse("250m")))

			// Verify that CPU limit and memory request/limit are still using the defaults
			Expect(customDBContainer.Resources.Limits[corev1.ResourceCPU]).To(Equal(defaultDBContainer.Resources.Limits[corev1.ResourceCPU]))
			Expect(customDBContainer.Resources.Requests[corev1.ResourceMemory]).To(Equal(defaultDBContainer.Resources.Requests[corev1.ResourceMemory]))
			Expect(customDBContainer.Resources.Limits[corev1.ResourceMemory]).To(Equal(defaultDBContainer.Resources.Limits[corev1.ResourceMemory]))

```

1. Ensure the following imports exist at the top of `internal/controller/kruize_controller_test.go` (adjust module paths if your project uses different ones):
   - `appsv1 "k8s.io/api/apps/v1"`
   - `corev1 "k8s.io/api/core/v1"`
   - `resource "k8s.io/apimachinery/pkg/api/resource"`
   - `config "github.com/kruize/kruize-operator/internal/config"` (or the actual path where `ResourceConfig` and `ContainerResourceConfig` are defined).
   - `client "sigs.k8s.io/controller-runtime/pkg/client"` if not already imported.

2. Update `"kruize-db"` (deployment name) and `"kruize-db"` (container name) in the `getDBContainer` closure if the actual DB deployment/container names differ in your manifests.

3. If `ResourceConfig` / `ContainerResourceConfig` live under a different package or have different field names, adjust the construction of `customConfig` accordingly to point to the DB-specific CPU request field.

4. If your tests already define a shared helper for locating the DB deployment/container, you can replace the inline `getDBContainer` closure with that existing helper to avoid duplication.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
@shreyabiradar07
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The new resource/PV configuration tests repeat a lot of boilerplate for locating deployments, containers, PVs, and PVCs; consider extracting small helper functions (e.g., findDeployment, findPV/PVC, getContainer) to reduce duplication and make the tests easier to maintain.
  • Both parseResourceQuantity and isValidAccessMode silently ignore invalid user input and fall back to defaults; it may be worth at least logging or surfacing a warning when a user-specified resource quantity or access mode is rejected so misconfigurations are observable.
  • The getPVConfigKubernetes helper reuses DefaultOpenShiftStorageClassName for Kubernetes; if the intent is to have different defaults per platform, consider introducing a dedicated Kubernetes storage class default constant for clarity and future flexibility.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new resource/PV configuration tests repeat a lot of boilerplate for locating deployments, containers, PVs, and PVCs; consider extracting small helper functions (e.g., `findDeployment`, `findPV/PVC`, `getContainer`) to reduce duplication and make the tests easier to maintain.
- Both `parseResourceQuantity` and `isValidAccessMode` silently ignore invalid user input and fall back to defaults; it may be worth at least logging or surfacing a warning when a user-specified resource quantity or access mode is rejected so misconfigurations are observable.
- The `getPVConfigKubernetes` helper reuses `DefaultOpenShiftStorageClassName` for Kubernetes; if the intent is to have different defaults per platform, consider introducing a dedicated Kubernetes storage class default constant for clarity and future flexibility.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
@shreyabiradar07
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In the CRD schema for resources.persistentVolume.accessModes, consider adding an explicit enum for the four supported values instead of only documenting them in the description so that invalid values are rejected at admission time rather than only logged and ignored.
  • There is still a fair amount of repeated code in the tests for locating Deployments/PVs/PVCs and extracting containers; since you’ve already introduced helpers like findDeployment and getContainer, you could refactor the remaining manual loops to use these helpers to keep the tests more concise and less error-prone.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the CRD schema for `resources.persistentVolume.accessModes`, consider adding an explicit `enum` for the four supported values instead of only documenting them in the description so that invalid values are rejected at admission time rather than only logged and ignored.
- There is still a fair amount of repeated code in the tests for locating Deployments/PVs/PVCs and extracting containers; since you’ve already introduced helpers like `findDeployment` and `getContainer`, you could refactor the remaining manual loops to use these helpers to keep the tests more concise and less error-prone.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
@shreyabiradar07
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • The isValidAccessMode helper in kruize_generator.go is currently unused; consider either wiring it into the PV/PVC access mode handling or removing it to avoid dead code.
  • In ResourceConfig.DeepCopyInto, Database and Kruize are copied with **out = **in instead of calling ContainerResources.DeepCopyInto; while safe today, switching to use the generated deepcopy would be more robust if ContainerResources ever gains slice/map fields.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `isValidAccessMode` helper in `kruize_generator.go` is currently unused; consider either wiring it into the PV/PVC access mode handling or removing it to avoid dead code.
- In `ResourceConfig.DeepCopyInto`, `Database` and `Kruize` are copied with `**out = **in` instead of calling `ContainerResources.DeepCopyInto`; while safe today, switching to use the generated deepcopy would be more robust if `ContainerResources` ever gains slice/map fields.

## Individual Comments

### Comment 1
<location path="internal/utils/kruize_generator.go" line_range="147-148" />
<code_context>
+	}
+}
+
+// isValidAccessMode validates if the given access mode is a valid Kubernetes PersistentVolume access mode
+func (g *KruizeResourceGenerator) isValidAccessMode(mode string) bool {
+	validModes := map[string]bool{
+		string(corev1.ReadWriteOnce):    true,
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Validate or remove `isValidAccessMode` to avoid dead code and misleading log message

This helper isn’t used, so invalid values in `ResourceConfig.PersistentVolume.AccessModes` (e.g. programmatically constructed ones that bypass the CRD) still reach the PV/PVC spec. The log message also incorrectly says such modes “will be ignored”. Please either integrate this into `getPVConfigWithDefaults` (filter and drop/log invalid modes) or remove it to avoid dead code and misleading behavior.

Suggested implementation:

```golang

```

1. If there are any remaining references to `isValidAccessMode` elsewhere in `internal/utils/kruize_generator.go` (or the wider codebase), they must be removed or replaced, since this helper is now deleted.
2. If you later decide you want to actually validate and filter access modes (as per the alternative in the review comment), you can reintroduce a similar helper and wire it into `getPVConfigWithDefaults` where `PersistentVolume.AccessModes` are being processed, applying the filter before constructing the PV/PVC spec and logging dropped values there.
</issue_to_address>

### Comment 2
<location path="internal/utils/kruize_generator.go" line_range="171-180" />
<code_context>
+func (g *KruizeResourceGenerator) getPVConfigWithDefaults(
</code_context>
<issue_to_address>
**suggestion:** Consider enforcing or logging PV/PVC size consistency to surface misconfigurations earlier

The docstring states `pvStorageSize` should be >= `pvcStorageSize`, but this function doesn’t enforce that. If a PVC is configured larger than the PV, the error only surfaces at bind time. Consider parsing both quantities here and, when PVC > PV, logging a warning and either clamping to PV or explicitly preserving the user value, so misconfigurations are detected earlier.

Suggested implementation:

```golang
func ensurePVAndPVCStorageConsistency(pvStorageSize, pvcStorageSize string) (string, string, error) {
	pvQty, err := resource.ParseQuantity(pvStorageSize)
	if err != nil {
		return pvStorageSize, pvcStorageSize, fmt.Errorf("failed to parse PV storage size %q: %w", pvStorageSize, err)
	}

	pvcQty, err := resource.ParseQuantity(pvcStorageSize)
	if err != nil {
		return pvStorageSize, pvcStorageSize, fmt.Errorf("failed to parse PVC storage size %q: %w", pvcStorageSize, err)
	}

	// If PVC > PV, surface the potential bind-time failure as early as possible.
	if pvcQty.Cmp(pvQty) == 1 {
		klog.Warningf("PVC storage request (%s) is greater than PV storage (%s); PVC may fail to bind", pvcStorageSize, pvStorageSize)
	}

	// We explicitly preserve the user-provided values here and only log a warning.
	return pvStorageSize, pvcStorageSize, nil
}

// getPVConfigWithDefaults is a shared helper that returns PV configuration with injected defaults
func (g *KruizeResourceGenerator) getPVConfigWithDefaults(
	defaultPVStorageSize, defaultStorageClassName, defaultHostPath string,
	defaultAccessModes []corev1.PersistentVolumeAccessMode,
) (pvStorageSize, pvcStorageSize, storageClassName, hostPath string, accessModes []corev1.PersistentVolumeAccessMode) {
	pvStorageSize = defaultPVStorageSize
	pvcStorageSize = defaultPVStorageSize
	storageClassName = defaultStorageClassName
	hostPath = defaultHostPath
	accessModes = defaultAccessModes

	if g.ResourceConfig != nil && g.ResourceConfig.PersistentVolume != nil {

```

`.

Here are the changes:

<file_operations>
<file_operation operation="edit" file_path="internal/utils/kruize_generator.go">
<<<<<<< SEARCH
// getPVConfigWithDefaults is a shared helper that returns PV configuration with injected defaults
func (g *KruizeResourceGenerator) getPVConfigWithDefaults(
	defaultPVStorageSize, defaultStorageClassName, defaultHostPath string,
	defaultAccessModes []corev1.PersistentVolumeAccessMode,
) (pvStorageSize, pvcStorageSize, storageClassName, hostPath string, accessModes []corev1.PersistentVolumeAccessMode) {
	pvStorageSize = defaultPVStorageSize
	pvcStorageSize = defaultPVStorageSize
	storageClassName = defaultStorageClassName
	hostPath = defaultHostPath
	accessModes = defaultAccessModes

	if g.ResourceConfig != nil && g.ResourceConfig.PersistentVolume != nil {
=======
func ensurePVAndPVCStorageConsistency(pvStorageSize, pvcStorageSize string) (string, string, error) {
	pvQty, err := resource.ParseQuantity(pvStorageSize)
	if err != nil {
		return pvStorageSize, pvcStorageSize, fmt.Errorf("failed to parse PV storage size %q: %w", pvStorageSize, err)
	}

	pvcQty, err := resource.ParseQuantity(pvcStorageSize)
	if err != nil {
		return pvStorageSize, pvcStorageSize, fmt.Errorf("failed to parse PVC storage size %q: %w", pvcStorageSize, err)
	}

	// If PVC > PV, surface the potential bind-time failure as early as possible.
	if pvcQty.Cmp(pvQty) == 1 {
		klog.Warningf("PVC storage request (%s) is greater than PV storage (%s); PVC may fail to bind", pvcStorageSize, pvStorageSize)
	}

	// We explicitly preserve the user-provided values here and only log a warning.
	return pvStorageSize, pvcStorageSize, nil
}

// getPVConfigWithDefaults is a shared helper that returns PV configuration with injected defaults
func (g *KruizeResourceGenerator) getPVConfigWithDefaults(
	defaultPVStorageSize, defaultStorageClassName, defaultHostPath string,
	defaultAccessModes []corev1.PersistentVolumeAccessMode,
) (pvStorageSize, pvcStorageSize, storageClassName, hostPath string, accessModes []corev1.PersistentVolumeAccessMode) {
	pvStorageSize = defaultPVStorageSize
	pvcStorageSize = defaultPVStorageSize
	storageClassName = defaultStorageClassName
	hostPath = defaultHostPath
	accessModes = defaultAccessModes

	if g.ResourceConfig != nil && g.ResourceConfig.PersistentVolume != nil {
>>>>>>> REPLACE
</file_operation>
</file_operations>

<additional_changes>
To fully implement the behavior described in your review comment, you should also:

1. **Import the required packages** at the top of `internal/utils/kruize_generator.go` (or reuse existing logging/quantity packages if your codebase already uses them):
   - Add (or reuse equivalent):
   ```go
   import (
       "fmt"

       "k8s.io/apimachinery/pkg/api/resource"
       "k8s.io/klog/v2"
   )
   ```
   If the project already uses a different logger (e.g. `logrus`, `zap`, or a wrapper), replace `klog.Warningf` with the appropriate warning-level log call and remove the `klog` import.

2. **Call the consistency helper after all overrides to PV/PVC sizes are applied** inside `getPVConfigWithDefaults`. Since we can’t see the full function body, place the call just before the function returns, once `pvStorageSize` and `pvcStorageSize` have their final values. For example:
   ```go
   pvStorageSize, pvcStorageSize, err := ensurePVAndPVCStorageConsistency(pvStorageSize, pvcStorageSize)
   if err != nil {
       // Decide on error handling policy:
       // - If invalid quantities should fail fast, return the error upstream (may require changing the signature).
       // - Otherwise, log and continue with the raw string values.
       klog.Warningf("Failed to validate PV/PVC storage consistency: %v", err)
   }
   ```
   If you want to **fail fast on invalid quantity strings**, you may need to:
   - Change the signature of `getPVConfigWithDefaults` to return an `error`.
   - Propagate that error to callers.

3. If parts of the function or callers rely on specific logging or error-handling patterns, adapt the `ensurePVAndPVCStorageConsistency` helper and the call site to fit those conventions (e.g. using structured logging, context-aware logging, or returning typed errors).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Signed-off-by: Shreya Biradar <shbirada@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant