Skip to content

ci: consolidate CI fixes (#2602 flux 2.8 + #2601 seaweedfs-db + #2612 kubevirt TPM + #2615 e2e trace) - #2619

Closed
myasnikovdaniil wants to merge 40 commits into
mainfrom
ci/consolidation-fixes
Closed

ci: consolidate CI fixes (#2602 flux 2.8 + #2601 seaweedfs-db + #2612 kubevirt TPM + #2615 e2e trace)#2619
myasnikovdaniil wants to merge 40 commits into
mainfrom
ci/consolidation-fixes

Conversation

@myasnikovdaniil

@myasnikovdaniil myasnikovdaniil commented May 12, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Consolidates four open PRs into a single branch so CI can run them together. Each individual PR fails CI on its own because the others' fixes are missing:

Original commits preserved via --no-ff merges, so authorship/signoffs are intact and the per-PR review history is recoverable. Once CI is green here, the four upstream PRs can be closed (or this PR can be split-merged in dependency order).

Conflict resolution

One conflict during the #2601 merge: packages/core/platform/images/migrations/migrations/39 was added on both sides — main's #2607 (instance-type resourcesPreset migration, lands at v40) and #2601's seaweedfs adopt migration. Kept main's 39, renumbered seaweedfs to migration 40 (header: `Migration 40 --> 41`, version stamp: 41). No other conflicts.

Verification

  • `helm template` clean on `seaweedfs-db`, `fluxcd`, `fluxcd-operator`, `kubevirt-instancetypes`
  • Migration version chain intact: 38→39 (vm-image rename), 39→40 (resourcesPreset), 40→41 (seaweedfs-db adopt)
  • All original commits preserved, DCO signoffs intact

Release note

```release-note
NONE
```

Summary by CodeRabbit

  • New Features

    • SeaweedFS database integration now available.
    • Optional Flux Operator web UI (Flux Status) with ingress/network options.
  • Updates

    • Flux Operator upgraded to v0.48.0; Flux distribution to 2.8.x; Helm controller bumped to v1.5.0.
    • Expanded VM instance profiles (Debian, Fedora, Oracle Linux, additional Windows/arch variants).
    • KubeVirt instance types: refined hugepages and CPU/socket sizing.
  • Bug Fixes

    • SeaweedFS release/migration and annotation handling improved.

Review Change Stack

@github-actions github-actions Bot added area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review size/XXL This PR changes 1000+ lines, ignoring generated files labels May 12, 2026
@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR splits SeaweedFS DB into a dedicated chart/HelmRelease with migration, upgrades Flux Operator/Instance to 0.48.0 (adds opt‑in web UI and CRD changes), normalizes KubeVirt instancetypes/preferences, expands VM profiles, and updates tests/infrastructure.

Changes

SeaweedFS HelmRelease Split

Layer / File(s) Summary
SeaweedFS database chart package
packages/system/seaweedfs-db/*
New Helm chart defining CNPG database parameters (replicas, size, storageClass) with schema, Makefile, README and values.
SeaweedFS database release and wiring
packages/extra/seaweedfs/templates/seaweedfs-db.yaml, packages/extra/seaweedfs/templates/seaweedfs.yaml, packages/core/platform/sources/seaweedfs-application.yaml, packages/system/seaweedfs/values.yaml
Adds conditional HelmRelease for DB, adds ${Release.Name}-db to main seaweedfs dependsOn and removes values.db from main seaweedfs values; registers seaweedfs-db component in package source.
Migration to adopt existing Cluster
packages/core/platform/images/migrations/migrations/40
New migration script that re-annotates CNPG Cluster resources when needed to allow Helm adoption and stamps platform version 41.

Flux Operator and Instance Upgrades

Layer / File(s) Summary
Chart metadata and docs
packages/system/fluxcd-operator/charts/flux-operator/*, packages/system/fluxcd/charts/flux-instance/*, packages/system/fluxcd/values.yaml
Bump operator/instance charts to v0.48.0, update README/prereqs and documentation links to fluxoperator.dev, and bump Flux instance distribution to 2.8.x.
Flux Operator web UI infrastructure
packages/system/fluxcd-operator/charts/flux-operator/templates/{_helpers,httproute,ingress,networkpolicy,service,web-secret,web-standard-roles,web-clusterrole}.yaml, packages/system/fluxcd-operator/charts/flux-operator/values.{schema,}yaml
Add helpers to determine web behavior, conditional Secret/Ingress/HTTPRoute/NetworkPolicy templates, service http-web port, web RBAC roles (user/admin/edit), and values/schema enabling opt-in web server.
Deployment, service and RBAC wiring
packages/system/fluxcd-operator/charts/flux-operator/templates/{deployment,admin-clusterrole,aggregate-clusterrole}.yaml, packages/system/fluxcd-operator/patches/networkPolicy.diff, packages/system/fluxcd-operator/values.yaml
Deployment adds web-config checksum, web CLI flags, WEB_SERVER_PORT env, conditional port/mounts; RBAC templates avoid binding web-server-only mode; Cilium policy denies port 9080; default web.enabled: false.
Flux Instance distribution support
packages/system/fluxcd/charts/flux-instance/{Chart,values.schema.json,values.yaml,templates/instance.yaml}
Add instance.distribution.variant schema/value and conditionally render spec.distribution.variant; quote version rendering.
Flux CRD schema enhancements
packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml
CRDs updated to controller-gen v0.20.0; add enterprise-distroless-fips variant; extend ResourceSetInputProvider (filter include/exclude, insecure, auth/type enum), add CEL validations; ResourceSet adds inputStrategy.includeEmptyProviders and status.externalChecksumRefs.

KubeVirt and VM Guest Catalogs

Layer / File(s) Summary
KubeVirt build and instancetypes
packages/system/kubevirt-instancetypes/Makefile, packages/system/kubevirt-instancetypes/templates/instancetypes.yaml
Makefile uses yq to filter by Kind; instancetype manifests updated to explicit hugepages sizes (1Gi/2Mi), align spec.memory.hugepages.pageSize, add spec.cpu.maxSockets, and introduce *1gi* variants.
KubeVirt guest preferences normalization
packages/system/kubevirt-instancetypes/templates/preferences.yaml
Normalize OpenShift metadata to block-scalar, add/standardize required-cpu/required-memory labels, architecture constraints, preferredRng additions, TPM persistence settings, and selective resource changes across many OS entries.
VM profile and RD schema updates
packages/apps/vm-instance/values.schema.json, packages/system/vm-instance-rd/cozyrds/vm-instance.yaml
Expand instanceProfile enum (add Debian, OracleLinux, Fedora s390x, RHEL s390x, linux.* variants, many Windows profiles), remove older CentOS entries; update embedded RD openAPISchema accordingly.

Infrastructure and Template Cleanup

Layer / File(s) Summary
HelmRelease dependsOn cleanup
packages/apps/kubernetes/templates/helmreleases/*
Remove lookup-guarded conditional dependsOn entries across many HelmRelease templates; many now explicitly depend on named releases (e.g., -cilium) or omit the conditional to simplify dependency graphs.
Images and test harness
internal/fluxinstall/manifests/fluxcd-tenants.yaml, hack/e2e-install-cozystack.bats, packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml
Bump helm-controller image to v1.5.0; refactor e2e pre-pull to render helm templates into temp files before piping to yq so set -e fails on helm errors; VPA nested dependsOn removed with explanatory comments to avoid circular waits.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Suggested labels

size:L, area/kubernetes, lgtm

Suggested reviewers

  • lllamnyp
  • kvaps
  • sircthulhu

Poem

🐰 I hopped through charts and templates wide,
SeaweedFS gained a DB to reside,
Flux wears a web door, opt-in and bright,
KubeVirt profiles tuned just right,
The rabbit cheers — the repo takes flight.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/consolidation-fixes

@dosubot dosubot Bot added area/ci Issues or PRs related to CI workflows, GitHub Actions, automation area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) area/storage Issues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor) area/testing Issues or PRs related to testing (e2e, bats, unit tests) labels May 12, 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 serves as a consolidation of four critical fixes required to stabilize the CI pipeline. By decoupling the SeaweedFS database from the system components, the PR eliminates race conditions that previously caused deployment failures. Additionally, it includes necessary upgrades to FluxCD and KubeVirt configurations, ensuring the platform remains compatible with recent upstream changes.

Highlights

  • CI Consolidation: Merged four interdependent PRs into a single branch to resolve CI failures caused by missing cross-component fixes.
  • SeaweedFS Architecture Split: Refactored seaweedfs-system into separate seaweedfs-db and seaweedfs-system Helm releases to resolve EPERM crashloop race conditions during startup.
  • Component Upgrades: Upgraded FluxCD to v2.8.0 and updated KubeVirt instancetypes and preferences to support newer KubeVirt versions.
  • E2E Stability: Improved e2e test reliability by fixing trace verbosity and refining image pre-pull logic in the test suite.
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: **/*.diff (1)
    • packages/system/fluxcd-operator/patches/networkPolicy.diff
  • Ignored by pattern: **/charts/** (25)
    • packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/README.md
    • packages/system/fluxcd-operator/charts/flux-operator/templates/NOTES.txt
    • packages/system/fluxcd-operator/charts/flux-operator/templates/_helpers.tpl
    • packages/system/fluxcd-operator/charts/flux-operator/templates/admin-clusterrole.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/aggregate-clusterrole.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/deployment.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/httproute.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/ingress.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/networkpolicy.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/service.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/web-clusterrole.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/web-secret.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml
    • packages/system/fluxcd-operator/charts/flux-operator/values.schema.json
    • packages/system/fluxcd-operator/charts/flux-operator/values.yaml
    • packages/system/fluxcd/charts/flux-instance/Chart.yaml
    • packages/system/fluxcd/charts/flux-instance/README.md
    • packages/system/fluxcd/charts/flux-instance/templates/NOTES.txt
    • packages/system/fluxcd/charts/flux-instance/templates/healthcheck.yaml
    • packages/system/fluxcd/charts/flux-instance/templates/instance.yaml
    • packages/system/fluxcd/charts/flux-instance/values.schema.json
    • packages/system/fluxcd/charts/flux-instance/values.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.

@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: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/fluxinstall/manifests/fluxcd-tenants.yaml (1)

8-8: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the deployment version label to match the upgraded controller stack.

app.kubernetes.io/version is still v2.7.3 while this manifest now deploys Helm Controller v1.5.0 (Flux 2.8 line). Keeping the label stale can confuse observability and inventory automation.

Suggested patch
-    app.kubernetes.io/version: v2.7.3
+    app.kubernetes.io/version: v2.8.0

Also applies to: 59-59

🤖 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 `@internal/fluxinstall/manifests/fluxcd-tenants.yaml` at line 8, Update the
stale label app.kubernetes.io/version in the fluxcd-tenants manifest to the new
controller stack version (e.g., change from v2.7.3 to the correct version that
matches Helm Controller v1.5.0 / Flux 2.8); locate the YAML key
app.kubernetes.io/version in fluxcd-tenants (and the similar occurrence at the
other reported location) and replace the value so the deployment label reflects
the upgraded controller stack.
🤖 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 `@docs/superpowers/plans/2026-05-10-split-seaweedfs-system.md`:
- Around line 169-175: The fenced code block that currently starts with ```
should include a language tag to satisfy markdownlint MD040; update the opening
fence to include a language (e.g., change ``` to ```text) for the block
containing the Kubernetes cluster YAML snippet (the block with "apiVersion:
postgresql.cnpg.io/v1" and "kind: Cluster" metadata) so the linter recognizes
the language.
- Line 25: The plan still references the old migration identifier migrations/39
for the seaweedfs migration but the merged PR renumbered it to migrations/40
with version stamp 41; update every occurrence of migrations/39 in the document
to migrations/40 and change the corresponding version stamp to 41 (also update
any manual verification/runbook text that mentions migration 39 or the old
version) so the plan matches the merged PR state.

In `@docs/superpowers/specs/2026-05-10-split-seaweedfs-system-design.md`:
- Around line 7-9: The fenced code block containing the literal "dial tcp
<ClusterIP>:5432 (seaweedfs-db-rw): connect: operation not permitted" (and the
other fenced blocks in the same file at the ranges you noted) need a language
annotation to satisfy MD040; update each triple-backtick fence from ``` to
```text (or another appropriate language like ```bash) for the blocks that show
plain output/error to remove the markdownlint warning, e.g., change the fence
around the "dial tcp ..." block and the blocks referenced at ranges 25-40 and
137-156 to include the language identifier.

In `@packages/core/platform/images/migrations/migrations/40`:
- Line 13: The script uses a POSIX sh shebang but then calls "set -euo
pipefail", which fails on Alpine's /bin/sh; change the shebang from "#!/bin/sh"
to "#!/bin/bash" at the top of the migration scripts (or alternatively remove
"pipefail" from the "set -euo pipefail" invocation) so the "set -euo pipefail"
line runs correctly; update the same pattern in the other migration scripts that
use "set -euo pipefail" (e.g., the migrations containing that exact "set -euo
pipefail" line) to ensure consistency.

In `@packages/extra/seaweedfs/templates/seaweedfs.yaml`:
- Around line 120-122: The manifest defines two separate spec.dependsOn entries
which creates duplicate keys; merge them into a single spec.dependsOn list and
remove the unnecessary ingress dependency so only the DB dependency remains.
Locate the spec.dependsOn blocks (the one referencing "{{ .Release.Name }}-db"
and the earlier ingress entry), combine their items into one YAML array under a
single dependsOn key, and drop the ingress item so the final dependsOn contains
only the "{{ .Release.Name }}-db" entry.

In
`@packages/system/fluxcd-operator/charts/flux-operator/templates/httproute.yaml`:
- Line 1: The HTTPRoute template currently renders when
.Values.web.httpRoute.enabled is true even if the web server is disabled; update
the guard in templates/httproute.yaml so the top-level conditional requires both
.Values.web.httpRoute.enabled and .Values.web.enabled (i.e., render only when
the HTTPRoute is enabled and the web server is enabled), and verify any matching
{% raw %}}{{- end }}{% endraw %} or else blocks still align with the new
combined condition.

In
`@packages/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml`:
- Around line 34-36: The RBAC block granting apiGroups: ["*"] and resources:
["*"] with verbs: ["get","list","watch"] in the flux-web-admin role is overly
permissive and allows cluster-wide read of sensitive objects (e.g., Secrets);
update the flux-web-admin (and flux-web-user if present) role definitions to
remove wildcard apiGroups/resources and instead enumerate only non-sensitive
resource kinds (e.g., pods, deployments, services, configmaps, ingresses) or
split into two roles (broad read for non-sensitive resources + a separate,
tightly-scoped role for anything sensitive), or convert the binding pattern to a
namespace-scoped Role/RoleBinding; locate and adjust the apiGroups/resources
block in web-standard-roles.yaml for the flux-web-admin role and ensure
documentation/comments instruct cluster admins to use namespace-scoped
RoleBindings if cluster-wide access is not intended.
- Around line 16-18: The ClusterRole "flux-web-user" currently grants
cluster-wide read on all apiGroups/resources which exposes Secrets and other
sensitive objects; change the ClusterRole to restrict resources to only
non-sensitive types (e.g., "pods","services","configmaps" if acceptable) and
explicitly remove "secrets" and other sensitive resources from the resources
list, or replace the ClusterRole with a namespaced Role and update any bindings
to use Role/RoleBinding to scope permissions per-namespace; look for the
resource/role definition in web-standard-roles.yaml and update the
apiGroups/resources/verbs accordingly to follow least privilege.

In `@packages/system/fluxcd-operator/charts/flux-operator/values.yaml`:
- Around line 17-19: The default enables the Flux Status web UI contrary to the
PR's opt-in requirement; change the value of web.enabled from true to false in
values.yaml (the web.enabled setting) so the web UI is disabled by default and
add or update a comment explaining it must be explicitly enabled by consumers.

In `@packages/system/kubevirt-instancetypes/templates/preferences.yaml`:
- Around line 7-11: The annotations openshift.io/documentation-url and
openshift.io/support-url currently use YAML literal block scalars (the "|" plus
quoted URL) which yields values like "\"https://...\"\n"; fix by emitting plain
scalar URLs (no | and no surrounding quotes/newline) for those keys across the
template (replace the block scalar nodes with bare string nodes for
openshift.io/documentation-url and openshift.io/support-url). Do not hard-edit
generated files long-term—update the regen pipeline instead (the kustomize build
+ yq -i select steps) to preserve upstream plain-scalar URLs from
kubevirt/common-instancetypes so future generations produce bare URLs rather
than block scalars.

---

Outside diff comments:
In `@internal/fluxinstall/manifests/fluxcd-tenants.yaml`:
- Line 8: Update the stale label app.kubernetes.io/version in the fluxcd-tenants
manifest to the new controller stack version (e.g., change from v2.7.3 to the
correct version that matches Helm Controller v1.5.0 / Flux 2.8); locate the YAML
key app.kubernetes.io/version in fluxcd-tenants (and the similar occurrence at
the other reported location) and replace the value so the deployment label
reflects the upgraded controller stack.
🪄 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: 737c2589-4e2c-4d6c-92d6-5d2b2ba3f634

📥 Commits

Reviewing files that changed from the base of the PR and between c247bf4 and 337ace4.

📒 Files selected for processing (49)
  • docs/superpowers/plans/2026-05-10-split-seaweedfs-system.md
  • docs/superpowers/specs/2026-05-10-split-seaweedfs-system-design.md
  • hack/e2e-install-cozystack.bats
  • internal/fluxinstall/manifests/fluxcd-tenants.yaml
  • internal/fluxinstall/manifests/fluxcd.yaml
  • packages/apps/vm-instance/values.schema.json
  • packages/core/platform/images/migrations/migrations/40
  • packages/core/platform/sources/seaweedfs-application.yaml
  • packages/extra/seaweedfs/templates/seaweedfs-db.yaml
  • packages/extra/seaweedfs/templates/seaweedfs.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/README.md
  • packages/system/fluxcd-operator/charts/flux-operator/templates/NOTES.txt
  • packages/system/fluxcd-operator/charts/flux-operator/templates/_helpers.tpl
  • packages/system/fluxcd-operator/charts/flux-operator/templates/admin-clusterrole.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/aggregate-clusterrole.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/deployment.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/httproute.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/ingress.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/networkpolicy.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/service.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/web-clusterrole.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/web-secret.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml
  • packages/system/fluxcd-operator/charts/flux-operator/values.schema.json
  • packages/system/fluxcd-operator/charts/flux-operator/values.yaml
  • packages/system/fluxcd-operator/patches/networkPolicy.diff
  • packages/system/fluxcd-operator/values.yaml
  • packages/system/fluxcd/charts/flux-instance/Chart.yaml
  • packages/system/fluxcd/charts/flux-instance/README.md
  • packages/system/fluxcd/charts/flux-instance/templates/NOTES.txt
  • packages/system/fluxcd/charts/flux-instance/templates/healthcheck.yaml
  • packages/system/fluxcd/charts/flux-instance/templates/instance.yaml
  • packages/system/fluxcd/charts/flux-instance/values.schema.json
  • packages/system/fluxcd/charts/flux-instance/values.yaml
  • packages/system/fluxcd/values.yaml
  • packages/system/kubevirt-instancetypes/Makefile
  • packages/system/kubevirt-instancetypes/templates/instancetypes.yaml
  • packages/system/kubevirt-instancetypes/templates/preferences.yaml
  • packages/system/seaweedfs-db/Chart.yaml
  • packages/system/seaweedfs-db/Makefile
  • packages/system/seaweedfs-db/README.md
  • packages/system/seaweedfs-db/templates/database.yaml
  • packages/system/seaweedfs-db/values.schema.json
  • packages/system/seaweedfs-db/values.yaml
  • packages/system/seaweedfs/values.yaml
  • packages/system/vm-instance-rd/cozyrds/vm-instance.yaml
💤 Files with no reviewable changes (2)
  • packages/system/seaweedfs/values.yaml
  • packages/system/kubevirt-instancetypes/Makefile

- `packages/system/seaweedfs-db/Makefile`
- `packages/system/seaweedfs-db/templates/database.yaml` (moved from system/seaweedfs)
- `packages/extra/seaweedfs/templates/seaweedfs-db.yaml`
- `packages/core/platform/images/migrations/migrations/39`

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update migration numbering in the plan to match the merged PR state.

This plan still instructs creating/running migration 39, but this PR’s merge resolution renumbered the seaweedfs migration to 40 (with version stamp 41). Keeping 39 here can lead to wrong manual verification and operator runbooks.

Suggested doc fix
-- `packages/core/platform/images/migrations/migrations/39`
+- `packages/core/platform/images/migrations/migrations/40`
...
-# Migration 38 --> 39
+# Migration 40 --> 41
...
-kubectl create configmap -n cozy-system cozystack-version \
-  --from-literal=version=39 --dry-run=client -o yaml | kubectl apply -f-
+kubectl create configmap -n cozy-system cozystack-version \
+  --from-literal=version=41 --dry-run=client -o yaml | kubectl apply -f-

Also applies to: 487-529

🤖 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 `@docs/superpowers/plans/2026-05-10-split-seaweedfs-system.md` at line 25, The
plan still references the old migration identifier migrations/39 for the
seaweedfs migration but the merged PR renumbered it to migrations/40 with
version stamp 41; update every occurrence of migrations/39 in the document to
migrations/40 and change the corresponding version stamp to 41 (also update any
manual verification/runbook text that mentions migration 39 or the old version)
so the plan matches the merged PR state.

Comment on lines +169 to +175
```
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: seaweedfs-db
```

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language to the fenced code block to satisfy markdownlint (MD040).

Use a language tag (for this snippet, text is fine).

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 169-169: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@docs/superpowers/plans/2026-05-10-split-seaweedfs-system.md` around lines 169
- 175, The fenced code block that currently starts with ``` should include a
language tag to satisfy markdownlint MD040; update the opening fence to include
a language (e.g., change ``` to ```text) for the block containing the Kubernetes
cluster YAML snippet (the block with "apiVersion: postgresql.cnpg.io/v1" and
"kind: Cluster" metadata) so the linter recognizes the language.

Comment on lines +7 to +9
```
dial tcp <ClusterIP>:5432 (seaweedfs-db-rw): connect: operation not permitted
```

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Annotate fenced code blocks with a language (MD040).

Please add a language to these fences (e.g., text) to avoid markdownlint warnings.

Also applies to: 25-40, 137-156

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 7-7: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@docs/superpowers/specs/2026-05-10-split-seaweedfs-system-design.md` around
lines 7 - 9, The fenced code block containing the literal "dial tcp
<ClusterIP>:5432 (seaweedfs-db-rw): connect: operation not permitted" (and the
other fenced blocks in the same file at the ranges you noted) need a language
annotation to satisfy MD040; update each triple-backtick fence from ``` to
```text (or another appropriate language like ```bash) for the blocks that show
plain output/error to remove the markdownlint warning, e.g., change the fence
around the "dial tcp ..." block and the blocks referenced at ranges 25-40 and
137-156 to include the language identifier.

# so the seaweedfs-system upgrade (which no longer renders the Cluster) does
# not delete it during the transition.

set -euo pipefail

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify shell/runtime assumptions for migration scripts.
echo "== Migration scripts using /bin/sh + pipefail =="
rg -n '^#!/bin/sh|pipefail' packages/core/platform/images/migrations -C1

echo
echo "== Migration image build files (check if bash is guaranteed) =="
fd -i 'Dockerfile*' packages/core/platform/images/migrations | while read -r f; do
  echo "--- $f"
  sed -n '1,120p' "$f"
done

Repository: cozystack/cozystack

Length of output: 10050


Change shebang to #!/bin/bash or remove pipefail from strict mode.

Line 13 uses set -euo pipefail with #!/bin/sh, but /bin/sh on Alpine (busybox) does not support pipefail. This causes the script to fail immediately before any migration logic runs. The Dockerfile explicitly installs bash, so the preferred fix is to use #!/bin/bash as the shebang. This same issue appears across many migration scripts (27–40 and others) and should be addressed systematically.

Recommended fix
-#!/bin/sh
+#!/bin/bash
🤖 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/core/platform/images/migrations/migrations/40` at line 13, The
script uses a POSIX sh shebang but then calls "set -euo pipefail", which fails
on Alpine's /bin/sh; change the shebang from "#!/bin/sh" to "#!/bin/bash" at the
top of the migration scripts (or alternatively remove "pipefail" from the "set
-euo pipefail" invocation) so the "set -euo pipefail" line runs correctly;
update the same pattern in the other migration scripts that use "set -euo
pipefail" (e.g., the migrations containing that exact "set -euo pipefail" line)
to ensure consistency.

Comment thread packages/extra/seaweedfs/templates/seaweedfs.yaml Outdated
@@ -0,0 +1,26 @@
{{- if .Values.web.httpRoute.enabled -}}

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add web.enabled guard to HTTPRoute rendering.

Line 1 renders the route even when the web server is disabled, which can produce a route to a non-serving backend port.

Suggested fix
-{{- if .Values.web.httpRoute.enabled -}}
+{{- if and .Values.web.enabled .Values.web.httpRoute.enabled -}}
📝 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
{{- if .Values.web.httpRoute.enabled -}}
{{- if and .Values.web.enabled .Values.web.httpRoute.enabled -}}
🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

🤖 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/system/fluxcd-operator/charts/flux-operator/templates/httproute.yaml`
at line 1, The HTTPRoute template currently renders when
.Values.web.httpRoute.enabled is true even if the web server is disabled; update
the guard in templates/httproute.yaml so the top-level conditional requires both
.Values.web.httpRoute.enabled and .Values.web.enabled (i.e., render only when
the HTTPRoute is enabled and the web server is enabled), and verify any matching
{% raw %}}{{- end }}{% endraw %} or else blocks still align with the new
combined condition.

Comment on lines +16 to +18
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "list", "watch"]

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.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Overly permissive RBAC grants cluster-wide read access to all resources including Secrets.

The flux-web-user role grants get/list/watch on apiGroups: ["*"] and resources: ["*"], which allows reading ALL cluster resources including Secrets, ConfigMaps, and other sensitive data across all namespaces. This violates the principle of least privilege and could expose credentials, tokens, and private keys to any user assigned this role.

Consider scoping the broad read permissions to non-sensitive resource types, or document that cluster admins should create namespace-scoped RoleBindings rather than cluster-wide ClusterRoleBindings to limit exposure.

🤖 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/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml`
around lines 16 - 18, The ClusterRole "flux-web-user" currently grants
cluster-wide read on all apiGroups/resources which exposes Secrets and other
sensitive objects; change the ClusterRole to restrict resources to only
non-sensitive types (e.g., "pods","services","configmaps" if acceptable) and
explicitly remove "secrets" and other sensitive resources from the resources
list, or replace the ClusterRole with a namespaced Role and update any bindings
to use Role/RoleBinding to scope permissions per-namespace; look for the
resource/role definition in web-standard-roles.yaml and update the
apiGroups/resources/verbs accordingly to follow least privilege.

Comment on lines +34 to +36
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "list", "watch"]

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.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Overly permissive RBAC grants cluster-wide read access to all resources including Secrets.

The flux-web-admin role also grants get/list/watch on apiGroups: ["*"] and resources: ["*"]. Same security concern as flux-web-user: any user with this role can read all Secrets and sensitive data cluster-wide.

Consider scoping the broad read permissions to non-sensitive resource types, or document that cluster admins should create namespace-scoped RoleBindings to limit exposure.

🤖 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/system/fluxcd-operator/charts/flux-operator/templates/web-standard-roles.yaml`
around lines 34 - 36, The RBAC block granting apiGroups: ["*"] and resources:
["*"] with verbs: ["get","list","watch"] in the flux-web-admin role is overly
permissive and allows cluster-wide read of sensitive objects (e.g., Secrets);
update the flux-web-admin (and flux-web-user if present) role definitions to
remove wildcard apiGroups/resources and instead enumerate only non-sensitive
resource kinds (e.g., pods, deployments, services, configmaps, ingresses) or
split into two roles (broad read for non-sensitive resources + a separate,
tightly-scoped role for anything sensitive), or convert the binding pattern to a
namespace-scoped Role/RoleBinding; locate and adjust the apiGroups/resources
block in web-standard-roles.yaml for the flux-web-admin role and ensure
documentation/comments instruct cluster admins to use namespace-scoped
RoleBindings if cluster-wide access is not intended.

Comment on lines +17 to +19
web:
# -- Enable the [Flux Status web server](https://fluxoperator.dev/web-ui/) on port 9080.
enabled: true

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Default web UI enablement conflicts with opt-in rollout.

Line 19 sets web.enabled: true, which makes the web UI active by default. That contradicts the PR objective (“web UI opt-in”) and widens default exposure.

Suggested fix
 web:
   # -- Enable the [Flux Status web server](https://fluxoperator.dev/web-ui/) on port 9080.
-  enabled: true
+  enabled: false
📝 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
web:
# -- Enable the [Flux Status web server](https://fluxoperator.dev/web-ui/) on port 9080.
enabled: true
web:
# -- Enable the [Flux Status web server](https://fluxoperator.dev/web-ui/) on port 9080.
enabled: false
🤖 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/system/fluxcd-operator/charts/flux-operator/values.yaml` around
lines 17 - 19, The default enables the Flux Status web UI contrary to the PR's
opt-in requirement; change the value of web.enabled from true to false in
values.yaml (the web.enabled setting) so the web UI is disabled by default and
add or update a comment explaining it must be explicitly enabled by consumers.

Comment on lines +7 to +11
openshift.io/documentation-url: |
"https://github.com/kubevirt/common-instancetypes"
openshift.io/provider-display-name: KubeVirt
openshift.io/support-url: https://github.com/kubevirt/common-instancetypes/issues
openshift.io/support-url: |
"https://github.com/kubevirt/common-instancetypes/issues"

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm that the |-block-scalar-with-quotes pattern is widespread in this file
# and inspect the regen pipeline that produced it.
set -euo pipefail

echo "=== Occurrences of '| "...URL..."' shape in preferences.yaml ==="
fd -t f 'preferences.yaml' -p 'kubevirt-instancetypes' \
  --exec rg -nC1 -P '^\s*openshift\.io/(documentation|support)-url:\s*\|\s*$' {}

echo
echo "=== The very next non-empty line (the actual value) ==="
fd -t f 'preferences.yaml' -p 'kubevirt-instancetypes' \
  --exec rg -nP '^\s*"https?://' {} \
  | head -20

echo
echo "=== Regen pipeline (Makefile) for kubevirt-instancetypes ==="
fd -t f 'Makefile' -p 'kubevirt-instancetypes' --exec cat {}

Repository: cozystack/cozystack

Length of output: 254


🌐 Web query:

kubevirt common-instancetypes openshift.io/documentation-url annotation format yaml

💡 Result:

The OpenShift annotation key openshift.io/documentation-url is used as a normal string value under metadata.annotations in YAML (typically for OpenShift Template objects, but the same annotation format applies anywhere you set it in an object's metadata). Example YAML value (as shown in KubeVirt’s OpenShift Templates user guide): metadata: annotations: openshift.io/documentation-url: "https://github.com/kubevirt/common-templates" [1] For KubeVirt common-instancetypes specifically, the instancetype resources live under API types like VirtualMachineInstancetype/VirtualMachineClusterInstancetype (and common-instancetypes are a set of those resources), and their spec has an optional spec.annotations map[string]string that is used by the instancetype to apply annotations to the VirtualMachineInstance. That map is also expressed in YAML as key/value pairs under annotations: [2] apiVersion: instancetype.kubevirt.io/v1beta1 kind: VirtualMachineInstancetype metadata: name: example-instancetype spec: annotations: some-annotation-key: "some-value" [2] Note: In the KubeVirt instancetype API, spec.annotations is declared as Annotations map[string]string (optional), so it is not free-form YAML text; it must be a string map. [2]

Citations:


🏁 Script executed:

#!/bin/bash
# Find the preferences.yaml file for kubevirt-instancetypes
echo "=== Finding preferences.yaml file ==="
find . -type f -name "preferences.yaml" -path "*/kubevirt-instancetypes/*"

echo
echo "=== Checking for Makefile in kubevirt-instancetypes ==="
find . -type f -name "Makefile" -path "*/kubevirt-instancetypes/*"

Repository: cozystack/cozystack

Length of output: 276


🏁 Script executed:

#!/bin/bash
# Once we find the file, let's look at specific lines from the review comment
FILE=$(find . -type f -name "preferences.yaml" -path "*/kubevirt-instancetypes/*" | head -1)
if [ -n "$FILE" ]; then
  echo "=== Content at lines 7-11 (first occurrence) ==="
  sed -n '7,11p' "$FILE"
  
  echo
  echo "=== Content at lines 37-42 (second occurrence) ==="
  sed -n '37,42p' "$FILE"
  
  echo
  echo "=== Sample of literal block scalar pattern (first 5 occurrences) ==="
  rg -n 'openshift\.io/(documentation|support)-url:\s*\|' "$FILE" | head -5
  
  echo
  echo "=== File size and line count ==="
  wc -l "$FILE"
fi

Repository: cozystack/cozystack

Length of output: 1061


🏁 Script executed:

#!/bin/bash
# Check the Makefile for the regen pipeline
MAKEFILE=$(find . -type f -name "Makefile" -path "*/kubevirt-instancetypes/*" | head -1)
if [ -n "$MAKEFILE" ]; then
  echo "=== Makefile for kubevirt-instancetypes ==="
  cat "$MAKEFILE"
fi

Repository: cozystack/cozystack

Length of output: 633


🌐 Web query:

kubevirt common-instancetypes repository raw manifest documentation-url annotation format

💡 Result:

The kubevirt/common-instancetypes repository is located at https://github.com/kubevirt/common-instancetypes. It provides a set of cluster-wide and namespaced VirtualMachineInstancetypes and VirtualMachinePreferences for KubeVirt VMs [1][2]. Deploy using kubectl apply -k https://github.com/kubevirt/common-instancetypes.git [2]. Latest release v1.6.0 as of 2026-01-28 [1]. Raw manifests are generated via kustomize from the repo's bases (e.g., for VirtualMachineInstancetypes: kubectl apply -k https://github.com/kubevirt/common-instancetypes.git/VirtualMachineInstancetypes) [2]. Example raw YAML snippet from KubeVirt bundles: - instancetype.kubevirt.io/common-instancetypes-version: v1.1.0 + instancetype.kubevirt.io/common-instancetypes-version: v1.2.0 name: cx1.2xlarge [3]. The key annotation in these manifests is instancetype.kubevirt.io/common-instancetypes-version: <version> (e.g., v1.2.0, v1.6.0), which identifies the common-instancetypes release/version used [3]. No documentation-url annotation is explicitly documented in sources for these manifests, but the repo homepage links to official docs: https://kubevirt.io/user-guide/virtual_machines/instancetypes/#common-instancetypes [1]. InstanceType specs support an optional annotations field for custom annotations applied to VMIs [4].

Citations:


🏁 Script executed:

#!/bin/bash
# Fetch the upstream manifest to see what format it uses before yq processing
echo "=== Fetching upstream preferences from kubevirt/common-instancetypes ==="
# Use kustomize to build the same upstream target
kustomize build https://github.com/kubevirt/common-instancetypes//preferences 2>/dev/null | head -100

Repository: cozystack/cozystack

Length of output: 136


🏁 Script executed:

#!/bin/bash
# If kustomize is not available, try to check what the current regen would produce
# Let's compare: run kustomize, then show before and after yq
FILE="./packages/system/kubevirt-instancetypes/templates/preferences.yaml"

echo "=== Current file first occurrence (lines 7-11) ==="
sed -n '7,11p' "$FILE"

echo
echo "=== Check if yq is available and test the select behavior ==="
which yq && echo "yq found" || echo "yq not found"

echo
echo "=== Count how many resources match the filter that should be removed ==="
if command -v yq &> /dev/null; then
  grep -c "^kind:" "$FILE" || true
fi

Repository: cozystack/cozystack

Length of output: 567


🏁 Script executed:

#!/bin/bash
# Let's also check if the upstream source (kubevirt/common-instancetypes) 
# has documentation on the annotation format by examining the repo
echo "=== Check if we can get upstream manifest info ==="
# Try to fetch raw content from the repo
curl -s https://raw.githubusercontent.com/kubevirt/common-instancetypes/main/preferences/CentOS-7.yaml | head -50

Repository: cozystack/cozystack

Length of output: 128


🏁 Script executed:

#!/bin/bash
# Check the directory structure and look for Chart.yaml
echo "=== Directory structure of kubevirt-instancetypes ==="
ls -la packages/system/kubevirt-instancetypes/

echo
echo "=== Check for Chart.yaml ==="
find packages/system/kubevirt-instancetypes -name "Chart.yaml" -exec cat {} \;

echo
echo "=== Check if templates/ contains other files ==="
ls -la packages/system/kubevirt-instancetypes/templates/ 2>/dev/null | head -20

Repository: cozystack/cozystack

Length of output: 959


🏁 Script executed:

#!/bin/bash
# Let's verify the actual YAML parsing outcome by checking how the annotation value
# would be interpreted. Count lines in a resource block to understand nesting.
FILE="./packages/system/kubevirt-instancetypes/templates/preferences.yaml"

echo "=== First resource with metadata/annotations (lines 1-20) ==="
sed -n '1,20p' "$FILE"

echo
echo "=== Check YAML structure: metadata.annotations block ==="
sed -n '1,35p' "$FILE" | cat -A

Repository: cozystack/cozystack

Length of output: 1895


Fix annotation values: remove literal block scalars (|) to preserve bare URLs

The openshift.io/documentation-url and openshift.io/support-url annotations are using YAML literal block scalars (|), which preserve the embedded quotes and trailing newline. This produces malformed annotation values—for example, "https://github.com/kubevirt/common-instancetypes"\n instead of the bare URL. Any tooling that consumes these annotations as hyperlinks (dashboards, UIs, OperatorHub) will receive a malformed value.

This pattern occurs throughout the file at all indicated line ranges (7-11, 37-42, 69-74, and continuing through 2341-2345).

The issue likely originates from the regen pipeline in the Makefile (kustomize build followed by yq -i select). Verify the format of these annotations in the upstream kubevirt/common-instancetypes manifests. If upstream emits bare URLs without the literal block scalar syntax, update the regen pipeline to preserve that format rather than correcting this generated file directly.

🤖 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/system/kubevirt-instancetypes/templates/preferences.yaml` around
lines 7 - 11, The annotations openshift.io/documentation-url and
openshift.io/support-url currently use YAML literal block scalars (the "|" plus
quoted URL) which yields values like "\"https://...\"\n"; fix by emitting plain
scalar URLs (no | and no surrounding quotes/newline) for those keys across the
template (replace the block scalar nodes with bare string nodes for
openshift.io/documentation-url and openshift.io/support-url). Do not hard-edit
generated files long-term—update the regen pipeline instead (the kustomize build
+ yq -i select steps) to preserve upstream plain-scalar URLs from
kubevirt/common-instancetypes so future generations produce bare URLs rather
than block scalars.

@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 implements an architectural split of the seaweedfs-system HelmRelease into seaweedfs-db and seaweedfs-system to resolve startup race conditions, utilizing HelmRelease.spec.healthCheckExprs for readiness gating. It includes the creation of a new chart, updates to existing templates, and a migration script for resource ownership. Additional changes include updates to vm-instance profiles, kubevirt-instancetypes, and various dependency versions. The review feedback identifies issues with POSIX shell compatibility in migration scripts, versioning logic conflicts, schema definition inaccuracies, and cleanup logic in E2E tests.

# so the seaweedfs-system upgrade (which no longer renders the Cluster) does
# not delete it during the transition.

set -euo pipefail

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

set -o pipefail is a non-standard extension not supported by all POSIX-compliant shells (such as dash, often the default /bin/sh). Since the shebang is #!/bin/sh and the project guidelines specify POSIX shell for migrations, this will cause the script to fail with an 'Illegal option' error in environments where /bin/sh is not bash or zsh.

Suggested change
set -euo pipefail
set -eu

Comment on lines +2 to +32
# Migration 40 --> 41
# Adopt existing Cluster/seaweedfs-db resources into the new seaweedfs-db
# HelmRelease introduced in this release.
#
# Pre-split, the CNPG Cluster lived inside the seaweedfs-system Helm release.
# Splitting moves it to a new release named seaweedfs-db. We rewrite the
# helm ownership annotations so Helm adopts the existing Cluster instead of
# erroring on the next reconcile, and stamp helm.sh/resource-policy: keep
# so the seaweedfs-system upgrade (which no longer renders the Cluster) does
# not delete it during the transition.

set -euo pipefail

# Iterate every namespace that has a Cluster named "seaweedfs-db".
for ns in $(kubectl get cluster.postgresql.cnpg.io -A \
-o jsonpath='{range .items[?(@.metadata.name=="seaweedfs-db")]}{.metadata.namespace}{"\n"}{end}'); do
current=$(kubectl get cluster.postgresql.cnpg.io seaweedfs-db -n "$ns" \
-o jsonpath='{.metadata.annotations.meta\.helm\.sh/release-name}' 2>/dev/null || true)
if [ "$current" = "seaweedfs-system" ]; then
echo "Re-annotating Cluster/seaweedfs-db in $ns: seaweedfs-system -> seaweedfs-db"
kubectl annotate cluster.postgresql.cnpg.io seaweedfs-db -n "$ns" \
meta.helm.sh/release-name=seaweedfs-db \
helm.sh/resource-policy=keep \
--overwrite
# release-namespace stays the same (tenant namespace, e.g. tenant-root)
fi
done

# Stamp version
kubectl create configmap -n cozy-system cozystack-version \
--from-literal=version=41 --dry-run=client -o yaml | kubectl apply -f-

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 is an inconsistency in the migration versioning logic:

  1. The filename is 40.
  2. The header says Migration 40 --> 41.
  3. The version stamp at the end sets version=41.

If this migration is intended to follow migration 39 from main, it should be named 40, migrate 39 --> 40, and set version=40. If it is intended to be version 41 (to avoid a conflict with another migration 40 mentioned in the PR description), the file should be renamed to 41. Naming it 40 while setting version 41 skips a version in the state tracking and will likely overwrite an existing migration 40 during merge.

Additionally, the implementation plan in docs/superpowers/plans/2026-05-10-split-seaweedfs-system.md still refers to this as migration 39 (line 25), which should also be updated.

Comment on lines +9 to +18
## @typedef {struct} DB - Database configuration.
## @field {int} [replicas] - Number of database replicas.
## @field {quantity} [size] - Persistent Volume size.
## @field {string} [storageClass] - StorageClass used to store the data.

## @param {DB} db - Database configuration.
db:
replicas: 2
size: 10Gi
storageClass: ""

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

The Resources typedef is defined but not used in the DB struct. Furthermore, the HelmRelease in packages/extra/seaweedfs/templates/seaweedfs-db.yaml passes db.resources, which is not declared here. This results in an incomplete values.schema.json, preventing the dashboard from correctly validating or displaying these parameters.

## @typedef {struct} DB - Database configuration.
## @field {int} [replicas] - Number of database replicas.
## @field {Resources} [resources] - Resource configuration.
## @field {quantity} [size] - Persistent Volume size.
## @field {string} [storageClass] - StorageClass used to store the data.

## @param {DB} db - Database configuration.
db:
  replicas: 2
  resources: {}
  size: 10Gi
  storageClass: ""

Comment on lines +7 to +8
openshift.io/documentation-url: |
"https://github.com/kubevirt/common-instancetypes"

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

The use of block scalars (|) with double quotes for URL fields (e.g., openshift.io/documentation-url) causes the quotes to be included as literal characters in the string value (e.g., "https://..."). This is likely an unintended side effect of the regeneration process and will break any tool or UI attempting to resolve these URLs. This pattern is repeated throughout the file.

Comment on lines +28 to +31
kubeovn_yaml=$(mktemp)
linstor_yaml=$(mktemp)
helm template packages/system/kubeovn > "$kubeovn_yaml"
helm template packages/system/linstor > "$linstor_yaml"

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 temporary files created with mktemp are only removed at the end of the function. If any command (like helm template) fails, the script will exit immediately due to set -e (standard in bats), leaving these files on the disk. Consider using a trap to ensure cleanup regardless of the test outcome.

myasnikovdaniil added a commit that referenced this pull request May 12, 2026
…or-vpa HR

The packages/system/vertical-pod-autoscaler chart's vpa-for-vpa.yaml template
emits an HR in cozy-vpa-for-vpa that the parent helm install applies and waits
on. That nested HR had `dependsOn: monitoring-agents`, which never resolves:

  parent VPA helm install
    waits for nested vpa-for-vpa HR Ready
      waits for monitoring-agents HR Ready
        waits for cozystack.vertical-pod-autoscaler PackageSource Ready
          waits for parent VPA HR Ready  <-- back to start

Symptom observed on PR #2619 e2e (cozyreport):

  Helm upgrade failed for release cozy-vertical-pod-autoscaler/
  vertical-pod-autoscaler with chart cozy-vertical-pod-autoscaler@...:
  timeout waiting for: [HelmRelease/cozy-vpa-for-vpa/vpa-for-vpa
  status: 'InProgress']

The recommender's /health-check readiness probe is served by the binary
itself and doesn't require Prometheus. Removing the dependsOn lets the
nested HR become Ready quickly; the recommender will log connection
errors against vmselect until monitoring-agents installs later in the
boot sequence, then start producing recommendations normally.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
myasnikovdaniil added a commit that referenced this pull request May 13, 2026
…or-vpa HR

The packages/system/vertical-pod-autoscaler chart's vpa-for-vpa.yaml template
emits an HR in cozy-vpa-for-vpa that the parent helm install applies and waits
on. That nested HR had `dependsOn: monitoring-agents`, which never resolves:

  parent VPA helm install
    waits for nested vpa-for-vpa HR Ready
      waits for monitoring-agents HR Ready
        waits for cozystack.vertical-pod-autoscaler PackageSource Ready
          waits for parent VPA HR Ready  <-- back to start

Symptom observed on PR #2619 e2e (cozyreport):

  Helm upgrade failed for release cozy-vertical-pod-autoscaler/
  vertical-pod-autoscaler with chart cozy-vertical-pod-autoscaler@...:
  timeout waiting for: [HelmRelease/cozy-vpa-for-vpa/vpa-for-vpa
  status: 'InProgress']

The recommender's /health-check readiness probe is served by the binary
itself and doesn't require Prometheus. Removing the dependsOn lets the
nested HR become Ready quickly; the recommender will log connection
errors against vmselect until monitoring-agents installs later in the
boot sequence, then start producing recommendations normally.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@myasnikovdaniil
myasnikovdaniil force-pushed the ci/consolidation-fixes branch from 60aecd5 to faa448a Compare May 13, 2026 16:25

@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.

♻️ Duplicate comments (1)
packages/core/platform/images/migrations/migrations/40 (1)

1-1: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Change shebang to #!/bin/bash for pipefail compatibility.

Line 13 uses set -euo pipefail, but /bin/sh on Alpine (busybox) does not support pipefail. Since the migration image includes bash, change the shebang to #!/bin/bash.

🐛 Recommended fix
-#!/bin/sh
+#!/bin/bash
🤖 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/core/platform/images/migrations/migrations/40` at line 1, The
script's shebang uses /bin/sh but later relies on "set -euo pipefail" which
requires bash; update the shebang in the migration script (the line currently
"#!/bin/sh") to "#!/bin/bash" so pipefail is supported, leaving the existing
"set -euo pipefail" and rest of the script (migration file in
packages/core/platform/images/migrations/migrations/40).
🤖 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.

Duplicate comments:
In `@packages/core/platform/images/migrations/migrations/40`:
- Line 1: The script's shebang uses /bin/sh but later relies on "set -euo
pipefail" which requires bash; update the shebang in the migration script (the
line currently "#!/bin/sh") to "#!/bin/bash" so pipefail is supported, leaving
the existing "set -euo pipefail" and rest of the script (migration file in
packages/core/platform/images/migrations/migrations/40).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d1924aed-1090-446d-b43b-aaffa71e5f63

📥 Commits

Reviewing files that changed from the base of the PR and between 60aecd5 and faa448a.

📒 Files selected for processing (18)
  • hack/e2e-install-cozystack.bats
  • packages/apps/vm-instance/values.schema.json
  • packages/core/platform/images/migrations/migrations/40
  • packages/core/platform/sources/seaweedfs-application.yaml
  • packages/extra/seaweedfs/templates/seaweedfs-db.yaml
  • packages/extra/seaweedfs/templates/seaweedfs.yaml
  • packages/system/kubevirt-instancetypes/Makefile
  • packages/system/kubevirt-instancetypes/templates/instancetypes.yaml
  • packages/system/kubevirt-instancetypes/templates/preferences.yaml
  • packages/system/seaweedfs-db/Chart.yaml
  • packages/system/seaweedfs-db/Makefile
  • packages/system/seaweedfs-db/README.md
  • packages/system/seaweedfs-db/templates/database.yaml
  • packages/system/seaweedfs-db/values.schema.json
  • packages/system/seaweedfs-db/values.yaml
  • packages/system/seaweedfs/values.yaml
  • packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml
  • packages/system/vm-instance-rd/cozyrds/vm-instance.yaml
💤 Files with no reviewable changes (2)
  • packages/system/kubevirt-instancetypes/Makefile
  • packages/system/seaweedfs/values.yaml
✅ Files skipped from review due to trivial changes (4)
  • packages/core/platform/sources/seaweedfs-application.yaml
  • packages/system/seaweedfs-db/Chart.yaml
  • hack/e2e-install-cozystack.bats
  • packages/system/seaweedfs-db/README.md
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/system/seaweedfs-db/values.schema.json
  • packages/system/vm-instance-rd/cozyrds/vm-instance.yaml
  • packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml
  • packages/system/seaweedfs-db/values.yaml
  • packages/system/seaweedfs-db/Makefile
  • packages/apps/vm-instance/values.schema.json
  • packages/extra/seaweedfs/templates/seaweedfs.yaml
  • packages/system/kubevirt-instancetypes/templates/instancetypes.yaml
  • packages/system/kubevirt-instancetypes/templates/preferences.yaml

myasnikovdaniil added a commit that referenced this pull request May 14, 2026
PR #2619 split seaweedfs into a serialized chain
(seaweedfs-db -> seaweedfs-system -> seaweedfs) that needs ~5 min of
wall-clock to install: CNPG bootstrap, master quorum, then the wrapper.
With the prior 5m wait budget on the parent tenant HR, helm-controller
would time out before the children reach Ready, rollback would delete
the child HRs, and the upgrade would retry in a loop. The e2e bats step
that patches the Tenant CR and waits 60s for child HRs to exist landed
in the rollback gap and timed out.

Two complementary changes:

- tenant-root is created statically by cozystack-basics, so its
  HelmRelease spec.timeout is bumped 5m -> 15m directly.
- Sub-tenants (Tenant CRs) get their HR built by cozystack-api from
  the tenant ApplicationDefinition. Add the
  release.cozystack.io/helm-install-timeout=15m annotation that
  kubernetes-rd already uses to opt the kind into the longer budget.

Keeps both values in lockstep and documents the coupling inline.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
myasnikovdaniil added a commit that referenced this pull request May 14, 2026
The bats step had two waits for tenant-root child HRs:

  kubectl wait hr/etcd hr/ingress hr/tenant-root hr/seaweedfs --timeout=4m
  kubectl wait hr/monitoring hr/seaweedfs-system --timeout=2m

The second line was the residue of a flux-reconcile-force workaround
removed in 7d292eb; the mechanical cleanup kept the same HRs on a
separate 2m wait without revisiting whether the line still made sense.
After PR #2509 fixed the underlying timing bug:

- monitoring is a top-level tenant-root child, identical shape to etcd
  and ingress; its Ready is already implied by hr/tenant-root Ready on
  the first line.
- seaweedfs-system is an internal HR of the seaweedfs umbrella chart;
  its Ready is already implied by hr/seaweedfs Ready on the first line.

So the second wait was always tautologically true by the time it ran,
and the naming inconsistency (top-level monitoring next to internal
seaweedfs-system) was an accident of the historical workaround. Promote
monitoring to the first line where it belongs and drop the redundant
second wait.

Also bump the wait from 4m to 10m. seaweedfs now installs as a serial
chain seaweedfs-db (CNPG bootstrap) -> seaweedfs-system (raft quorum)
-> seaweedfs wrapper, so the parent tenant-root HR's Ready flip lags
~5-6 min. The previous 4m budget was sized for the old single-HR
seaweedfs and is the immediate cause of the e2e failure on PR #2619.
The 10m budget stays inside tenant-root HR.spec.timeout (15m).

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
myasnikovdaniil added a commit that referenced this pull request May 14, 2026
Flux helm-controller v1.5.0 (shipped in Flux v2.8) replaced the legacy
Helm readiness logic with kstatus-based health checking, which polls
Deployment/StatefulSet/Service status and waits for kstatus to assess
rollout-ready. This typically adds 10-30s of latency between resource
apply and HR condition Ready=True compared to v2.7.

Our per-app bats tests had `kubectl wait hr/... --for=condition=ready
--timeout=` budgets of 20s, 30s, 60s, 100s — sized for v2.7's faster
readiness flip and previously masked by the 3x retry on Run E2E tests
(dropped in #2558). Under v2.8 with no retry, every app that runs after
the first few hit its HR wait timeout exactly, surfacing as 13 of 16
test failures on PR #2619.

Standardise on 5m for HR Ready across all app tests. Tight enough to
catch genuine bring-up failures within the per-app job budget, loose
enough to absorb kstatus dispatch jitter on a management cluster that
is concurrently reconciling multiple tenant-test HRs.

Post-HR-Ready checks for app-specific resources (StatefulSet/Service/
PVC/operator CRs) remain — for CR-based apps kstatus only observes
that the chart applied, not that the operator finished. Audit of
which of those are actually redundant under v2.8 kstatus is queued
as a follow-up.

Also bumps the 10s "kamajicontrolplane appears" wait in
run-kubernetes.sh to 2m, and the kubernetes-addon HR Ready loop from
1m to 5m for the same reason.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
myasnikovdaniil added a commit that referenced this pull request May 15, 2026
Five PackageSources whose charts apply cert-manager Certificate CRs and
mount the resulting Secret on a webhook Deployment lacked an explicit
dependsOn: cozystack.cert-manager. Under Flux v2.8 helm-controller v1.5.0
kstatus, the dependent Deployment trips progressDeadlineSeconds (10m
default) when cert-manager controller isn't running yet, and the HR is
failed early. Repeatedly observed on PR #2619 with capi-operator,
kamaji, rabbitmq-operator, cozystack-api (cozystack-engine), and
ingress-nginx all cascading to InstallFailed at ~12-15m into a fresh
install.

The mariadb-operator, kubeovn-webhook, snapshot-controller, etcd-operator,
postgres-operator, mongodb-operator, victoria-metrics-operator, linstor,
and linstor-scheduler PackageSources already had the dependency, which
is why they weren't in the failure set.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
myasnikovdaniil added a commit that referenced this pull request May 15, 2026
…afka WorkloadMonitor replicas paths

Flux v2.8 / helm-controller v1.5.0 embeds Helm v4, which renamed --force
to --force-replace and rejects combining it with SSA's --force-conflicts.
Existing HelmReleases with spec.upgrade.force: true fail every upgrade with
"cannot use force conflicts and force replace together", looping
upgrade -> rollback -> upgrade and blocking dependants. Observed on PR #2619
CI for tenant-root/{ingress-nginx-system,seaweedfs-db}, tenant-test/info,
and others.

Per Flux docs, upgrade.force has been a no-op since v2.8 anyway, so removing
it is safe on green clusters and unblocks broken ones.

Also fix packages/apps/kafka/templates/workloadmonitor.yaml: it referenced
.Values.replicas (no such field; values.yaml has kafka.replicas and
zookeeper.replicas). Flux v2.7 silently dropped the null; v2.8 SSA forwards
it, and the WorkloadMonitor CRD rejects "spec.replicas: null" as not
type:integer, which blocks every kafka-test install.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Bump flux-operator and flux-instance vendored charts from v0.33.0 to
v0.48.0, moving the Flux distribution from 2.7.x to 2.8.x. This brings
helm-controller v1.5.x, which exposes spec.install.healthCheckExprs on
HelmRelease — a prerequisite for adding real readiness gating to
dependency-target packages (postgres, mongodb, kafka, etc.).

The new flux-operator chart defaults web.enabled=true; override it to
false in packages/system/fluxcd-operator/values.yaml so the Flux Status
Web UI stays opt-in. Operators wanting it can set web.enabled=true and
configure web.config / web.configSecretName / web.ingress per the
upstream chart values.

Patches reapplied:
- kubernetesEnvs.diff: matched cleanly (offset shift only)
- networkPolicy.diff: extended to also restrict port 9080 (web UI port);
  hunk count updated 20 -> 22

Pre-flight: no references to the v0.39-removed --disable-wait-interruption
flag anywhere in packages/ or internal/.

Verified locally:
- helm template renders both packages without errors
- web.enabled=false (default): no web Deployment/Service/NetworkPolicy
- web.enabled=true: renders web NetworkPolicy on port 9080
- CiliumClusterwideNetworkPolicy lists 8080/8081/9080
- FluxInstance distribution.version: "2.8.x", all 7 components present
- Cozystack kustomize patches (concurrent, requeue, storage-adv-addr,
  events-addr) intact

Notable upstream changes between v0.33 and v0.48:
- Flux 2.8.x with HelmRelease inventory format change (auto-migrated)
- Reliability fixes for stuck FluxInstance/ResourceSet on health-check
  cancellation (v0.39, v0.46)
- New CLI: flux-operator migrate, diff, patch instance, distro mirror
- ResourceSetInputProvider: GitLab Environments, GitHub App, Gitea/Forgejo
- CVE-2026-23990 (Web UI OIDC impersonation bypass) — N/A while web is off

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
… 2.8.0

Re-render internal/fluxinstall/manifests/fluxcd.yaml via
`make update` in packages/core/flux-aio (timoni bundle build against
oci://ghcr.io/stefanprodan/modules/flux-aio at the latest tag) so
the cozystack-operator binary embeds Flux 2.8.0 instead of 2.7.3.
Auto-syncs the helm-controller image into fluxcd-tenants.yaml.

Embedded versions now match the chart bump in the prior commit:
  flux:                   v2.7.3 -> v2.8.0
  helm-controller:        v1.4.3 -> v1.5.0   (enables healthCheckExprs)
  source-controller:      v1.7.3 -> v1.8.0
  kustomize-controller:   v1.7.2 -> v1.8.0
  notification-controller:v1.7.4 -> v1.8.0
  source-watcher:         v2.0.2 -> v2.1.0

Verified by rebuilding cmd/cozystack-operator and running `strings`
on the binary -- the expected v1.5.0 / v1.8.0 / v2.1.0 image strings
are now embedded in place of the v1.4.x / v1.7.x ones.

Structure preserved:
- single AIO Deployment named "flux" in namespace cozy-fluxcd
- all 5 controllers + source-watcher as containers in one pod
- custom tolerations from flux-aio.cue intact
- Namespace pod-security label still "privileged" via the
  Makefile yq post-processing step

Net diff is -3664 lines (mostly CRD schema simplification in 2.8).

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@myasnikovdaniil

Copy link
Copy Markdown
Contributor Author

Split into 8 review-friendly PRs. All branches rebased onto fresh main; all commits GPG-signed + DCO-signed-off; duplicate signoff trailers de-duped. Numbering follows the proposal we agreed on:

Chain (B stacks on A):

Independent of #2602:

Dropped (already merged separately on main):

Dropped (not re-proposed):

  • ci(e2e): fail fast on first failing bats, cancel remaining apps — your call.

Closing this PR. All review activity should move to the split PRs.

@lexfrei Aleksei Sviridkin (lexfrei) removed the area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review label May 25, 2026
myasnikovdaniil added a commit that referenced this pull request May 26, 2026
)

## What this PR does

Adds `startupProbe` to two operator deployments whose readiness probes
fail repeatedly during a cold cluster install, generating noise and (for
CDI) blocking dependants on slow leader-election:

- **`kubevirt-cdi-operator`** — leader-election against a slow
`kube-apiserver` (Kamaji control plane bringup) consistently takes >30s
on a cold install. The default readinessProbe with 1s `periodSeconds` /
3 `failureThreshold` fires the first time election times out, the
operator pod gets marked NotReady, and dependants block on it.
- **`grafana-operator`** — bootstrap CRD discovery + Helm-managed
Dashboard reconcile loop spikes startup duration past readinessProbe's
default budget under load.

`startupProbe` gives each operator a longer one-time window to reach
steady state; the regular `readinessProbe` then takes over with its
tight per-second cadence to detect genuine ongoing failures.

## Origin

Both commits lifted unchanged from #2619.

### Release note

```release-note
NONE
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Configuration Updates**
  * Added startup health checks to Grafana operator container
  * Added startup health checks to KubeVirt CDI operator container

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2725?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
myasnikovdaniil added a commit that referenced this pull request May 26, 2026
## What this PR does

Pre-pulls every image referenced by `packages/system/kubeovn`,
`packages/system/linstor`, and `packages/system/cert-manager` onto every
node before those HelmReleases install. Cluster-member workloads (OVN
raft, LINSTOR, cert-manager webhook) fail when replicas start at
different times due to per-node image-pull stagger; pre-pulling means
all replicas start with images already cached.

## Mechanics

Renders each chart with `helm template`, then runs a `yq` filter that
walks every PodSpec-shaped object and emits the images of each container
— scoping the output to images the kubelet actually pulls (skips
configmap fields and CRD examples that happen to contain an `image:`
key). Each render is staged through a tmp file so a helm-template
failure trips `set -e` cleanly (cozytest.sh runs `@test` bodies under
`/bin/sh`, which is dash on Ubuntu CI — no `pipefail`).

The pre-pull DaemonSet itself is the hard part: distroless images
(cert-manager and friends) ship no shell and no `/bin/sleep`, so the
obvious `command: ["sleep", "infinity"]` fails with `exec: ENOENT`. The
script stages a statically-linked `busybox:musl` into a shared
`emptyDir` from an initContainer; every prepull container then execs
`/shared/sleep` regardless of what the image itself ships. The glibc
`busybox` tag is unusable — it needs `/lib64/ld-linux-x86-64.so.2` which
distroless lacks.

## Origin

Lifted from #2619 — squash of `test(e2e): pre-pull cert-manager images`
→ POSIX rewrite → cert-manager removal (failed on distroless) →
reintroduction with the busybox helper that solves the distroless
problem. Final state only — the four iterative commits aren't
review-friendly individually.

## Verification

- `sh -n hack/e2e-prepull-images.sh` clean
- All chart-referenced images held Ready under the DaemonSet on local
kind v1.33.1 single-node

### Release note

```release-note
NONE
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Improved end-to-end test reliability for platform image pre-pulling by
rendering charts separately and consolidating extracted images.
* Simplified and consolidated readiness waits during tenant
configuration for more robust application readiness checks.

* **Chores**
* Enhanced image pre-pulling to reliably handle distroless images using
a staged helper binary and shared volume approach.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2724?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
myasnikovdaniil added a commit that referenced this pull request May 27, 2026
Five PackageSources whose charts apply cert-manager Certificate CRs and
mount the resulting Secret on a webhook Deployment lacked an explicit
dependsOn: cozystack.cert-manager. Under Flux v2.8 helm-controller v1.5.0
kstatus, the dependent Deployment trips progressDeadlineSeconds (10m
default) when cert-manager controller isn't running yet, and the HR is
failed early. Repeatedly observed on PR #2619 with capi-operator,
kamaji, rabbitmq-operator, cozystack-api (cozystack-engine), and
ingress-nginx all cascading to InstallFailed at ~12-15m into a fresh
install.

The mariadb-operator, kubeovn-webhook, snapshot-controller, etcd-operator,
postgres-operator, mongodb-operator, victoria-metrics-operator, linstor,
and linstor-scheduler PackageSources already had the dependency, which
is why they weren't in the failure set.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 0fc0796)
myasnikovdaniil added a commit that referenced this pull request May 27, 2026
The dashboard gatekeeper (oauth2-proxy) does OIDC discovery against the
external host at container startup. The e2e sandbox uses
host=example.org which does not resolve, so the auth-proxy crashloops:

  Get "https://keycloak.example.org/realms/cozy/.well-known/openid-configuration":
    dial tcp: lookup keycloak.example.org: no such host

Under Flux v2.8 kstatus the gatekeeper Deployment then flips to
'Failed' (rather than the pre-v2.8 'InProgress') and stalls the
cozy-dashboard/dashboard HelmRelease, which in turn blocks
cozy-fluxcd/flux-plunger via dependsOn. Previous runs masked this with
an unrelated ImagePullBackOff on cozy-dashboard-console; with the
console image fixed the OIDC discovery failure now surfaces.

packages/core/platform/values.yaml:194-198 already declares
authentication.oidc.keycloakInternalUrl. When set, the dashboard
chart (packages/system/dashboard/templates/gatekeeper.yaml:59-66)
renders --skip-oidc-discovery plus explicit redeem/jwks/validate/
backend-logout URLs pointing at the in-cluster keycloak Service.
Browser-facing redirect-url and login-url stay on the external host
(they are not exercised by the e2e flow).

The patch sets the value alongside oidc.enabled in the same
kubectl-patch so the configmap and gatekeeper rollout happen in one
reconcile pass.

Observed on CI run 26142986969 (PR #2619).

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 5915a57)
myasnikovdaniil added a commit that referenced this pull request May 27, 2026
…2726)

## What this PR does

Adds `cert-manager` as a `dependsOn` entry to the five PackageSources
whose charts apply `cert-manager.io/v1` `Certificate` CRs and need the
webhook ready before their first reconcile. Without this, the helm
install renders Certificate manifests, the cert-manager webhook isn't
admitting requests yet (cold cluster), the apply fails, and
helm-controller retries until the webhook eventually comes up — burning
~2-3 minutes per affected package on cold installs.

The five PackageSources: `capi-operator`, `cozystack-engine`,
`ingress-nginx`, `kamaji`, and `rabbitmq-operator` (the platform
`cozy-system` set with webhook-cert consumers; not the apps layer).

In `cozystack-engine`, the dependency is added to both the `default` and
`oidc` variants — the `oidc` variant installs the same `cozystack-api`
and `lineage-controller-webhook` components that render Certificate
resources, so it had the same race.

## Origin

First commit lifted unchanged from #2619. Second commit (`oidc` variant)
added in response to review feedback.

### Release note

```release-note
NONE
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Chores**
* Updated package source dependencies across multiple components to
ensure proper installation sequencing.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2726?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
myasnikovdaniil added a commit that referenced this pull request May 27, 2026
…rl (#2728)

## What this PR does

Bundles four independent e2e improvements lifted from #2619:

1. **`test(e2e): fold ouroboros assertions into kubernetes-latest`** —
moves the standalone `hack/e2e-apps/ouroboros.bats` (which provisioned
its own full Kamaji control plane, ~25m) into the existing
`kubernetes-latest` run as an optional addon. The assertions cover
ouroboros HR Ready, controller pod Running, `Ingress → coredns-custom`
rewrite-line injection, and end-to-end DNS resolution from inside the
tenant. Reuses the existing tenant cluster instead of building a second
one.

2. **`test(e2e): wait for tenant CSI HR Ready before NFS test`** —
explicit `kubectl wait hr/kubernetes-${test_name}-csi
--for=condition=ready` ahead of the NFS pod. Otherwise the NFS pod
schedules while the `kubevirt-csi-node` DaemonSet is still rolling out,
eats ~1m on `FailedAttachVolume` retries, and trips the pod-Succeeded
wait.

3. **`test(e2e): bump NFS pod wait to 10m to fit slow-path chain`** —
was 5m. With dependencies properly serialized (per #2), 5m was tight on
slow runners; 10m gives the chain genuine room without masking real
bugs.

4. **`test(e2e): set keycloakInternalUrl when enabling OIDC`** — the
dashboard gatekeeper (oauth2-proxy) does OIDC discovery against the
keycloak Service URL; without an explicit `keycloakInternalUrl`, it
falls back to the public ingress URL which isn't routable from inside
the cluster yet during install.

## Origin

All four commits lifted unchanged from #2619.

### Release note

```release-note
NONE
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Integrated Ouroboros validations into the main Kubernetes end-to-end
flow (removed separate standalone Ouroboros test)
* Added hairpin-NAT and in-tenant DNS resolution checks for Ouroboros
scenarios
* Improved Keycloak OIDC test by configuring an in-cluster internal URL
* Increased various timeouts and readiness waits and added tenant CSI
readiness gating to improve test reliability

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2728?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
myasnikovdaniil added a commit that referenced this pull request May 28, 2026
…afka WorkloadMonitor replicas paths

Flux v2.8 / helm-controller v1.5.0 embeds Helm v4, which renamed --force
to --force-replace and rejects combining it with SSA's --force-conflicts.
Existing HelmReleases with spec.upgrade.force: true fail every upgrade with
"cannot use force conflicts and force replace together", looping
upgrade -> rollback -> upgrade and blocking dependants. Observed on PR #2619
CI for tenant-root/{ingress-nginx-system,seaweedfs-db}, tenant-test/info,
and others.

Per Flux docs, upgrade.force has been a no-op since v2.8 anyway, so removing
it is safe on green clusters and unblocks broken ones.

Also fix packages/apps/kafka/templates/workloadmonitor.yaml: it referenced
.Values.replicas (no such field; values.yaml has kafka.replicas and
zookeeper.replicas). Flux v2.7 silently dropped the null; v2.8 SSA forwards
it, and the WorkloadMonitor CRD rejects "spec.replicas: null" as not
type:integer, which blocks every kafka-test install.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 7e286cf)
myasnikovdaniil added a commit that referenced this pull request May 28, 2026
…or-vpa HR

The packages/system/vertical-pod-autoscaler chart's vpa-for-vpa.yaml template
emits an HR in cozy-vpa-for-vpa that the parent helm install applies and waits
on. That nested HR had `dependsOn: monitoring-agents`, which never resolves:

  parent VPA helm install
    waits for nested vpa-for-vpa HR Ready
      waits for monitoring-agents HR Ready
        waits for cozystack.vertical-pod-autoscaler PackageSource Ready
          waits for parent VPA HR Ready  <-- back to start

Symptom observed on PR #2619 e2e (cozyreport):

  Helm upgrade failed for release cozy-vertical-pod-autoscaler/
  vertical-pod-autoscaler with chart cozy-vertical-pod-autoscaler@...:
  timeout waiting for: [HelmRelease/cozy-vpa-for-vpa/vpa-for-vpa
  status: 'InProgress']

The recommender's /health-check readiness probe is served by the binary
itself and doesn't require Prometheus. Removing the dependsOn lets the
nested HR become Ready quickly; the recommender will log connection
errors against vmselect until monitoring-agents installs later in the
boot sequence, then start producing recommendations normally.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 08433dc)
myasnikovdaniil added a commit that referenced this pull request May 28, 2026
Flux helm-controller v1.5.0 (shipped in Flux v2.8) replaced the legacy
Helm readiness logic with kstatus-based health checking, which polls
Deployment/StatefulSet/Service status and waits for kstatus to assess
rollout-ready. This typically adds 10-30s of latency between resource
apply and HR condition Ready=True compared to v2.7.

Our per-app bats tests had `kubectl wait hr/... --for=condition=ready
--timeout=` budgets of 20s, 30s, 60s, 100s — sized for v2.7's faster
readiness flip and previously masked by the 3x retry on Run E2E tests
(dropped in #2558). Under v2.8 with no retry, every app that runs after
the first few hit its HR wait timeout exactly, surfacing as 13 of 16
test failures on PR #2619.

Standardise on 5m for HR Ready across all app tests. Tight enough to
catch genuine bring-up failures within the per-app job budget, loose
enough to absorb kstatus dispatch jitter on a management cluster that
is concurrently reconciling multiple tenant-test HRs.

Post-HR-Ready checks for app-specific resources (StatefulSet/Service/
PVC/operator CRs) remain — for CR-based apps kstatus only observes
that the chart applied, not that the operator finished. Audit of
which of those are actually redundant under v2.8 kstatus is queued
as a follow-up.

Also bumps the 10s "kamajicontrolplane appears" wait in
run-kubernetes.sh to 2m, and the kubernetes-addon HR Ready loop from
1m to 5m for the same reason.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 5ef02ee)
myasnikovdaniil added a commit that referenced this pull request May 28, 2026
PR #2619 split seaweedfs into a serialized chain
(seaweedfs-db -> seaweedfs-system -> seaweedfs) that needs ~5 min of
wall-clock to install: CNPG bootstrap, master quorum, then the wrapper.
With the prior 5m wait budget on the parent tenant HR, helm-controller
would time out before the children reach Ready, rollback would delete
the child HRs, and the upgrade would retry in a loop. The e2e bats step
that patches the Tenant CR and waits 60s for child HRs to exist landed
in the rollback gap and timed out.

Two complementary changes:

- tenant-root is created statically by cozystack-basics, so its
  HelmRelease spec.timeout is bumped 5m -> 15m directly.
- Sub-tenants (Tenant CRs) get their HR built by cozystack-api from
  the tenant ApplicationDefinition. Add the
  release.cozystack.io/helm-install-timeout=15m annotation that
  kubernetes-rd already uses to opt the kind into the longer budget.

Keeps both values in lockstep and documents the coupling inline.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit cc9da3a)
myasnikovdaniil added a commit that referenced this pull request May 28, 2026
…edfs-system (#2601)

## What this PR does

Splits the `seaweedfs-system` HelmRelease into two: the CNPG
`Cluster/seaweedfs-db` moves to its own HR (`seaweedfs-db`), and the
application HR (`seaweedfs-system`) `dependsOn` it. The new HR uses Flux
v2 `HelmRelease.spec.healthCheckExprs` with a CEL expression on
`Cluster.status.conditions[type=Ready]` plus `waitStrategy.name:
poller`, so its `Ready=True` only flips after the postgres primary is
actually serving connections — not just after `helm install` applied the
`Cluster` CR.

This eliminates the `seaweedfs-filer` CrashLoopBackOff race on a fresh
tenant install. With Cilium `kubeProxyReplacement: true`, socket-LB
returns `EPERM` from `connect(2)` to ClusterIPs with no Ready endpoints.
Pre-split, the filer StatefulSet scheduled concurrently with the CNPG
bootstrap (~55–70s of unavailable postgres), each `connect()` failed
`EPERM`, kubelet exponential restart backoff pushed past the e2e bats
`kubectl wait hr/seaweedfs-system --timeout=2m` window, and the
"Configure Tenant and wait for applications" test failed.

## Stacked on #2602

This PR depends on **#2602** (Flux v2.8.0 upgrade) — `healthCheckExprs`
is a helm-controller v1.5.0 feature. GitHub base set to `flux-bump-v048`
so the diff cleanly shows only this PR's changes; will auto-rebase onto
`main` once #2602 merges.

## Commits

1. **`refactor(seaweedfs)`** — the split itself. Squash of the three
iterative commits from the consolidated branch (#2619): the initial
split, a `dependsOn` merge-collision fix (collapses unconditional
`seaweedfs-db` dependency with the namespace-guarded ingress dependency
into one list), and the `healthCheckExprs` three-predicate form (route
CNPG's `ClusterIsNotReady` bootstrap condition to `inProgress`, reserve
`failed` for other `Ready=False` reasons, lean on the HR `timeout: 10m`
as the real backstop).
2. **`fix(tenant)`** — bump parent HR `spec.timeout` from 5m → 15m so
the serialized `seaweedfs-db → seaweedfs-system → seaweedfs` chain has
enough wall-clock budget. Two complementary changes: the static
`tenant-root` HR (created by `cozystack-basics`) gets its `spec.timeout`
bumped directly; sub-tenants (Tenant CRs whose HR is built by
`cozystack-api` from the `tenant` ApplicationDefinition) get the
`release.cozystack.io/helm-install-timeout=15m` annotation that
`kubernetes-rd` already uses to opt into the longer budget.
3. **`test(e2e)`** — consolidate two redundant child-HR waits in
`hack/e2e-install-cozystack.bats` into one budgeted assert. The second
`kubectl wait` (`hr/monitoring hr/seaweedfs-system --timeout=2m`) was a
residue of a `flux-reconcile-force` workaround removed in #2509;
`monitoring`'s Ready is already implied by `hr/tenant-root` Ready and
`seaweedfs-system`'s by `hr/seaweedfs` Ready, so the line was
tautologically true by the time it ran.

## Migration

`packages/core/platform/images/migrations/migrations/42` adopts existing
`Cluster/seaweedfs-db` resources into the new release on upgrade —
rewrites `meta.helm.sh/release-name: seaweedfs-system → seaweedfs-db`
and stamps `helm.sh/resource-policy: keep` so the `seaweedfs-system`
upgrade (which no longer renders the Cluster) does not delete it during
the transition. Renumbered from the consolidated branch's slot 40 to fit
fresh main (last migration is 41). `targetVersion` bumped 42 → 43.

The new HR's `upgrade.force: true` was dropped to match #2602's
platform-wide cleanup (Helm v4 in helm-controller v1.5.0 rejects
combining `--force-replace` with SSA's `--force-conflicts`).

## Verification

- `helm template` renders `seaweedfs-db` HR cleanly with
`healthCheckExprs`, `waitStrategy: poller`, and `upgrade: { remediation:
{ retries: -1 } }` (no `force: true`).
- Migration 42 syntax-checks under `sh -n`.
- All four PR commits GPG-signed + DCO-signed-off.

### Release note

```release-note
NONE
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* SeaweedFS database is now available as a separate, independently
configurable component with customizable replicas, storage size, and
storage class options.

* **Chores**
* Restructured database configuration from the main application into a
dedicated component for improved modularity and initialization order.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2601?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@myasnikovdaniil myasnikovdaniil self-assigned this May 28, 2026
myasnikovdaniil added a commit that referenced this pull request Jun 2, 2026
…(folds #2612) (#2602)

## What this PR does

Upgrades Flux v2.7.3 → v2.8.0 across both the vendored tenant chart and
the embedded management-cluster manifests, and folds in the chart fixes
that become hard errors under the new strict helm-controller v1.5.

Flux v2.8's helm-controller v1.5.0 ships:
- **Server-Side Apply with `--force-conflicts`** — strict CRD schema
enforcement; misplaced fields (silently dropped on v2.7) now fail the
apply.
- **kstatus-based health checking** by default — parent HR waits for
every applied resource (including child HRs) to be Ready before flipping
its own Ready, surfacing latent ordering deadlocks.
- **Helm v4 embedded** — `upgrade.force: true` is deprecated and now
conflicts with SSA.
- **`HelmRelease.spec.healthCheckExprs`** — prerequisite for proper
readiness gating (used in PR #2601 split).

Folds in PR #2612 (kubevirt-instancetypes null TPM fix) since the same
Flux upgrade triggers it.

## Commits

**Flux upgrade itself:**
- `feat(fluxcd)`: bump `flux-operator` / `flux-instance` vendored charts
to v0.48.0; web UI opt-in.
- `feat(flux)`: regenerate embedded management-cluster manifests via
`make update` in `packages/core/flux-aio` (timoni bundle build).

**Chart fixes for strict SSA — fields the chart sent that v2.7 silently
dropped, v2.8 rejects:**
- `fix(kubevirt-instancetypes)`: drop persistent strip that produced
null `preferredTPM` (folds #2612).
- `fix(foundationdb)`: relocate `faultDomain`, `imageType`, `labels`,
`minimumUptimeSecondsForBounce` from inside `automationOptions` to
direct children of `spec`.
- `fix(kafka)`: place `enableServiceLinks` under `template.pod`, not a
phantom `template.spec`.
- `fix(vm-instance)`: emit `disk: {}` (not `disk:`/null) when no bus is
set.
- `fix(platform)`: drop deprecated `upgrade.force: true` from
HelmReleases; fix `kafka` WorkloadMonitor `replicas` paths.

**Ordering / deadlock fixes under v2.8 kstatus:**
- `fix(vpa)`: break circular wait between parent install and nested
`vpa-for-vpa` HR.
- `fix(kubernetes)`: drop lookup-guarded parent-HR `dependsOn` on tenant
addon child HRs (parent waits on child via kstatus, child waited on
parent — deadlock).

**E2E waits for v2.8 kstatus timing:**
- `test(e2e)`: bump app HR-Ready waits to 5m (was 20s–100s under v2.7's
faster dispatch).
- `test(e2e)`: wait for parent HR Ready before downstream asserts in
`run-kubernetes.sh` and `vminstance.bats`.

## Scope discipline

This PR is part of the split of #2619 (the consolidated CI fixes branch)
into review-friendly pieces. Companion PRs:
- **PR #2601** (seaweedfs split) — folded into this PR (commits
`29c6afc8`, `0e8b46d7`, `7157158c`, `dccdeb52`, `f880b324`): the
seaweedfs-system → seaweedfs-db + seaweedfs-system split, its adoption
migration 43 (targetVersion 44), and the configurable db resources all
land here, because the strict-SSA `upgrade.force` removal and the
kstatus parent-HR timeout bump only make sense together with the split.
#2601 is superseded.
- **PR #2558** (drop 3× retry on `Run E2E` + `Install Cozystack`) —
independent, lands separately.
- Several smaller standalone fixes lifted out of #2619 (startup probes,
cert-manager `dependsOn`, prepull machinery, CSI HR timeout, NFS/OIDC
test improvements) — opened as separate PRs.

## Verification

- `helm template` renders cleanly for both `fluxcd` and
`fluxcd-operator` packages with `web.enabled=false` (default) and
`web.enabled=true`.
- Embedded `cmd/cozystack-operator` binary contains the v1.5.0 / v1.8.0
/ v2.1.0 controller image strings.
- No references to the v0.39-removed `--disable-wait-interruption` flag
anywhere in `packages/` or `internal/`.

### Release note

```release-note
Flux upgraded to v2.8.0 (helm-controller v1.5 — Helm v4 Server-Side Apply with --force-conflicts, kstatus health checking).

When upgrading existing clusters:
- Kubernetes 1.33+ is now required for the platform (management) cluster, and for any tenant cluster that enables the optional (default-off) Flux addon — that addon ships the bumped Flux too.
- HelmReleases no longer set `upgrade.force: true`. Helm v4 SSA resolves field-ownership conflicts automatically (`--force-conflicts`), but that is not the old client-side replace: immutable-field changes (e.g. StatefulSet volumeClaimTemplates/serviceName) no longer self-heal and require manual recreation — delete the object (e.g. `kubectl delete sts <name> --cascade=orphan`) and let Flux recreate it.
- KubeVirt: persistent TPM/EFI is re-enabled for the Windows 11/2k22/2k25 preferences (KubeVirt 1.8 VMPersistentState); each affected VM provisions an extra RWO backend-storage PVC from the default StorageClass.
- KubeVirt: the EOL centos.7*/centos.stream8* preferences are retained as deprecated, hidden aliases (`tags: hidden`, `instancetype.kubevirt.io/deprecated: "true"`) — existing VMInstances on these profiles keep rendering and need no action on upgrade, but the profiles are no longer offered for new VMs; repoint to centos.stream9/10 when convenient. The gn1.* GPU instancetypes are likewise retained.
- FoundationDB: imageType now reaches the operator (silently dropped pre-SSA); it is pinned to `split` to match the value existing clusters effectively ran, so upgrades stay non-disruptive. Set `imageType: unified` to migrate deliberately.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Flux Status web UI: optional web server, config secret, service port,
HTTPRoute/Ingress, network policy, and RBAC roles.
  * New SeaweedFS DB Helm chart and optional managed DB release.

* **Improvements**
* CRD/schema enhancements: new provider kinds, validations, variant
option, and external checksum refs.
* Raised Kubernetes prerequisite to 1.30+; extended e2e timeouts for
reliability.

* **Chores**
* Bumped Flux Operator and Flux versions; documentation links updated to
fluxoperator.dev.
* **Bug Fixes**
  * Removed aggressive HelmRelease force-upgrade/install flags.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2602?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
myasnikovdaniil added a commit that referenced this pull request Jun 5, 2026
Aligns kubevirt-csi-node HR with every other tenant addon HR in
packages/apps/kubernetes/templates/helmreleases/ (cilium, coredns,
ingress-nginx, etc.) — all set timeout: 10m, csi.yaml was the only
exception. 9f9d8f8 ("Allign timeouts for HelmReleases") missed it.

Symptom: e2e NFS test (hack/e2e-apps/run-kubernetes.sh) times out
waiting for nfs-test-pod to reach Succeeded. Cozyreport events show
the tenant csi HR running Install -> Uninstall -> Install remediation
cycles. With install.remediation.retries: -1 and the default 5m Helm
timeout, kstatus marks the kubevirt-csi-node DaemonSet 'InProgress'
past 5m on a slow tenant control-plane bringup (Kamaji APIs flapping,
VM image pulls), helm-controller times out, the remediation uninstalls
the DaemonSet, then reinstalls. Any volume mount in flight at that
moment is wedged.

Observed on PR #2619 CI run 26142986969: csi HR remediation at
~07:07 happened ~10 min into the nfs-test-pod wait, killing the
mount and timing out the pod-Succeeded condition.

10m matches the surrounding HRs and gives the DaemonSet headroom
without changing remediation semantics on truly-broken installs.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 866588f)
@myasnikovdaniil

Copy link
Copy Markdown
Contributor Author

Closing this because it was preview of changes, actual progress here #2397

myasnikovdaniil added a commit that referenced this pull request Jun 8, 2026
Aligns kubevirt-csi-node HR with every other tenant addon HR in
packages/apps/kubernetes/templates/helmreleases/ (cilium, coredns,
ingress-nginx, etc.) — all set timeout: 10m, csi.yaml was the only
exception. 9f9d8f8 ("Allign timeouts for HelmReleases") missed it.

Symptom: e2e NFS test (hack/e2e-apps/run-kubernetes.sh) times out
waiting for nfs-test-pod to reach Succeeded. Cozyreport events show
the tenant csi HR running Install -> Uninstall -> Install remediation
cycles. With install.remediation.retries: -1 and the default 5m Helm
timeout, kstatus marks the kubevirt-csi-node DaemonSet 'InProgress'
past 5m on a slow tenant control-plane bringup (Kamaji APIs flapping,
VM image pulls), helm-controller times out, the remediation uninstalls
the DaemonSet, then reinstalls. Any volume mount in flight at that
moment is wedged.

Observed on PR #2619 CI run 26142986969: csi HR remediation at
~07:07 happened ~10 min into the nfs-test-pod wait, killing the
mount and timing out the pod-Succeeded condition.

10m matches the surrounding HRs and gives the DaemonSet headroom
without changing remediation semantics on truly-broken installs.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 866588f)
Aleksei Sviridkin (lexfrei) added a commit that referenced this pull request Jun 9, 2026
…ay.bats tenant teardown (#2558)

## What this PR does

Drops the 3× retry loop on `Run E2E tests` and `Install Cozystack into
sandbox`. `Prepare environment` keeps its 3× retry — that step is pure
infrastructure (Talos image download, sandbox VM boot, network) where
transient runner hiccups warrant a retry.

On failure, the test step now captures `kubectl get hr -A -o wide` and
`kubectl get events -A` under a collapsible group so triage starts with
the actual broken-state snapshot.

> [!NOTE]
> An earlier revision of this PR also doubled every bats timeout. That
commit was dropped in a rebase and is intentionally **not restored**:
the timeout class that actually matters (per-app HR-Ready waits) has
since been standardized at 5m on `main` (7b9f286), making a blanket 2×
redundant.

**Fixes gateway.bats teardown leakage.** The nested-tenant tests deleted
tenants fire-and-forget, parent and child back-to-back. The leftover
uninstalls (each blocked on a cleanup Job, parents wedged on
still-terminating child namespaces) plus one mid-install child HR
occupied exactly 5 workers on the `--concurrent=5` tenants
helm-controller shard, starving whichever app test ran next — observed
as the harbor HR sitting unreconciled for its whole 5m HR-Ready budget
in [run
27020081550](https://github.com/cozystack/cozystack/actions/runs/27020081550),
surfaced by this PR's own retry removal + diagnostics dump. Teardown now
deletes child→parent with hard `wait hr --for=delete` between, so a
wedged tenant uninstall fails gateway.bats itself, not an innocent
neighbor.

## Why

Audit of 30 successful PR runs found that across 5 sampled failure
attempts, **25/25 retries** on `Run E2E tests` failed — the retry loop
never recovered a flake, only stretched deterministic failures and
tripled diagnostic wall-time. Same data shape on `Install Cozystack`.

Beyond wasted CI time, the retry was hiding ~10 deterministic bugs (Helm
namespace-ownership conflict, seaweedfs HR timeout, harbor BucketInfo
wiring, vminstance disk race, etc.). Each failure looked like a "flake"
because the retry sometimes coincided with whatever transient state had
cleared — the retry never fixed the bug, just delayed surfacing.

## Dependencies

The deterministic bugs the retry was masking are now fixed on `main`:
- ✅ **#2508** — installer namespace bootstrap (Helm namespace-ownership
conflict on cold install) — merged
- ✅ **#2509** — operator HelmRelease config knobs (`seaweedfs-system`
2-min wait race within Flux's 5-min reconcile windows) — merged
- ✅ **#2528** — harbor bucket-secret + BucketInfo gating (harbor
`ValuesError` on first install) — merged
- ✅ **#2529** — objectstorage-controller BucketAccess conflict retry —
merged

