Repository navigation
Restore the sts_k8s_logs data stream with Elasticsearch restore - #131
Conversation
The restore label is set on the workload metadata only, never on pod templates, so waiting on the label matched no pods and ScaleDown returned while the pods were still terminating. Wait on each workload's spec.selector. Applies to every datastore. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Cleanup deleted the data stream's backing indices by name after a rollover, and the restore named only backing indices, so they came back as plain indices without a data stream (#126). - Delete the data stream instead of rolling it over; a 404 means only orphaned backing indices remain, which are deleted as plain indices. - Name the data stream in the restore request when the snapshot has it, and reject before scale-down a snapshot that has its backing indices without it. - List again after cleanup and fail before _restore if STS indices reappeared. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Reviewed at f1c786b.
Verdict: the Elasticsearch changes fix all three #126 cases (checked against a local Elasticsearch 8.19.16), but the scale-down commit 25b8f86 has one blocker.
Blocker B1: a scale-down timeout can leave workloads at 0 replicas for good
- Cause: the pod wait also counts finished pods (
internal/orchestration/scale/scale.go:175). An evicted (Failed) receiver or e2es pod lingers after scale-to-0, so the 120 s wait times out. - Effect: the lock is released while replicas stay at 0 (
scale.go:117). A retry overwritespre-restore-replicaswith "0" (internal/clients/k8s/client.go:279,:302), so scale-up restores 0 replicas without a warning. Before this PR the wait matched no ES, VictoriaMetrics or ClickHouse pods, so this path was unreachable. - Fix: the pod wait needs to ignore finished pods (Succeeded/Failed), while still counting terminating ones. On a wait failure, either keep the lock and print the
--finalize-onlyhint, or don't overwrite an existing annotation when the workload is already at 0.scale_test.go:126says terminal pods "should be ignored", but it passes only because it deletes them.
Suggestions
- S1: the reappearance guard (
cmd/elasticsearch/restore.go:273) rarely catches an active writer;_restore(:166) then fails with a bare name-collision error, or succeeds with the writer's new index orphaned outside the stream. - S2: after the restore, check that
sts_k8s_logsexists and that no.ds-sts_k8s_logs-*index sits outside it (restore.go:166). - S3: only the guard error prints the
--finalize-onlyhint; data-stream delete, index delete and_restorefailures leave workloads scaled down without it. Wrapping the error atrestore.go:144covers all of them. - S4:
indicesPatternis not applied to backing indices once the stream is named: the restore brings all of them back (restore.go:316) and the delete removes all live ones (restore.go:249). The chart pattern selects all of them anyway, so documenting the limit is enough. - S5: test gaps: no scale-down timeout/retry test, nothing asserts that
restoreTargetsruns before scale-down, and the mockRestoreSnapshot(restore_test.go:91) never models the restored stream. - S6: helm-charts-internal
stable/suse-observability/scripts/restore-elasticsearch-snapshot.sh:23still rolls over and still ships; worth mentioning as a follow-up.
The sts-882-nonha acceptance run is still pending.
…s on retry An evicted pod stays in Failed phase after scale-to-0, so the wait counted it and timed out. The lock was then released with the workload still at 0, and a retry overwrote pre-restore-replicas with 0, so scale-up restored 0 replicas. Count only pods that are not Succeeded or Failed, and do not overwrite an existing annotation when the workload is already at 0. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…very failure - After the restore completes, require that sts_k8s_logs exists and that no .ds-sts_k8s_logs-* index sits outside it, before scaling workloads up. - Wrap every error after scale-down, not only the reappearance guard, with the check-and-finalize --finalize-only hint. - Point a failing _restore at workloads not matched by scaleDownLabelSelector. - Validate the snapshot in prepareRestoreTargets so it is tested to run before any scale-down, and let the mock model what _restore brings back. - Document that indicesPattern cannot narrow the data stream's backing indices. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Review addressed in two new commits (the earlier ones are unchanged). B1 (70ef3c4): the pod wait now ignores Succeeded/Failed pods and still counts terminating ones. A scale-down retry no longer overwrites S1–S3, S5 (91d0b91):
S4: documented in the README. S6 (not in this PR): The acceptance run on sts-882-nonha is still pending. |
There was a problem hiding this comment.
Re-reviewed at 91d0b91.
B1: resolved. Finished pods no longer block the wait (internal/orchestration/scale/scale.go:178), and a retry keeps the recorded replicas (internal/clients/k8s/client.go:280, :307). An evicted pod no longer causes a timeout. After a timeout from a pod stuck terminating, a retry and scale-up now restore the original count. The new tests fail on f1c786b.
- S1: fixed, via S2. With a continuous writer on a local Elasticsearch 8.19.16, every run that left logs outside the stream failed the new check, and the collision error now points at unmatched writers (
cmd/elasticsearch/restore.go:179). - S2: fixed (
cmd/elasticsearch/check_and_finalize.go:475). - S3: fixed (
restore.go:140,check_and_finalize.go:467). - S4: fixed (
README.md:349). - S5: fixed.
- S6: deferred to helm-charts-internal; I found no tracking issue there yet.
New, should fix before merge: verification can run over a dead port-forward. verifyAndFinalize uses the original esClient (check_and_finalize.go:431, :443), while polling replaces a broken port-forward because "a broken one never recovers" (:121). If the port-forward drops during a long restore, polling recovers. Verification then fails with a connection error, and the workloads stay scaled down after a successful restore. verify-backup counts that as a failure and retries, which deletes the restored indices. Run the verification through the reconnecting client or a fresh port-forward.
The sts-882-nonha acceptance run is still pending.
The verification used the caller's Elasticsearch client, but polling replaces a port-forward that dropped during a long restore. After a successful restore the verification then failed on a dead connection and left workloads scaled down. Use the reconnecting client and retry transient request failures. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Verification over a dead port-forward fixed in the new commit. The post-restore checks now run through the reconnecting client and retry transient request failures (3 attempts). A missing data stream or orphaned backing indices are still reported straight away. Tests cover the retry and the dropped-client reconnect. S6: no tracking issue in helm-charts-internal yet. I'll leave creating it to the team. |
There was a problem hiding this comment.
Re-reviewed at 8171f9d.
Dead port-forward finding: fixed. Both verification paths go through the reconnecting client (cmd/elasticsearch/check_and_finalize.go:465, :477). Only the two read-only requests are retried (:511), so a missing stream or stray backing indices are reported after one call, and nothing is deleted or scaled during a retry. On a local Elasticsearch 8.19.16, a dead port-forward was dropped after one failure and reconnects were attempted. The run then failed with the hint, and the workloads stayed scaled down. B1 and S1–S5 are unaffected.
Optional:
- When verification fails on a request error, the hint at
:529points to--finalize-only, which skips the check.check-and-finalize --operation-id <snapshot>would run it again. - The new tests cover dropping the client and retrying separately (
check_and_finalize_test.go:545,restore_test.go:660). None runs a retry throughreconnectingHealthClient.
Correction to my earlier reviews: #126's "Done when" list does not require the sts-882-nonha run. It is at most an optional extra step in this PR's validation plan.
|
Acceptance run on sts-882-nonha (ES 8.19.16), CLI built from 8171f9d. Snapshot (a) Ingesting target with a write index outside the snapshot (rolled over first, creating
(b) Target in the #126 bug state
Notes:
|
craffit
left a comment
There was a problem hiding this comment.
The restore can finalize before every backing index in the restored logs data stream is ready.
Naming the sts_k8s_logs data stream restores all of its snapshotted backing indices, and deleting it removes all live ones. With a pattern selecting only some of them, completion tracking and verification would not cover the rest, so the CLI could scale workloads up while an omitted backing index still had unavailable primary shards. Fail before scale-down and require the pattern to select all of them or none. The restore mock now expands a named data stream to all of its snapshotted backing indices, as Elasticsearch does. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fixes #126
elasticsearch restorenow deletes thests_k8s_logsdata stream instead of rolling it over, and names the data stream in the_restorerequest. Orphaned backing indices are still deleted as plain indices._restoreif STS indices reappeared.spec.selector. This applies to every datastore.Validation:
go test ./...and golangci-lint v2.15.0 pass, with regression tests for the three cases in #126. Not yet run against a real Elasticsearch; the acceptance run on sts-882-nonha is still to do.🤖 Generated with Claude Code