Skip to content

feat(valkey): add managed Valkey service - #3380

Open
Andrei Kvapil (kvaps) wants to merge 9 commits into
mainfrom
feat/valkey-app
Open

feat(valkey): add managed Valkey service#3380
Andrei Kvapil (kvaps) wants to merge 9 commits into
mainfrom
feat/valkey-app

Conversation

@kvaps

@kvaps Andrei Kvapil (kvaps) commented Jul 20, 2026

Copy link
Copy Markdown
Member

What this PR does

Adds a managed Valkey service to the catalog, alongside managed Redis.

Stacked on #3406 (redis-operator migration to freshworks-oss). This PR targets that branch and depends on it; review/merge #3406 first.

Why

Redis relicensed at 8.x to a source-available family (AGPLv3 / SSPL / RSALv2), and the managed Redis app currently ships v8: 8.4.0 with no BSD-licensed option ≤ 7.2. That is a licensing risk for CNCF Incubation. Valkey is the BSD-3-Clause fork of Redis 7.2.4, governed by the Linux Foundation, and a drop-in replacement for Redis. This is the same move Argo CD made — cncf/foundation#750 was closed with "no need for exception" after they migrated to Valkey.

How it works

Valkey runs on the same operator as managed Redis. #3406 migrates that operator from the archived spotahome/redis-operator to the actively-maintained freshworks-oss/redis-operator fork, which adds a native spec.engine: Valkey switch. With it, the operator runs valkey-server / valkey-cli natively (in the launch command and in its liveness / readiness / shutdown probes), so the chart uses the official valkey/valkey image directly — no Redis-compatibility shim image.

The app mirrors managed Redis: same shape/values (replicas, resources/resourcesPreset, size, storageClass, external, version, authEnabled), Sentinel-based HA, metrics exporter, WorkloadMonitors, dashboard resource map, and ApplicationDefinition (kind: Valkey).

Versions offered: v8 → 8.1.8 (default) and v7 → 7.2.13 (the BSD-3-Clause Redis 7.2 line, most conservative drop-in).

How it was verified

  • helm template renders cleanly for v8, v7, and external: true; the RedisFailover carries spec.engine: Valkey and image: valkey/valkey:<version>. helm lint shows only the pre-existing icon-URL / cozy-lib warnings that managed Redis emits too.
  • helm template of valkey-rd renders a valid ApplicationDefinition (kind: Valkey, plural: valkeys, category: PaaS).
  • Generated artifacts (values.schema.json, README.md, types.go, zz_generated.deepcopy.go, the ApplicationDefinition openAPISchema) reproduce with the pinned cozyvalues-gen v1.6.0 and controller-gen v0.16.4 — root make generate and per-app generate both produce no drift; go build ./valkey/... passes.
  • A live-cluster e2e was not run from this environment; the Chainsaw suite hack/e2e-chainsaw/valkey/ (mirroring the redis suite) is included and hack/select-e2e.sh maps the valkey-application source to it, so it runs in CI once the freshworks operator image is built.

Notes

  • The Valkey logo (packages/apps/valkey/logos/valkey.svg) is a placeholder in Valkey's brand colors, pending the official brand asset.
  • A Grafana db/valkey dashboard was intentionally left out of this initial PoC; it can follow.

Screenshots

N/A — no UI changes.

Downstream repositories

This adds a new managed-app kind, which likely warrants follow-ups in cozystack/website (user-facing docs for the new service) and possibly cozystack/terraform-provider-cozystack. No follow-up PRs are opened yet — leaving these for a maintainer to decide, per the template guidance.

Release note

feat(valkey): add managed Valkey service — a BSD-3-Clause, Linux Foundation-governed alternative to managed Redis, running on the freshworks-oss redis-operator via native spec.engine: Valkey (versions 8.1.8 and 7.2.13)

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds managed Valkey support across CRD types, Helm deployment templates, versioned Redis-compatible images, platform registration, permissions, documentation, build automation, and Chainsaw end-to-end validation.

Changes

Valkey API and chart runtime