Companion PRs in the #2619 split (independent of this PR,
ordering-wise):
- **#2602** — Flux v2.8.0 + chart fixes
- **#2601** — seaweedfs-system split

This PR does NOT depend on #2602/#2601 — it now touches only the
workflow file and gateway.bats teardown, both on top of fresh `main`.

Surfaced from #2500.

### Release note

```release-note
NONE
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* CI prepare-environment step now reports plain attempt counts with
clear success/failure messages.
* Install and per-app test steps no longer retry; each runs once and
fails immediately on error. Failed apps log diagnostics and job proceeds
to remaining apps while overall job fails.
* **Tests**
* End-to-end tests and install/prepare flows use longer, more tolerant
timeouts and added existence polling to reduce flakiness and improve
diagnostics.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2558?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Aleksei Sviridkin (lexfrei) pushed a commit that referenced this pull request Jun 10, 2026
Aligns kubevirt-csi-node HR with every other tenant addon HR in
packages/apps/kubernetes/templates/helmreleases/ (cilium, coredns,
ingress-nginx, etc.) — all set timeout: 10m, csi.yaml was the only
exception. 9f9d8f8 ("Allign timeouts for HelmReleases") missed it.

Symptom: e2e NFS test (hack/e2e-apps/run-kubernetes.sh) times out
waiting for nfs-test-pod to reach Succeeded. Cozyreport events show
the tenant csi HR running Install -> Uninstall -> Install remediation
cycles. With install.remediation.retries: -1 and the default 5m Helm
timeout, kstatus marks the kubevirt-csi-node DaemonSet 'InProgress'
past 5m on a slow tenant control-plane bringup (Kamaji APIs flapping,
VM image pulls), helm-controller times out, the remediation uninstalls
the DaemonSet, then reinstalls. Any volume mount in flight at that
moment is wedged.

Observed on PR #2619 CI run 26142986969: csi HR remediation at
~07:07 happened ~10 min into the nfs-test-pod wait, killing the
mount and timing out the pod-Succeeded condition.

10m matches the surrounding HRs and gives the DaemonSet headroom
without changing remediation semantics on truly-broken installs.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 866588f)
myasnikovdaniil added a commit that referenced this pull request Jun 16, 2026
Aligns kubevirt-csi-node HR with every other tenant addon HR in
packages/apps/kubernetes/templates/helmreleases/ (cilium, coredns,
ingress-nginx, etc.) — all set timeout: 10m, csi.yaml was the only
exception. 9f9d8f8 ("Allign timeouts for HelmReleases") missed it.

Symptom: e2e NFS test (hack/e2e-apps/run-kubernetes.sh) times out
waiting for nfs-test-pod to reach Succeeded. Cozyreport events show
the tenant csi HR running Install -> Uninstall -> Install remediation
cycles. With install.remediation.retries: -1 and the default 5m Helm
timeout, kstatus marks the kubevirt-csi-node DaemonSet 'InProgress'
past 5m on a slow tenant control-plane bringup (Kamaji APIs flapping,
VM image pulls), helm-controller times out, the remediation uninstalls
the DaemonSet, then reinstalls. Any volume mount in flight at that
moment is wedged.

Observed on PR #2619 CI run 26142986969: csi HR remediation at
~07:07 happened ~10 min into the nfs-test-pod wait, killing the
mount and timing out the pod-Succeeded condition.

10m matches the surrounding HRs and gives the DaemonSet headroom
without changing remediation semantics on truly-broken installs.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 866588f)
Aleksei Sviridkin (lexfrei) added a commit that referenced this pull request Jun 16, 2026
## What this PR does

Adds `spec.timeout: 10m` to the `kubevirt-csi-node` HelmRelease template
in `packages/apps/kubernetes/templates/helmreleases/csi.yaml`, aligning
it with every other tenant addon HR in the same directory (cilium,
coredns, ingress-nginx, etc. — all set `timeout: 10m`). `csi.yaml` was
the only one missing it; commit 9f9d8f8 ("Align timeouts for
HelmReleases") missed this template.

## Symptom

E2E NFS test times out waiting for `nfs-test-pod` to reach `Succeeded`.
Cozyreport events show the tenant `csi` HR running an Install →
Uninstall → Install remediation cycle. With
`install.remediation.retries: -1` and the default 5m Helm timeout,
kstatus marks the `kubevirt-csi-node` DaemonSet `InProgress` past 5m on
a slow tenant control-plane bringup (Kamaji APIs flapping, VM image
pulls), helm-controller times out, the remediation uninstalls the
DaemonSet, then reinstalls. Any volume mount in flight at that moment is
wedged.

## Origin

Single commit lifted unchanged from #2619.

### Release note

```release-note
NONE
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Updated the Container Storage Interface (CSI) Helm release settings to
include a `spec.timeout` of **10 minutes** when the etcd namespace value
is set (keeping the existing `spec.interval` at **5 minutes**).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci Issues or PRs related to CI workflows, GitHub Actions, automation area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) area/storage Issues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor) area/testing Issues or PRs related to testing (e2e, bats, unit tests) debug Debugging in progress size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants