Skip to content

feat(wpcli): add controlled log truncation - #429

Merged
tinswzy merged 1 commit into
zilliztech:masterfrom
tinswzy:feat/wp-cli-log-truncate-428
Oct 14, 2026
Merged

tinswzy merged 1 commit into
zilliztech:masterfrom
tinswzy:feat/wp-cli-log-truncate-428

Conversation

@tinswzy

@tinswzy tinswzy commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

Operators can inspect and repair metadata with wp meta, but truncation fields are protected and there is no dedicated CLI retention workflow. Add wp log truncate <logName> --segment N --entry M to preview and explicitly apply a verified truncation-frontier advancement.

  • Default to a no-write JSON/YAML preview showing before/after records, the log revision, target segment revision and cleanup effect. Apply requires --expected-revision, --reason and a new --backup; an unchanged frontier makes no writes or artifacts.
  • Reuse the SDK's log-metadata transition with stricter operator validation: require a non-empty Completed/Sealed target, canonical key/SegNo identity, valid entry bounds and monotonic advancement. Reject invalid selectors and missing apply guards before connecting.
  • Read the log and target segment at one etcd snapshot; persist their readable, byte-preserving backup before committing. Compare both source revisions, preserve unrelated/unknown log fields and its lease, and atomically write the frontier plus an audit record. A concurrent update aborts without a partial frontier/audit write.
  • Use the merged etcd/context resolver. Complete etcd settings require no admin endpoint, node mapping or writer takeover. Like normal SDK truncation, a writer lock is allowed; the operator must verify the application's checkpoint and retention requirements.
  • Explain that the CLI does not change segment states or remove payloads: subsequent auditor rounds handle earlier finalized segments under retention/reader protection, while the frontier segment remains retained. Add command parameters, preview/apply output and failure/retry examples. The consolidated HTML handbook update remains a separate follow-up.

Validation:

  • go build -o /tmp/woodpecker-428-wp ./cmd/wpcli
  • go test -race -short -count=1 -timeout=5m ./cmd/wpcli/... (passed; command package 88.398s)
  • Truncate regression tests passed after the final backup-error classification change; CLI golangci-lint reports zero issues.
  • Embedded-etcd tests exercise actual commands, JSON/YAML, context-only connections with an unreachable admin endpoint, preview/no-op/stale revision behavior, rejected states/identities/bounds, missing/corrupt records, backup failures, metadata/lease preservation and audit atomicity. Deterministic concurrent log/segment updates between backup and conditional commit verify real etcd CAS behavior.
  • Checked documentation example flags against the built CLI help and git diff --check.

Closes #428

@github-actions

Copy link
Copy Markdown

CI commands

Comment any of these to rerun checks on this pull request:

Command Reruns
/rerun every failed workflow on the latest commit
/rerun-lint Lint
/rerun-mod-tidy Go Mod Tidy Check
/rerun-unit-test Unit Test
/rerun-e2e-local E2E Local
/rerun-e2e-objectstorage E2E Object Storage
/rerun-e2e-service E2E Service
/rerun-component-test Component Integration Test
/rerun-chaos Chaos Test
/rerun-service-stability-process Service Stability (Process)
/rerun-service-stability-docker Service Stability (Docker)
/rerun-operator Operator Test
/rerun-upgrade-local Upgrade Compat Local
/rerun-upgrade-objectstorage Upgrade Compat Object Storage
/rerun-upgrade-service Upgrade Compat Service

The ci-passed label is applied automatically once every required check passes.

@codecov

codecov Bot commented Oct 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.79245% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.26%. Comparing base (ccae846) to head (669f38d).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
cmd/wpcli/cmd/log_truncate.go 86.66% 7 Missing and 7 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #429      +/-   ##
==========================================
+ Coverage   84.23%   84.26%   +0.02%     
==========================================
  Files         219      220       +1     
  Lines       31147    31253     +106     
==========================================
+ Hits        26237    26335      +98     
- Misses       3672     3677       +5     
- Partials     1238     1241       +3     
Components Coverage Δ
Server 83.65% <ø> (-0.03%) ⬇️
Client 90.83% <ø> (-0.04%) ⬇️
Meta 85.58% <ø> (+0.27%) ⬆️
Common 88.33% <ø> (+0.10%) ⬆️
Files with missing lines Coverage Δ
cmd/wpcli/cmd/log_readers.go 85.00% <100.00%> (+0.15%) ⬆️
cmd/wpcli/cmd/log_truncate.go 86.66% <86.66%> (ø)

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@czs007