Layer / File(s) Summary
API types and configuration contract
api/apps/v1alpha1/valkey/*, packages/apps/valkey/values.*, packages/system/valkey-rd/cozyrds/valkey.yaml
Defines Valkey fields, defaults, enums, resource settings, version selection, authentication, and immutable storage classes with generated deepcopy methods.
Helm deployment resources
packages/apps/valkey/templates/*, packages/apps/valkey/Chart.yaml
Renders RedisFailover, authentication, storage, external and metrics Services, monitoring resources, resource presets, version mapping, and dashboard RBAC.

Build and platform integration

Layer / File(s) Summary
Versioned image build
packages/apps/valkey/Makefile, packages/apps/valkey/files/*, packages/apps/valkey/hack/*, packages/apps/valkey/images/*, Makefile
Builds Redis-compatible Valkey images for v7 and v8, refreshes upstream versions, records image tags, and adds Valkey image generation to the repository build.
Package registration and permissions
packages/core/platform/..., packages/system/valkey-rd/..., packages/system/cozystack-basics/..., .github/workflows/pr-labeler.yaml
Registers the Valkey package and system release, includes it in PAAS bundles, grants tenant access to Valkey resources, and maps the valkey scope to area/database.

Validation and documentation

Layer / File(s) Summary
Deployment test and documentation
hack/e2e-chainsaw/valkey/*, packages/apps/valkey/README.md, docs/storage-immutability.md
Adds a Chainsaw test for HelmRelease readiness, PVC binding, Deployment availability, and StatefulSet replicas, alongside Valkey and storage immutability documentation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: kind/api-change, area/api, area/kubernetes, area/storage

Suggested reviewers: lllamnyp

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding a managed Valkey service.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/valkey-app

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/feature Categorizes issue or PR as related to a new feature size/XXL This PR changes 1000+ lines, ignoring generated files labels Jul 20, 2026
@kvaps
Andrei Kvapil (kvaps) marked this pull request as ready for review July 20, 2026 18:45
@dosubot dosubot Bot added the area/database Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse) label Jul 20, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a managed Valkey service to the Cozystack platform. By leveraging the existing redis-operator through a lightweight compatibility layer, this change provides a robust, BSD-3-Clause licensed alternative to Redis. The implementation includes all necessary Helm charts, API definitions, monitoring resources, and automated versioning scripts to integrate Valkey seamlessly into the current infrastructure.

Highlights

  • Managed Valkey Service: Added a managed Valkey service to the catalog as a governance-clean, BSD-3-Clause licensed alternative to Redis.
  • Compatibility Layer: Implemented a thin compatibility image that symlinks required binaries, allowing the existing redis-operator to manage Valkey without code changes.
  • Version Support: Configured support for Valkey versions 8.1.8 and 7.2.13, with automated version management scripts.
  • Infrastructure and Testing: Included comprehensive Helm charts, monitoring configurations, and an end-to-end testing suite to ensure service reliability.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: **/charts/** (1)
    • packages/apps/valkey/charts/cozy-lib
  • Ignored by pattern: **/zz_generated.*.go (1)
    • api/apps/v1alpha1/valkey/zz_generated.deepcopy.go
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/pr-labeler.yaml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new managed Valkey service to Cozystack, adding API types, a Helm chart with a thin Redis-compatibility layer, E2E tests, and platform integration. The review feedback highlights a bug in the service scrape configuration where target_label is incorrectly written in snake_case, and points out potential resource over-provisioning for Sentinel pods. Additionally, improvements are suggested for the version update script to preserve file permissions and ensure proper cleanup, alongside minor cleanups of redundant template conditionals and empty keys.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +14 to +24
- metricRelabelConfigs:
relabelConfigs:
- replacement: valkey
targetLabel: job
- sourceLabels: [__meta_kubernetes_pod_node_name]
targetLabel: node
- replacement: cluster
targetLabel: tier
- target_label: service
replacement: {{ .Release.Name }}
port: metrics

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

There are two issues in this endpoint definition:

  1. Bug: On line 22, target_label is written in snake_case. Kubernetes CRDs (like VMServiceScrape and ServiceMonitor) use camelCase (targetLabel). Using target_label will cause the operator to ignore this relabeling rule, and the service label will not be set on the metrics.
  2. Redundancy: The empty metricRelabelConfigs: key on line 14 is unnecessary. We can clean this up by moving port: metrics to the top of the endpoint block and removing the empty key.
  - port: metrics
    relabelConfigs:
    - replacement: valkey
      targetLabel: job
    - sourceLabels: [__meta_kubernetes_pod_node_name]
      targetLabel: node
    - replacement: cluster
      targetLabel: tier
    - targetLabel: service
      replacement: {{ .Release.Name }}

Comment on lines +26 to +28
sentinel:
replicas: 3
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Sentinel is a lightweight monitoring and failover coordinator that does not store data or serve database traffic. Assigning it the same resources and resourcesPreset as the main Valkey database pods can lead to massive resource over-provisioning (e.g., if a user selects a large preset like m1.large for the database, the 3 Sentinel pods will also request m1.large resources, wasting a significant amount of CPU and memory).

