Repository navigation
fix(monitoring): surface missing VictoriaLogs and gate dead-end vlinsert ExternalName - #3215
Conversation
Summary of ChangesHello, 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 addresses silent log ingestion failures by implementing stricter readiness checks and conditional resource creation. By gating the monitoring-system HelmRelease on the actual health of the VictoriaLogs cluster and ensuring that log-forwarding services are only created when a valid destination exists, the platform now provides clear feedback on misconfigurations instead of silently dropping data. Highlights
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. Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
Code Review
This pull request addresses issue #3181 by ensuring that the cozy-monitoring ExternalName redirects are only created when the root tenant actually hosts the platform monitoring stack. It also adds a readiness gate to the monitoring HelmRelease based on the VLCluster status and fails rendering if logsStorages is empty. The feedback highlights two potential nil pointer dereferences in the Helm templates: one when .Values.monitoring is omitted or null in apps.yaml, and another when .Values._cluster is undefined in monitoring-external-services.yaml.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| and would flip an explicit rootEnabled=false back to true. The | ||
| chart values.yaml supplies the true default, so quote the value | ||
| as-is. */}} | ||
| monitoring-enabled: {{ .Values.monitoring.rootEnabled | quote }} |
There was a problem hiding this comment.
If .Values.monitoring is omitted or overridden to null in custom values, accessing .Values.monitoring.rootEnabled directly will cause a template rendering panic (nil pointer dereference). Guard against this by checking if .Values.monitoring is defined before accessing its fields.
monitoring-enabled: {{ if .Values.monitoring }}{{ .Values.monitoring.rootEnabled | quote }}{{ else }}true{{ end }}References
- Review carefully for logic errors, off-by-one bugs, and nil dereferences. (link)
| {{- if $rootTenant -}} | ||
| {{- $enabled = toString (dig "spec" "monitoring" false $rootTenant) -}} | ||
| {{- else -}} | ||
| {{- $enabled = toString (index .Values._cluster "monitoring-enabled" | default "true") -}} |
There was a problem hiding this comment.
If .Values._cluster is nil or not defined (which can happen if the cozystack-values Secret is missing or during certain test/dry-run scenarios), calling index on it will cause a template rendering panic (index of untyped nil). Guard against this by defaulting .Values._cluster to an empty dictionary (dict) before indexing.
{{- $enabled = toString (index (.Values._cluster | default dict) "monitoring-enabled" | default "true") -}}References
- Review carefully for logic errors, off-by-one bugs, and nil dereferences. (link)
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (10)
🚧 Files skipped from review as they are similar to previous changes (8)
📝 WalkthroughWalkthroughAdds a root-monitoring toggle into platform values and Secret wiring, gates redirect Services on that flag, adds HelmRelease readiness checks for VLCluster status, and fails rendering when ChangesMonitoring root-enabled propagation and readiness
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related issues
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ea2cf15 to
d301a57
Compare
VerdictLGTM with non-blocking notes The three-layer fix for the silent-log-loss path (#3181) is coherent, idiomatic (mirrors the seaweedfs CNPG readiness-gate precedent), and verified safe on both upgrade and fresh install; the only issue is one inaccurate code comment. Findings[MINOR] The comment reads "VLCluster has no status.conditions; it exposes status.updateStatus". The vendored CRD ( Caveats
|
d301a57 to
5a7fc41
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@packages/system/cozystack-basics/templates/monitoring-external-services.yaml`:
- Line 31: The monitoring template logic currently uses default on
_cluster.monitoring-enabled, which converts an explicit false into "true" and
enables fallback Services unintentionally. Update the value resolution in
monitoring-external-services.yaml to explicitly check whether the key exists in
.Values._cluster before falling back, and only use "true" when the key is
missing; keep the existing $enabled handling and the surrounding template flow
intact.
🪄 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: e0052780-0250-4a34-9400-570a18e6d319
📒 Files selected for processing (10)
packages/core/platform/templates/apps.yamlpackages/core/platform/tests/apps_monitoring_enabled_wiring_test.yamlpackages/core/platform/values.yamlpackages/extra/monitoring/Makefilepackages/extra/monitoring/templates/helmrelease.yamlpackages/extra/monitoring/tests/helmrelease_test.yamlpackages/system/cozystack-basics/templates/monitoring-external-services.yamlpackages/system/cozystack-basics/tests/monitoring-external-services_test.yamlpackages/system/monitoring/templates/vlogs/vlogs.yamlpackages/system/monitoring/tests/vlogs_logsstorages_required_test.yaml
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/extra/monitoring/tests/helmrelease_test.yaml
- packages/system/monitoring/tests/vlogs_logsstorages_required_test.yaml
- packages/core/platform/tests/apps_monitoring_enabled_wiring_test.yaml
- packages/extra/monitoring/Makefile
- packages/extra/monitoring/templates/helmrelease.yaml
- packages/core/platform/values.yaml
- packages/system/cozystack-basics/tests/monitoring-external-services_test.yaml
- packages/core/platform/templates/apps.yaml
IvanHunters
left a comment
There was a problem hiding this comment.
Verdict
NOT LGTM
The empty-logsStorages fail and the readiness gate are sound, but the third layer (lookup-gated ExternalName render on an engine-generated HelmRelease) rests on an incorrect assumption about helm-controller re-render behaviour and creates a stale-state hole in both directions.
Findings
[MAJOR] packages/system/cozystack-basics/templates/monitoring-external-services.yaml:26-33 — lookup-gated render will go stale; the "cannot drift" claim is false
The template gates the three vlinsert/vminsert ExternalName Services on lookup of Tenant/root spec.monitoring, and the comment (line 15-16) plus the commit body assert that "the ExternalNames and the tenant's actual monitoring can never drift." That is not how helm-controller works. helm-controller re-renders a chart only on install/upgrade/rollback (chart-source change or HR values change) — never on a reconcile tick, and never when a lookup result changes. cozystack-basics is an operator-generated HelmRelease; your own in-tree note at packages/core/platform/sources/cozystack-basics.yaml:32-36 spells this out ("Drift detection is off on operator-generated HelmReleases, so a capability gate in the templates would render the policy out at first install and never add it back").
Tenant/root spec.monitoring is a runtime bool on the Tenant CR (packages/apps/tenant/values.yaml:12), toggled out-of-band and independent of the platform monitoring.rootEnabled value. So the two divergence scenarios are:
- Root monitoring ON → later turned OFF via
Tenant/root spec.monitoring: no re-render is triggered, the three ExternalNames stay, and the exact dead-end redirect / silent log-drop this PR set out to eliminate persists until an unrelated chart bump forces a re-render. - Root monitoring OFF at install → later turned ON via
Tenant/root spec.monitoring: the redirects were never created and are never added back, so ingestion into a now-valid VictoriaLogs never routes — the fix silently fails to activate.
The only reliable re-render trigger is a change to the HR's valuesFrom cozystack-values Secret, i.e. flipping monitoring.rootEnabled in platform values (that mutates the Secret, which helm-controller watches). Toggling the Tenant CR alone does nothing. Either (a) make monitoring.rootEnabled the single source of truth and drop the lookup branch entirely (the lookup adds the drift risk without a reliable refresh path), or (b) keep the lookup but document, in the template comment and PR body, that the redirects only refresh when monitoring.rootEnabled is changed, and ship an operator recipe for forcing the refresh after a Tenant/root spec.monitoring toggle. As written, the code comment and commit message make a correctness claim that is false and will mislead the next maintainer.
Claim mismatches
[PARTIAL] "reads the live Tenant/root spec.monitoring via lookup (source of truth, so it cannot drift from the tenant's real state)" — the lookup is only re-evaluated on a Helm action, not on Tenant CR change; on an engine-generated HR with drift detection off, the rendered ExternalNames drift from Tenant/root spec.monitoring in both directions (see Findings). The claim is true only at the instant of an install/upgrade/values-change, not continuously.
[PARTIAL] "Covered by helm-unittest across all four affected charts (141 tests)" — the four suites run and pass (verified: 51 + 7 + 3 + 82 = 143 tests total, including pre-existing), but the new tests exercise only the fallback branch; the comment at monitoring-external-services_test.yaml:19-21 correctly notes the lookup branch is unit-untested. The drift behaviour in Findings is therefore not covered by any test. Not blocking on its own, but it means the failure mode ships unverified.
Operational risks
- Stale-lookup on
Tenant/root spec.monitoringtoggle (monitoring-external-services.yaml:26-33): an operator who disables/enables root monitoring the documented way (editing the Tenant CR, the PR's stated "source of truth") gets no redirect update and no failing signal — a silent regression of the very behaviour #3181 tracks. At 3am this surfaces as "logs stopped / never started" with aReadymonitoring release and correct-looking Tenant spec, with nothing in Flux events pointing at the stale ExternalName set.
Caveats
Phase 5b — existing-customer upgrade:
packages/system/monitoring/templates/vlogs/vlogs.yaml:8-10— the newfailon emptylogsStoragesis a deliberate behaviour change.logsStoragesis user-facing (exposed inpackages/system/monitoring-rd/cozyrds/monitoring.yamlopenAPISchema, default onegenericentry, nominItems). A customer running today withlogsStorages: [](currently a silent-drop config) will, on upgrade, have themonitoring-systemHR fail to render and loop onretries: -1. That is the intended "loud" outcome, but it is a hard upgrade break for that config — acceptable given the rationale, noted so it is not a surprise.packages/core/platform/values.yaml:80-92— newmonitoring.rootEnabled: truedefault preserves the historical always-create behaviour for the fallback branch, so existing clusters whosecozystack-valuesSecret predates the key are unaffected (dig ... default trueandindex ... | default "true"both resolve to the create-redirects path). Verified via the three wiring tests and by readingapps.yaml:20.- No migration script needed: no resource rename/move/adoption, no CRD change, no RBAC contraction.
packages/core/platformhas novalues.schema.json/README.md, so nomake generateartifact is owed for the values.yaml addition (verified: files absent).
Phase 5b — fresh install:
waitStrategy/healthCheckExprsonpackages/extra/monitoring/templates/helmrelease.yaml:26-48are supported: the identical shape is already in production atpackages/extra/seaweedfs/templates/seaweedfs-db.yaml:24-35(same helm-controller). The<release>-systemHR targetschartRef: ExternalArtifact(a real Flux HR), so it can carry these fields — distinct from the legacycozystack.monitoringsource. The PR's "Known limitation" is accurate:cozystack.monitoringis referenced by no active bundle (onlycozystack.monitoring-applicationandcozystack.monitoring-agentsappear inpackages/core/platform/templates/bundles/system.yaml:195,208).- CEL initial-empty-status is safe: on a freshly-applied VLCluster with no
status.updateStatus, all ofcurrent/inProgress/failedare false, so helm-controller holds the release not-Ready and polls untiltimeout: 10m— the intended gate behaviour, not a spurious failure.
Recommended follow-ups
- Add
minItems: 1to thelogsStoragesschema inpackages/system/monitoringvalues.schema.json / cozyvalues-gen source so the dashboard/API rejects an empty list up front, instead of the operator discovering it only as a stuck HR at render time. This complements thefailguard rather than replacing it.
5a7fc41 to
a3d688c
Compare
IvanHunters
left a comment
There was a problem hiding this comment.
Verdict
LGTM with non-blocking notes
The prior drift hole is resolved — the vlinsert/vminsert ExternalName gate no longer uses lookup; it now reads _cluster.monitoring-enabled (fed from the new monitoring.rootEnabled platform value), which lands in the cozystack-values Secret that cozystack-basics consumes via valuesFrom, so flipping it re-renders the chart. Remaining items are a stale PR-body description and two edge-case UX notes, none blocking.
Findings
[MINOR] packages/system/monitoring/templates/vlogs/vlogs.yaml:8-10 — empty-logsStorages hard-fail is reachable by user input with no schema guard
logsStorages is a user-settable array in the monitoring ApplicationDefinition openAPISchema (packages/system/monitoring-rd/cozyrds/monitoring.yaml:11) and carries no minItems constraint, so the dashboard/API accepts an explicit logsStorages: []. With this PR that configuration now hard-fails the HelmRelease render (helm fail) instead of rendering nothing. For an existing monitoring app CR that was deliberately set to an empty list, an upgrade flips it from "silently renders no VLCluster" to "HR stuck in render failure". The loud-fail is the intended behaviour and the default ([{generic...}]) is non-empty, so this is not a regression for standard installs — but the failure would be more legible if minItems: 1 were added to the logsStorages schema in the RD so the API rejects the empty list up front with a validation message, rather than surfacing as an HR reconcile failure. Consider adding minItems: 1 (regenerated via make generate) as a follow-up.
Claim mismatches
[PARTIAL] "The template reads the live Tenant/root spec.monitoring via lookup (source of truth, so it cannot drift from the tenant's real state)" (PR body, layer 3) — the shipped code does NOT use lookup. packages/system/cozystack-basics/templates/monitoring-external-services.yaml:26 gates on index (.Values._cluster | default dict) "monitoring-enabled", and the in-file comment (lines 13-20) explicitly explains why lookup was rejected (operator-generated HR, drift detection off, re-renders only on install/upgrade/values-change). The PR body still describes the earlier lookup-based revision and repeats the "cannot drift" framing, which is now inaccurate — the value can go stale if an operator changes Tenant/root spec.monitoring out-of-band without updating monitoring.rootEnabled. The CodeRabbit summary and the git commit body correctly describe the value-driven approach; only the top "What this PR does" section is stale. Update the PR body layer-3 text to match the shipped mechanism before merge so reviewers and operators do not carry a false mental model.
Caveats
- Upgrade impact (existing customer): verified no migration is needed and no breakage for the default path. Clusters on N-1 carry a
cozystack-valuesSecret without themonitoring-enabledkey; the template's| default "true"(line 26) keeps all three ExternalName redirects, and oncepackages/core/platformre-renders the Secret the key is emitted as"true"by default (apps.yaml:140,dig "rootEnabled" trueverified: default→"true", explicitfalse→"false", null→"true", no panic). So existing behaviour is preserved unless an operator explicitly setsrootEnabled: false.repo_invariantsandcozy_invariantsboth empty; no numbered migration required. - Fresh install: verified safe.
system/monitoringdefaultlogsStoragesis non-empty (packages/system/monitoring/values.yaml:43,generic), so the new render-fail does not fire on cold install. ThewaitStrategy: poller+healthCheckExprsshape is an established precedent (packages/extra/seaweedfs/templates/seaweedfs-db.yaml:24-35, identical structure), confirming the in-use helm-controller supports theseHelmReleasev2 fields.packages/core/platformhas novalues.schema.json/cozyvalues-gentarget, so themonitoring.rootEnabledaddition needs nomake generateartifacts. - CI wiring: verified the added
test:target inpackages/extra/monitoring/Makefiledoes wire the suite into CI —hack/helm-unit-tests.shiterates chart dirs and runsmake -C <dir> testonly where the target exists (make -C "$dir" -n testguard), so a chart with notest:target was silently skipped before. All four charts' suites pass locally (143 tests: 51 + 7 + 3 + 82). - The functional correctness of the CEL
healthCheckExprs(operational/expanding/catch-all-failedmapping onstatus.updateStatus) is not exercised by helm-unittest (the tests only pin the string values); it can only be validated live against victoria-metrics-operator. The mapping is defensible on paper (unknown status can never read as Ready), but end-to-end confirmation on a dev cluster is recommended before relying on it as the log-store backstop. - The residual out-of-band drift (operator toggles
Tenant/root spec.monitoringwithout updatingmonitoring.rootEnabled) is an accepted, documented tradeoff — surfaced in both the template comment (lines 13-20) andvalues.yaml(packages/core/platform/values.yaml:88-95, "operators MUST set it to match their actual Tenant/root spec.monitoring"). This is the correct honest framing; the only gap is the stale PR-body text noted under Claim mismatches.
…ert ExternalName (#3181) Platform log ingestion could fail silently: fluent-bit shipped to vlinsert-generic while the monitoring HelmRelease reported Ready, and a vlinsert-generic ExternalName in cozy-monitoring dead-ended at a tenant-root VictoriaLogs that did not exist when the root tenant had monitoring disabled. Logs were dropped with no failing signal. Three complementary changes: - Readiness (do not stay silently Ready): the monitoring-system HelmRelease now uses a `poller` waitStrategy and a healthCheckExpr on its VLCluster (status.updateStatus), so a missing/unhealthy log store makes the release not-ready instead of flipping Ready as soon as the CR is applied. Mirrors the seaweedfs CNPG pattern. - No empty-log-store hole: system/monitoring rejects an empty logsStorages at render time (helm fail). With no entry no VLCluster is created, the readiness gate has nothing to match, and fluent-bit would silently drop logs — so this is made a loud misconfiguration rather than a documented footgun. - No silent fallback: the cozy-monitoring -> tenant-root vlinsert/vminsert ExternalName redirects in cozystack-basics are now created only when the root tenant hosts monitoring, gated on _cluster.monitoring-enabled — fed from a new platform value monitoring.rootEnabled (default true, preserving the historical always-create behaviour). monitoring.rootEnabled is the single render-time source of truth: changing it re-renders cozystack-basics (helm-controller watches the cozystack-values Secret it flows into). A live `lookup` of Tenant/root spec.monitoring is deliberately NOT used: cozystack-basics is an operator-generated HelmRelease with drift detection off, so it re-renders only on install/upgrade/values-change — never on a reconcile tick or when a lookup result changes — and a lookup would go stale in both directions. Operators must keep monitoring.rootEnabled in sync with Tenant/root spec.monitoring. Covered by helm-unittest across all four charts: readiness gate fields, empty-vs-populated logsStorages contract, ExternalName present/absent and null-guard contract, and the platform wiring into the cozystack-values Secret. The CEL health predicates are exercised live, not in helm-unittest (which cannot evaluate CEL). Adds the missing `test:` target to packages/extra/monitoring/Makefile so its suite runs in CI. Known limitation (follow-up): the legacy cozystack.monitoring PackageSource that installs system/monitoring directly into cozy-monitoring cannot carry the readiness gate, because the engine's ComponentInstall/HelmRelease builder and the vendored helm-controller API v1.4.3 lack waitStrategy/healthCheckExprs. That source is not referenced by any active bundle; full coverage needs a helm-controller bump plus engine support. Signed-off-by: Alexey Artamonov <[email protected]>
a3d688c to
f9afc73
Compare
What this PR does
Addresses #3181, where platform log ingestion could fail silently: fluent-bit shipped to
vlinsert-genericwhile the monitoringHelmReleasereportedReady, and avlinsert-genericExternalNameincozy-monitoringdead-ended at atenant-rootVictoriaLogs that did not exist when the root tenant had monitoring disabled. Logs were dropped with no failing signal.Three complementary layers make the failure loud instead of silent:
packages/extra/monitoring/templates/helmrelease.yamlnow sets apollerwaitStrategyand ahealthCheckExprsentry on theVLClusterstatus.updateStatus. A missing/unhealthy log store makes themonitoring-systemrelease not-ready instead of flippingReadythe moment the CR is applied. Mirrors the existing seaweedfs CNPG pattern.packages/system/monitoring/templates/vlogs/vlogs.yamlfails the render on an emptylogsStorages. With no entry noVLClusterexists, the readiness gate has nothing to match, and fluent-bit would silently drop logs — so this is now a loud misconfiguration.cozy-monitoring → tenant-rootvlinsert/vminsertExternalNameredirects incozystack-basicsare created only when the root tenant hosts monitoring. The template reads the liveTenant/rootspec.monitoringvialookup(source of truth, so it cannot drift from the tenant's real state) and falls back to a new platform valuemonitoring.rootEnabled(via_cluster.monitoring-enabled) whenlookupis empty (dry-run / first render). The default preserves the historical always-create behaviour.Covered by helm-unittest across all four affected charts (141 tests): readiness-gate fields, empty-vs-populated
logsStoragescontract,ExternalNamepresent/absent fallback contract, and the platform wiring into thecozystack-valuesSecret. Also adds the missingtest:target topackages/extra/monitoring/Makefileso its suite runs in CI.Known limitation / follow-up: the legacy platform monitoring release installed directly into
cozy-monitoringvia thecozystack.monitoringPackageSource cannot carry the readiness gate, because the engine'sComponentInstall/HelmRelease builder and the vendoredhelm-controllerAPI v1.4.3 lackwaitStrategy/healthCheckExprs. That source is not referenced by any active bundle; full coverage there needs a helm-controller bump plus engine support.Release note
Summary by CodeRabbit
monitoring.rootEnabled) to control whether root-level monitoring is enabled.monitoring.rootEnabled=falseis preserved when generating platform configuration.logsStoragesis empty.logsStoragesrequirements.make testtarget to run chart unittests.