czs007 commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

Must-fix issues introduced by this PR: 0
Merge recommendation: Mergeable as-is — this review found no must-fix issue introduced by this PR.

Adversarial review found no issues requiring changes.

Verified:

  • cmd/wpcli/cmd/log_truncate.go:109 / :185 — the read is a single transaction with two OpGets (consistent snapshot), and the commit compares ModRevision of both the log and segment keys plus Version(auditKey)==0 against that same snapshot, so there is no TOCTOU window; tx.Succeeded==false maps to StateConflict, and the concurrent-update test confirms neither metadata nor audit is written on conflict.
  • cmd/wpcli/cmd/log_truncate.go:137-143 — target validation is stricter than the SDK path (woodpecker/log/log_handle.go:959): non-Completed/Sealed segments and empty segments (LastEntryId<0) are rejected, and the opt.entry > seg.LastEntryId bound is checked against the target segment, matching SDK semantics.
  • cmd/wpcli/cmd/log_truncate.go:146-149 — frontier legality (<-1, (-1 && !=-1)) and monotonic-advance checks handle the unset (-1,-1) frontier correctly without misreporting a regression; covered by the unset_frontier test.
  • cmd/wpcli/cmd/log_truncate.go:108 with meta/constant.go:114 and meta.go:151-159 — segment key construction matches the canonical prefix / suffix==FormatInt / id==SegNo triple check; identity_mismatch test covers it, and validateMetaTarget (meta.go:101-105) rejects empty names or names containing / before any connection is opened.
  • cmd/wpcli/cmd/log_truncate.go:173 → :185 with meta.go:326-352 — the backup is written with O_EXCL plus file and directory fsync before the commit; an existing backup or missing directory returns ConfigError and leaves etcd and the audit log untouched.
  • cmd/wpcli/cmd/log_truncate.go:182-184 — WithLease is applied only when kv.Lease!=0, and pb.Clone preserves unknown fields; tests at :294 and :301 assert lease and unknown fields survive the rewrite.

Pre-existing hazards — not introduced by this PR (follow-up only)

The following hazards are real but pre-existing and were not introduced by this PR. They should be tracked as separate follow-up work and do not block this PR.

  • woodpecker/log/log_handle.go:1024 — After a CLI truncate, the SDK-side truncation frontier gauge is not refreshed, and for segment 0 it is never published. The CLI writes LogMeta directly via an etcd transaction (cmd/wpcli/cmd/log_truncate.go:150) and therefore never reaches metrics.SetTruncationFrontier at log_handle.go:1002; the writer process only catches up via the auditor's call to CheckAndSetSegmentTruncatedIfNeed at :1029, and read-only client processes never do. For --segment 0 (accepted by the CLI at log_truncate.go:25), the TruncatedSegmentId <= 0 early return at :1024 prevents :1029 from ever running. An operator runs wp log truncate <log> --segment 0 --entry N --apply on a never-truncated log and the writer's auditor then calls CheckAndSetSegmentTruncatedIfNeed → the early return at :1024 fires, SetTruncationFrontier at :1029 is skipped, and the wp_client_truncation_frontier_{segment,entry} gauges for that log are absent or stale, so monitoring does not show the frontier at (0,N); metrics only, metadata and data cleanup are unaffected. This is unrelated to this PR because the PR touches only cmd/wpcli/{README.md,cmd/log_readers.go,cmd/log_truncate.go,cmd/log_truncate_test.go} and docs/wp-log-truncate-cli.md, leaving log_handle.go:1024/1029 and common/metrics/client_metrics.go:425 unchanged, and the SDK's own Truncate already behaves identically for any other process (gauge refreshed only in the caller, other processes depend on the auditor, segment 0 blocked by the same early return), so the CLI behaves exactly like another client process calling Truncate. Suggested follow-up in the SDK: publish the frontier for any non-negative value before the segment-zero early return at :1024. No tracking issue yet. (raised by sijie-ni-0214)

@tinswzy

tinswzy commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator Author

/rerun-service-stability-process

@github-actions

Copy link
Copy Markdown

Rerunning service-stability-process workflow. Check the Actions tab for progress.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

enhance(wpcli): add controlled log truncation with preview, backup and audit

2 participants