Consider using a fixed small preset (like nano) for Sentinel, or providing a separate configuration for Sentinel resources.

  sentinel:
    replicas: 3
    resources: {{- include "cozy-lib.resources.defaultingSanitize" (list "nano" dict $) | nindent 6 }}

Comment on lines +103 to +104
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

low

Using mv with a file created by mktemp can cause the target file (values.yaml) to lose its original permissions (since mktemp creates files with 0600 permissions, which mv preserves). Additionally, writing to $TEMP_FILE.tmp bypasses the trap cleanup if the script fails mid-execution.

To fix both issues, write directly to $TEMP_FILE (which is tracked by the trap) and copy its contents back using cat to preserve the original file permissions of values.yaml.

Suggested change
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"
' "$VALUES_FILE" > "$TEMP_FILE"
cat "$TEMP_FILE" > "$VALUES_FILE"

Comment on lines +113 to +114
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

low

Similarly, write directly to $TEMP_FILE and use cat to overwrite values.yaml to ensure proper cleanup and preserve file permissions.

Suggested change
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"
' "$VALUES_FILE" > "$TEMP_FILE"
cat "$TEMP_FILE" > "$VALUES_FILE"

app: {{ .Release.Name }}-metrics
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
annotations:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

low

The annotations: key is empty and redundant. It should be removed to keep the manifest clean.

Comment on lines +11 to +17
type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }}
{{- if .Values.external }}
externalTrafficPolicy: Local
{{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }}
allocateLoadBalancerNodePorts: false
{{- end }}
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

low

Since the entire Service manifest is already wrapped in {{- if .Values.external }} (line 1), .Values.external is guaranteed to be true here. We can simplify the type field and remove the redundant inner if check.

  type: LoadBalancer
  externalTrafficPolicy: Local
  {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }}
  allocateLoadBalancerNodePorts: false
  {{- end }}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/apps/valkey/templates/service.yaml (1)

11-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify redundant conditionals for the external service.

Since the entire file is wrapped in {{- if .Values.external }} (line 1), the service will only be created when external is truthy. Therefore, type will always evaluate to "LoadBalancer" and the nested {{- if .Values.external }} check is redundant.

Consider simplifying the code to remove the redundancy.

♻️ Proposed refactor
-  type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }}
-  {{- if .Values.external }}
-  externalTrafficPolicy: Local
-    {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }}
-  allocateLoadBalancerNodePorts: false
-    {{- end }}
-  {{- end }}
+  type: LoadBalancer
+  externalTrafficPolicy: Local
+  {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }}
+  allocateLoadBalancerNodePorts: false
+  {{- end }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/apps/valkey/templates/service.yaml` around lines 11 - 17, In the
service template, simplify the external-service block by setting the service
type directly to LoadBalancer and removing the redundant .Values.external
conditional around externalTrafficPolicy and allocateLoadBalancerNodePorts.
Preserve the existing disableLoadBalancerNodePorts condition and its behavior.
packages/apps/valkey/templates/servicescrape.yaml (1)

22-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix inconsistent field naming to prevent potential CRD pruning.

The relabelConfigs field uses targetLabel (camelCase) for the preceding entries, but switches to target_label (snake_case) here. Kubernetes CRDs typically enforce camelCase fields, and target_label might be silently pruned by the API server depending on the VictoriaMetrics CRD schema definition.

Use targetLabel consistently.

♻️ Proposed refactor
-    - target_label: service
-      replacement: {{ .Release.Name }}
+    - targetLabel: service
+      replacement: {{ .Release.Name }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/apps/valkey/templates/servicescrape.yaml` around lines 22 - 23,
Update the final relabelConfigs entry in the servicescrape template to use the
camelCase targetLabel field instead of target_label, matching the preceding
entries and the CRD schema.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/apps/valkey/README.md`:
- Around line 15-38: Regenerate the ## Parameters section in README.md using
cozyvalues-gen by running make generate from packages/apps/valkey or the
repository root. Commit the generated table alignment and spacing changes,
without manually editing the generated output.

---

Nitpick comments:
In `@packages/apps/valkey/templates/service.yaml`:
- Around line 11-17: In the service template, simplify the external-service
block by setting the service type directly to LoadBalancer and removing the
redundant .Values.external conditional around externalTrafficPolicy and
allocateLoadBalancerNodePorts. Preserve the existing
disableLoadBalancerNodePorts condition and its behavior.

In `@packages/apps/valkey/templates/servicescrape.yaml`:
- Around line 22-23: Update the final relabelConfigs entry in the servicescrape
template to use the camelCase targetLabel field instead of target_label,
matching the preceding entries and the CRD schema.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fd3252c8-c822-4cc7-9f27-864c317bd2a5

📥 Commits

Reviewing files that changed from the base of the PR and between f5227ee and 6c0bf89.

⛔ Files ignored due to path filters (1)
  • packages/apps/valkey/logos/valkey.svg is excluded by !**/*.svg
📒 Files selected for processing (33)
  • .github/workflows/pr-labeler.yaml
  • Makefile
  • api/apps/v1alpha1/valkey/types.go
  • api/apps/v1alpha1/valkey/zz_generated.deepcopy.go
  • docs/storage-immutability.md
  • hack/e2e-chainsaw/valkey/chainsaw-test.yaml
  • hack/e2e-chainsaw/valkey/valkey.yaml
  • packages/apps/valkey/.helmignore
  • packages/apps/valkey/Chart.yaml
  • packages/apps/valkey/Makefile
  • packages/apps/valkey/README.md
  • packages/apps/valkey/charts/cozy-lib
  • packages/apps/valkey/files/versions.yaml
  • packages/apps/valkey/hack/update-versions.sh
  • packages/apps/valkey/images/valkey-7.2.13.tag
  • packages/apps/valkey/images/valkey-8.1.8.tag
  • packages/apps/valkey/images/valkey/Dockerfile
  • packages/apps/valkey/templates/_resources.tpl
  • packages/apps/valkey/templates/_versions.tpl
  • packages/apps/valkey/templates/dashboard-resourcemap.yaml
  • packages/apps/valkey/templates/service.yaml
  • packages/apps/valkey/templates/servicescrape.yaml
  • packages/apps/valkey/templates/valkeyfailover.yaml
  • packages/apps/valkey/values.schema.json
  • packages/apps/valkey/values.yaml
  • packages/core/platform/sources/valkey-application.yaml
  • packages/core/platform/templates/bundles/paas.yaml
  • packages/system/cozystack-basics/templates/clusterroles.yaml
  • packages/system/valkey-rd/Chart.yaml
  • packages/system/valkey-rd/Makefile
  • packages/system/valkey-rd/cozyrds/valkey.yaml
  • packages/system/valkey-rd/templates/cozyrd.yaml
  • packages/system/valkey-rd/values.yaml

Comment thread packages/apps/valkey/README.md
@myasnikovdaniil

Copy link
Copy Markdown
Contributor

Before we proceed, I think we need an explicit maintainer position on the operator lifecycle.

spotahome/redis-operator was archived on June 11, 2026 and is now read-only: https://github.com/spotahome/redis-operator. This PR would make Valkey another consumer of that operator, increasing our dependency on an unmaintained upstream.

My preference is to move away from the Spotahome operator to an actively maintained alternative with comparable capabilities—Sentinel-style HA/failover, persistence, authentication, metrics, and external access. Maintaining our own fork does not look like a good long-term tradeoff: this operator is a small, non-core part of Cozystack, and owning its maintenance would consume disproportionate time and resources.

Could the author/maintainers please explicitly acknowledge the upstream archival and state the intended position?

  • Is continued use of the archived operator accepted as a temporary or long-term dependency?
  • If temporary, what migration target or selection process is expected?
  • Should this PR be deferred until an actively maintained replacement is chosen?

I would prefer not to add another consumer until this direction is clear.

@kvaps
Andrei Kvapil (kvaps) marked this pull request as draft July 21, 2026 15:40
@kvaps
Andrei Kvapil (kvaps) marked this pull request as ready for review July 21, 2026 15:41

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new managed Valkey application to Cozystack, integrating it as a drop-in Redis-compatible engine. It includes the API types, Helm chart templates, a thin compatibility Dockerfile, version update scripts, and E2E chainsaw tests. The review feedback highlights several improvement opportunities: optimizing Sentinel resource allocations to prevent waste (and updating the WorkloadMonitor label accordingly), ensuring proper cleanup in the version update script by writing directly to the tracked temporary file, and removing redundant checks and empty blocks in the Helm templates to improve readability.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +26 to +28
sentinel:
replicas: 3
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Sentinel is a lightweight coordinator and does not require the same resource allocation as the main Valkey database. Sharing .Values.resources and .Values.resourcesPreset with Sentinel can lead to significant resource waste when scaling up the database. Consider hardcoding Sentinel to a minimal preset like nano (or exposing a separate configuration for it).

  sentinel:
    replicas: 3
    resources: {{- include "cozy-lib.resources.defaultingSanitize" (list "nano" dict $) | nindent 6 }}

name: {{ $.Release.Name }}-sentinel
namespace: {{ $.Release.Namespace }}
labels:
workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

If Sentinel is configured with a fixed lightweight preset (like nano), the resource-preset label on its WorkloadMonitor should also be updated to match, preventing the controller from applying the database's larger preset to Sentinel pods.

    workloads.cozystack.io/resource-preset: "nano"

Comment on lines +89 to +104
awk -v new_section="$NEW_VERSION_SECTION" '
/^## @enum {string} Version/ {
in_section = 1
print new_section
next
}
in_section && /^version: / {
in_section = 0
next
}
in_section {
next
}
{ print }
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

low

Writing to a .tmp file outside of the tracked TEMP_FILE path bypasses the cleanup trap if the script is interrupted or fails during the awk execution. Writing directly to TEMP_FILE ensures it is properly cleaned up on exit.

Suggested change
awk -v new_section="$NEW_VERSION_SECTION" '
/^## @enum {string} Version/ {
in_section = 1
print new_section
next
}
in_section && /^version: / {
in_section = 0
next
}
in_section {
next
}
{ print }
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"
awk -v new_section="$NEW_VERSION_SECTION" '
/^## @enum {string} Version/ {
in_section = 1
print new_section
next
}
in_section && /^version: / {
in_section = 0
next
}
in_section {
next
}
{ print }
' "$VALUES_FILE" > "$TEMP_FILE"
mv "$TEMP_FILE" "$VALUES_FILE"

Comment on lines +107 to +114
awk -v new_section="$NEW_VERSION_SECTION" '
/^## @section Application-specific parameters/ {
print new_section
print ""
}
{ print }
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

low

Similarly, write directly to TEMP_FILE instead of TEMP_FILE.tmp to ensure proper cleanup by the exit trap.

Suggested change
awk -v new_section="$NEW_VERSION_SECTION" '
/^## @section Application-specific parameters/ {
print new_section
print ""
}
{ print }
' "$VALUES_FILE" > "$TEMP_FILE.tmp"
mv "$TEMP_FILE.tmp" "$VALUES_FILE"
awk -v new_section="$NEW_VERSION_SECTION" '
/^## @section Application-specific parameters/ {
print new_section
print ""
}
{ print }
' "$VALUES_FILE" > "$TEMP_FILE"
mv "$TEMP_FILE" "$VALUES_FILE"

Comment on lines +11 to +17
type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }}
{{- if .Values.external }}
externalTrafficPolicy: Local
{{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }}
allocateLoadBalancerNodePorts: false
{{- end }}
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

low

Since the entire file is already wrapped in {{- if .Values.external }} on line 1, the nested {{- if .Values.external }} check and the ternary function are redundant. Simplifying this block improves readability.

  type: LoadBalancer
  externalTrafficPolicy: Local
  {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }}
  allocateLoadBalancerNodePorts: false
  {{- end }}

Comment on lines +31 to +38
metadata:
name: {{ .Release.Name }}-metrics
labels:
app: {{ .Release.Name }}-metrics
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
annotations:
spec:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

low

The empty annotations: block is redundant and can be removed to keep the manifest clean.

metadata:
  name: {{ .Release.Name }}-metrics
  labels:
    app: {{ .Release.Name }}-metrics
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:

@github-actions github-actions Bot added size/XL This PR changes 500-999 lines, ignoring generated files and removed size/XXL This PR changes 1000+ lines, ignoring generated files labels Jul 21, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/apps/valkey/templates/valkeyfailover.yaml`:
- Around line 26-28: Update the sentinel.resources configuration in the
valkeyfailover template to use minimal explicit CPU and memory requests/limits
instead of the database-level resourcesPreset/resources values, while leaving
the Valkey data-node resource configuration unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f983917e-bf29-4246-bf78-ca05f315f3b1

📥 Commits

Reviewing files that changed from the base of the PR and between 6c0bf89 and 00d1a4e.

⛔ Files ignored due to path filters (1)
  • packages/apps/valkey/logos/valkey.svg is excluded by !**/*.svg
📒 Files selected for processing (33)
  • .github/workflows/pr-labeler.yaml
  • Makefile
  • api/apps/v1alpha1/valkey/types.go
  • api/apps/v1alpha1/valkey/zz_generated.deepcopy.go
  • docs/storage-immutability.md
  • hack/e2e-chainsaw/valkey/chainsaw-test.yaml
  • hack/e2e-chainsaw/valkey/valkey.yaml
  • packages/apps/valkey/.helmignore
  • packages/apps/valkey/Chart.yaml
  • packages/apps/valkey/Makefile
  • packages/apps/valkey/README.md
  • packages/apps/valkey/charts/cozy-lib
  • packages/apps/valkey/files/versions.yaml
  • packages/apps/valkey/hack/update-versions.sh
  • packages/apps/valkey/images/valkey-7.2.13.tag
  • packages/apps/valkey/images/valkey-8.1.8.tag
  • packages/apps/valkey/images/valkey/Dockerfile
  • packages/apps/valkey/templates/_resources.tpl
  • packages/apps/valkey/templates/_versions.tpl
  • packages/apps/valkey/templates/dashboard-resourcemap.yaml
  • packages/apps/valkey/templates/service.yaml
  • packages/apps/valkey/templates/servicescrape.yaml
  • packages/apps/valkey/templates/valkeyfailover.yaml
  • packages/apps/valkey/values.schema.json
  • packages/apps/valkey/values.yaml
  • packages/core/platform/sources/valkey-application.yaml
  • packages/core/platform/templates/bundles/paas.yaml
  • packages/system/cozystack-basics/templates/clusterroles.yaml
  • packages/system/valkey-rd/Chart.yaml
  • packages/system/valkey-rd/Makefile
  • packages/system/valkey-rd/cozyrds/valkey.yaml
  • packages/system/valkey-rd/templates/cozyrd.yaml
  • packages/system/valkey-rd/values.yaml
🚧 Files skipped from review as they are similar to previous changes (24)
  • packages/system/valkey-rd/Makefile
  • packages/apps/valkey/templates/_versions.tpl
  • packages/core/platform/templates/bundles/paas.yaml
  • packages/apps/valkey/Chart.yaml
  • packages/apps/valkey/.helmignore
  • packages/system/valkey-rd/values.yaml
  • packages/apps/valkey/images/valkey/Dockerfile
  • packages/apps/valkey/images/valkey-8.1.8.tag
  • packages/apps/valkey/images/valkey-7.2.13.tag
  • packages/core/platform/sources/valkey-application.yaml
  • hack/e2e-chainsaw/valkey/valkey.yaml
  • packages/system/valkey-rd/Chart.yaml
  • packages/apps/valkey/files/versions.yaml
  • packages/apps/valkey/charts/cozy-lib
  • .github/workflows/pr-labeler.yaml
  • docs/storage-immutability.md
  • packages/system/cozystack-basics/templates/clusterroles.yaml
  • packages/system/valkey-rd/cozyrds/valkey.yaml
  • packages/apps/valkey/values.yaml
  • packages/apps/valkey/values.schema.json
  • api/apps/v1alpha1/valkey/types.go
  • hack/e2e-chainsaw/valkey/chainsaw-test.yaml
  • packages/apps/valkey/templates/_resources.tpl
  • api/apps/v1alpha1/valkey/zz_generated.deepcopy.go

Comment on lines +26 to +28
sentinel:
replicas: 3
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Avoid allocating full database resources to Sentinel nodes.

Currently, the Sentinel nodes are assigned the exact same resource preset as the Valkey data nodes. Sentinel is a lightweight quorum manager; allocating it database-sized resources (e.g., large CPU/RAM instances) will lead to severe resource waste and potential scheduling issues.

Consider providing minimal explicit resource requests/limits for Sentinels.

⚡ Proposed fix
   sentinel:
     replicas: 3
-    resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }}
+    resources:
+      requests:
+        cpu: 50m
+        memory: 64Mi
+      limits:
+        memory: 128Mi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sentinel:
replicas: 3
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }}
sentinel:
replicas: 3
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
memory: 128Mi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/apps/valkey/templates/valkeyfailover.yaml` around lines 26 - 28,
Update the sentinel.resources configuration in the valkeyfailover template to
use minimal explicit CPU and memory requests/limits instead of the
database-level resourcesPreset/resources values, while leaving the Valkey
data-node resource configuration unchanged.

@kvaps
Andrei Kvapil (kvaps) changed the base branch from main to feat/redis-operator-freshworks July 21, 2026 19:51
@kvaps

Copy link
Copy Markdown
Member Author

Thanks — you're right, and here's the explicit position after digging into the alternatives.

Acknowledged: spotahome/redis-operator is archived (2026-06-11) and we won't build new consumers on a dead upstream.

Direction: migrate the operator to freshworks-oss/redis-operator — an actively-maintained (v3.3.5, commits through July 2026), Apache-2.0 fork that keeps the exact RedisFailover/Sentinel contract (same CRD + API group, so managed Redis is untouched) and adds a native spec.engine: Valkey. That's a third-party maintained fork, so we're not taking on self-maintenance — which also answers your concern about owning a fork.

Answers to your questions:

  • Continued use of the archived operator? No — we move to freshworks-oss.
  • Migration target? freshworks-oss now; we'll track the official valkey-io/valkey-operator as the long-term vendor-neutral home (it's pre-production and Cluster-only today, so not yet a fit for our Sentinel single-endpoint contract).
  • Defer this PR? No need — I've rebased it onto the operator migration and switched Valkey to the native engine: Valkey (the compat shim is gone). It rides on the maintained operator rather than deepening the spotahome dependency.

Operator migration is a separate PR (#3406); this one now stacks on it. Also reaching out about upstreaming the cozystack/redis-operator TLS work into freshworks-oss so it lands in the shared fork.

@IvanHunters IvanHunters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed with the cozy-review methodology. Verdict: LGTM with non-blocking notes. No blocking findings. A clean additive mirror of the existing managed Redis app onto the same operator.

  • Upgrade (Phase 5b): the diff is purely additive: a new app package, a new PackageSource plus bundle entry, a new ApplicationDefinition, and one valkeys resource added to the cozy:tenant:admin:base ClusterRole. No migration, no default changes, no RBAC contraction, no CRD transition.
  • Fresh install: sources/valkey-application.yaml is wired into bundles/paas.yaml:26; dependsOn is identical to redis; cozyrds resourceNames match the dashboard Role under release.prefix: valkey-; make generate has no drift.
  • The Go API module builds and go vet is clean.
  • Render corners (external=true, version=v7, authEnabled=false) are valid and admittable; version=v9 and size="" are correctly rejected by values.schema.json.

Minor (non-blocking)

packages/apps/valkey/templates/valkeyfailover.yaml:119,145: container images (valkey/valkey:..., oliver006/redis_exporter:v1.55.0-alpine) are not digest-pinned and do not go through cozy-lib.image, so air-gapped / mirrored-registry installs fail to pull. This is verbatim parity with the existing packages/apps/redis (same two unpinned lines), i.e. inherited operator-chart debt, not a regression introduced by this PR. If fixed, add the new image lines to the Renovate managerFilePatterns.

Notes

  • This PR is stacked on #3406 (base branch feat/redis-operator-freshworks), and spec.engine: Valkey is served by the CRD from #3406. #3406 should be merged first.
  • Follow-up (non-blocking): the chainsaw suite only covers the default corner; the version=v7, external=true, authEnabled=false branches have no automated test (parity with redis).

…ss fork

spotahome/redis-operator was archived 2026-06-11 (read-only). Switch the
operator to the actively-maintained freshworks-oss/redis-operator fork, which
keeps the same RedisFailover CRD and API group (databases.spotahome.com) and
adds a native Valkey engine (spec.engine: Redis|Valkey) — so managed Redis is
unaffected and managed Valkey no longer needs a Redis-compat shim image.

- re-vendor the chart from oci://ghcr.io/freshworks-oss/charts/redis-operator
- build the operator image from freshworks-oss v3.3.5 source
- re-target the label/annotation-preservation patch onto the freshworks module

The operator image is built out-of-band (make -C packages/system/redis-operator
image) and its digest pinned in values.yaml; a maintainer must rebuild and pin
before merge (tag is a placeholder here).

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
Build the freshworks-oss v3.3.5 operator image (with our label-preservation
patch) and pin its digest in values.yaml, replacing the placeholder tag.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
@kvaps
Andrei Kvapil (kvaps) force-pushed the feat/redis-operator-freshworks branch from 7d03ed6 to ba310b8 Compare July 24, 2026 12:54
Add a managed Valkey service mirroring the managed Redis app. Valkey is the
BSD-3-Clause, Linux Foundation-governed fork of Redis 7.2 and a drop-in
replacement for it, offered as a governance-clean alternative to the now
source-available (AGPLv3/SSPL/RSALv2) Redis 8.x.

Valkey runs on the same Spotahome redis-operator: the operator hardcodes the
redis-server command and redis-cli in its (non-overridable) probe scripts, so
the chart deploys a thin compat image (FROM valkey/valkey:<ver>) that adds the
redis-* symlinks over the official upstream binaries — no Valkey code rebuilt.

Versions offered: v8 (8.1.8, default) and v7 (7.2.13, the BSD Redis 7.2 line).

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
Wire the managed Valkey app into the platform: add the valkey-rd package
carrying the Valkey ApplicationDefinition, the valkey-application PackageSource
(reusing the existing redis-operator), enable it in the paas bundle, and grant
tenant roles access to the valkeys resource.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
Add the Valkey e2e bats test (mirrors redis), build the compat image in the
top-level build target, map the valkey scope to area/database in the PR
labeler, and list valkey among charts with an immutable storageClass.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
The app e2e harness on main is chainsaw (hack/e2e-chainsaw/<app>/), not the
older bats layout. Add hack/e2e-chainsaw/valkey/ mirroring the redis suite so
select-e2e.sh maps the valkey-application source to the valkey suite, and drop
the misplaced hack/e2e-apps/valkey.bats.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
- servicescrape: fix target_label -> targetLabel (snake_case was ignored by the
  VM operator), drop the empty metricRelabelConfigs and annotations keys
- service: drop the redundant inner external conditional (the whole manifest is
  already gated on .Values.external)
- update-versions.sh: write through the trap-tracked temp file and cat back to
  preserve values.yaml permissions
- regenerate README.md parameter table with the pinned cozyvalues-gen v1.6.0
  (column widths differed from the committed version)

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
With the operator on freshworks-oss/redis-operator, RedisFailover supports
spec.engine: Valkey — the operator runs valkey-server/valkey-cli natively. Drop
the thin Redis-compat wrapper image entirely and point the chart at the official
valkey/valkey image directly:

- RedisFailover: set spec.engine: Valkey, image valkey/valkey:<version>
- remove images/ (Dockerfile + per-version tags), the image build target, the
  root build wiring and the images helmignore entry

Depends on the freshworks-oss operator migration.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
The valkey-application PackageSource ships system/valkey-rd (an
ApplicationDefinition); it must dependOn cozystack.cozystack-engine so the
ApplicationDefinition CRD is registered before the -rd HelmRelease reconciles.
Mirrors redis-application.yaml and satisfies check-applicationdefinition-crd-ordering.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
IvanHunters
IvanHunters previously approved these changes Jul 24, 2026

@IvanHunters IvanHunters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. Two independent static reviews (no cluster, no kubectl) both confirm:

  • Faithful mirror of managed Redis: values.yaml/values.schema.json/types.go byte-identical to the redis equivalents modulo redis→valkey rename; valkeyfailover.yaml differs only by spec.engine: Valkey, the valkey image, and monitor labels.
  • Base-branch CRD (#3406) actually supports the switch: engine enum [Redis,Valkey] under databases.spotahome.com/v1 RedisFailover — verified in the base tree, not taken on faith.
  • Renders cleanly across the config matrix: v8/v7, external=true (LoadBalancer), authEnabled=false (drops Secret + auth.secretPath), size=null (ephemeral: appendonly no / save "").
  • All in-repo registries updated: tenant ClusterRole (valkeys), paas bundle, PackageSource, ApplicationDefinition, pr-labeler, storage-immutability doc. Generated artifacts (cozyvalues-gen, schema, README, deepcopy) reproduce with zero git diff; go build/vet clean.
  • Purely additive: new app, new Package CR on upgrade, no existing resource touched — no regression, no migration-state change.
  • Chainsaw e2e is non-vacuous (PVCs Bound, Deployment Available, StatefulSet readyReplicas: 2), matches redis suite.

Non-blocking:

  1. hack/e2e-chainsaw/README.md suite list omits valkey (docs-only; select-e2e.sh discovers dynamically) — add the entry.
  2. update-versions.sh: SC2064 (trap expands at set-time, harmless) and MAJORS=(8 7) hardcode diverges from redis's auto-detect — DRY drift to watch (dev-time script only).
  3. Placeholder logo with non-official brand colors — cosmetic, acknowledged in PR.
  4. Stacked on #3406 (targets feat/redis-operator-freshworks) — correctly declared; #3406 must land first.
  5. Optional follow-up: run cozystack-pr-test on a disposable dev cluster to confirm the freshworks operator schedules valkey/valkey pods for engine: Valkey end-to-end — the one link inherited on trust from #3406.

@kvaps

Andrei Kvapil (kvaps) commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

Timofei Larkin (@lllamnyp) requesting your review, as an API owner, thank you

@kvaps
Andrei Kvapil (kvaps) force-pushed the feat/redis-operator-freshworks branch 2 times, most recently from a95fa0e to 41d1153 Compare July 30, 2026 22:12
@kvaps
Andrei Kvapil (kvaps) force-pushed the feat/redis-operator-freshworks branch 5 times, most recently from a76852c to b3064e1 Compare August 12, 2026 14:07
@kvaps
Andrei Kvapil (kvaps) force-pushed the feat/redis-operator-freshworks branch 3 times, most recently from d0ec44b to 3197c48 Compare August 19, 2026 08:16
Base automatically changed from feat/redis-operator-freshworks to main August 20, 2026 10:11
@lexfrei
Aleksei Sviridkin (lexfrei) dismissed IvanHunters’s stale review August 20, 2026 10:11

The base branch was changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/database Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse) area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/feature Categorizes issue or PR as related to a new feature size/XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants