Commit Graph

6935 Commits

Author SHA1 Message Date
Feng Ruohang 0fa4a8c503 fix(logger): keep reloaded webhook and audit targets alive after a peer reload
A runtime change to audit_webhook, logger_webhook or audit_kafka is
applied on every peer by serviceReloadDynamic, under a 30-second context
that is cancelled as soon as the handler returns. applyDynamicConfigForSubSys
passed that context to the logger target updates, and the targets tie
their queue worker and, with queue_dir, their disk replay to the Init
context. On every server except the one that served the admin request
the new targets therefore stopped right after they were created: records
filled the in-memory queue and were then dropped with "log buffer full"
until the server restarted.

- Build logger webhook, audit webhook and audit Kafka targets with
  GlobalContext, as startup and the serving node already do. The
  caller's context is still used for logging.
- Open the HTTP disk queue store before starting the queue worker, and
  cancel the derived context when it cannot be opened. A worker started
  before a failed Open dereferenced the nil store on the first record and
  crashed the server; with the process context that would have happened
  on every server.
- Let Cancel hand records still waiting in the channel to the shared
  buffer of the replacement target. A target whose queue store never
  opened has no worker to do this, so repairing queue_dir and applying
  the configuration again used to discard the records it had accepted.
- TestDynamicWebhookOutlivesConfigContext applies each case through
  applyDynamicConfigForSubSys under a short context, cancels it as the
  peer handler does, and requires delivery: audit and logger webhooks
  with a memory queue, a disk queue and an unopenable disk queue
  (recovered by applying the configuration again), and audit Kafka with
  and without queue_dir against a sarama mock broker. Each case runs in
  a child process without logger and audit environment variables.

This completes earlier uncommitted maintainer work on this issue, which
covered the two HTTP call sites, the store-before-worker order and the
first version of the test.

Refs #259

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-05 02:20:06 +08:00
Feng Ruohang dd0a2da55e fix(heal): send the dry-run flag to remote bucket heal
remotePeerS3Client.HealBucket sent only the bucket name and the remove
flag, and HealBucketHandler built its heal options from those two
values. During a dry-run bucket heal every remote node therefore ran a
real one: it created the bucket directory on drives that lacked it, or
removed empty bucket directories when the bucket was missing from
every pool. Only the coordinating node honored DryRun.

Add a "dry-run" key to the peer message and read it into
HealOpts.DryRun on the receiving side, so healBucketLocal returns
before MakeVol and DeleteVol on every node. The message is a string
map: an older node ignores the key, and a missing key reads as false,
so a mixed-version cluster behaves as before until every node is
upgraded.

The regression calls the real client over a test grid connection to
the real handler. It fails on main, and it fails if either side of the
change is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-05 01:21:13 +08:00
Feng Ruohang c8dd5678bb fix(heal): do not purge dangling data during a dry-run heal
healObject handles a metadata read-quorum failure before its dry-run
return, so an admin heal with DryRun set still called deleteIfDangling.
When the drives without the version's xl.meta all answered "not found"
and outnumbered its parity blocks, the dry run deleted the version,
data directory included, from every drive that still held it. A
site-wide dry run reaches .minio.sys/config the same way.

When DryRun is set, return the quorum error with a set-level result
built from the observed read errors, before the purge. Real heals are
unchanged.

The production change is the first cmd/erasure-healing.go hunk of
PR #280, unchanged. The tests are the PR's dry-run tests that do not
depend on its parallel deep verification or its dry-run reporting
change; both stay out of this commit. The tests now assert the delete
counter first and the converted error for each quorum case, and drop
the CheckParts stub that only the excluded tests use.

Co-authored-by: Jasper Bernhardt <jasper.bernhardt@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-05 01:21:13 +08:00
Feng Ruohang 9f7b49369d fix(ilm): require an authoritative cross-pool history before lifecycle expiry
The merged all-pool check from #279 decided on the versions that a read
quorum of each set merged non-strictly. A drive that missed one metadata
update could therefore supply the revision used for the decision, and a
partially unreadable set could drop a committed version from the history.
Both let an expiry delete data the rule did not cover, including a version
under legal hold.

- objectVersions accepts a revision only when max(n/2+1, the version's
  metadata read quorum) drives hold it, identifies revisions by the header
  plus a sha256 over a canonical, length-prefixed encoding of the
  normalized metadata, filters non-accepted revisions before the strict
  merge, and fails closed on omitted versions, too many unreadable drives,
  or cancellation.
- Lock fields are read with the evaluator's key precedence. Cross-pool
  copies that disagree on hold or retention must be strictly ordered by
  valid timestamps; copies with different ModTime are separate writes and
  an older protected write refuses the object. The set safeguard re-checks
  protection and pending purges on its fresh read for checked version
  deletes.
- Duplicate copies with semantically different replication or purge state
  refuse the object.
- Batch expiry announces and audits only completed or already-absent
  removals.

Reviewed adversarially over seven rounds; the final round approved with no
remaining findings in scope. All-versions expiry through deletePrefix and
tiered delete-all dispatch are tracked separately.

Signed-off-by: Feng Ruohang <rh@vonng.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 00:16:38 +08:00
Denis Babchuk ed05d982a1 fix(storage): remove the empty object directory of a failed RenameData
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-11-04 11:39:57 +03:00
Feng Ruohang f321f7f1c7 fix(ilm): do not announce batch expiries the recheck rejected
The expiry worker now asks DeleteObjects to recheck ILM against all
pools. A rejected entry keeps its version and returns
errLifecycleNotApplicable, but the worker still wrote an ILMExpiry
audit record, an ILM trace and an s3:ObjectRemoved:Delete event for it.
Event delivery drops the error element, so consumers saw an ordinary
removal, repeated on every scan while the versions stay split across
pools.

Skip rejected entries; eligible entries of the same batch are still
reported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-04 16:37:42 +08:00
Feng Ruohang 82dd12faf8 fix(restore): keep queued restores waiting for the object lock
The POST handler marks a version ongoing before its background restore
takes the object lock, and only the restore clears that marker. Native
restore holds the lock through the tier download, so a restore of
another version of the same key waits behind it. Both restore entry
points gave up after one delete-operation timeout and returned before
any cleanup, leaving ongoing-request="true" with no owner. Every later
POST for that version was refused with 409 and nothing expired the
marker.

Retry the lock while the restore's context lives, with a dedicated
dynamic timeout so repeated waits do not lengthen delete timeouts.
Shutdown or a caller deadline still ends the wait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-04 16:37:42 +08:00
Feng Ruohang 3ddf83182f Integrate scanner rejection contract regression
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:56:05 +08:00
Feng Ruohang 374b9ce309 Include R1 scanner rejection regression in R4 dependency
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:56:05 +08:00
Feng Ruohang 0c5a309507 test(ilm): assert scanner refusal without claiming absence
Keep the specialized scanner routing test aligned with the explicit lifecycle rejection result, and verify the addressed version and payload remain readable. This distinguishes refused expiry from an idempotent missing version.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:56:05 +08:00
Feng Ruohang f83d02831c Integrate complete R3 encoding and safe-read repairs
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:46:04 +08:00
Feng Ruohang 496eab4b76 fix(restore): preserve safe read context through nested lookups
Carry restore context through POST status reads, metadata copy routing, null-version Object Lock checks and multipart completion. A failed read must preserve the target and must not enqueue its remote object for garbage collection. Cover initial/status POST failures and metadata loss during single and multipart rehydration on real disks.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:46:03 +08:00
Feng Ruohang ea483e453e Integrate R2 restore cleanup boundary repairs
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:45:14 +08:00
Feng Ruohang ce60cc0c84 Integrate R1 adversarial review repairs
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:45:14 +08:00
Feng Ruohang 997846f413 Merge R1 lifecycle safety repair into R4
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:42:42 +08:00
Feng Ruohang 7c9b6386c6 Merge R2 restore safety repair into R3
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:40:08 +08:00
Feng Ruohang ba0b59d0b2 fix(ilm): preserve duplicate metadata and reject unapplied purges
Merge lock and tag revisions for duplicate versions before all-pool
lifecycle evaluation using the existing metadata reconciliation rules.

Distinguish ordinary lifecycle refusal from object absence and clear
rejected batch replication state so a late policy withdrawal cannot
schedule a purge. Preserve restored-copy cleanup and real absence.

Cover single and batch protections, legitimate metadata removals, and
actual replication queue and HTTP target behavior.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:38:21 +08:00
Feng Ruohang d9837fb319 fix(restore): retain legacy part-size compatibility
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:32:55 +08:00
Feng Ruohang 8579466557 fix(restore): preserve versions across cleanup and failed reads
Reject replacement markers and legacy objects before restored-copy cleanup
can mutate their type or data. Prevent restore lookups and failure cleanup
from purging dangling versions, preserve Transition on metadata rereads,
and return without writing when the initial restore read fails.

Add real-disk regressions for stale null tasks, minority metadata, initial
and cleanup read failures, and stored marker/legacy types. Keep ordinary
dangling cleanup and marker purge as positive controls.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:32:33 +08:00
Feng Ruohang 4f72d0ea94 fix(restore): preserve encoded object identity and part layout
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 22:16:47 +08:00
Feng Ruohang 3c4980eb80 Integrate multipart error-case test lint correction
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:40:59 +08:00
Feng Ruohang 50a234d6c3 test(restore): clarify invalid-upload error cases
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:40:59 +08:00
Feng Ruohang a02ce222f0 Integrate complete R3 input-error regression fix
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:39:36 +08:00
Feng Ruohang 8ae19de7a8 fix(restore): avoid duplicate completion locks for empty upload IDs
Keep the storage layer error precedence for missing buckets and uploads while retaining every real upload lock. Cover the alias with short deadlines and race-check the original complete-multipart suite in CI.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:39:36 +08:00
Feng Ruohang 7a4f0b5e69 Integrate native restore test lint correction
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:21:46 +08:00
Feng Ruohang 5ac27f7533 test(restore): follow context-first helper convention
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:21:46 +08:00
Feng Ruohang fa42a09826 fix(restore): rehydrate the selected version under its object lock
Preserve handler version context, resolve the requested version's pool, and
return on the initial read failure without writing metadata. Propagate owned
NoLock to single-part writes, multipart completion and failure cleanup in
the same patch. Preserve the original modification time on cleanup.

Route the restore status copy by version and allow internal multipart
rehydration only for a matching completed transition. Single-pool restores
own the metadata snapshot through download and cleanup. Keep public
completion in object-before-upload order, using the target set's object
lock for single-pool calls, so concurrent completion cannot invert locks.

Cover real signed POSTs, null/UUID and cross-pool identity, download failures,
multipart overwrite guards, Object Lock updates and concurrent completion.
This package depends on the restored-copy cleanup safety delivered in R2.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:20:24 +08:00
Feng Ruohang fcbf2c7d49 Integrate complete native restore repair after R2 cleanup safety
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:20:24 +08:00
Feng Ruohang 18ba0ef32a Merge R4 version-specific read expiry rechecks after R1
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:11:41 +08:00
Feng Ruohang 65c59dd860 fix(ilm): recheck read expiry for the resolved version
Recheck only local ordinary-delete candidates that need an all-pool lifecycle decision. Match UUID/null identity to the version actually read and queue its global metadata and event; retain a successful read on recheck failure, absence, or refusal.

Keep GET reader cleanup, authorization, proxy reads, single-pool reads, restored-copy cleanup, and expiry response headers on their existing paths. Cover signed GET/HEAD, queue contents, metadata faults, missing matches, no-scan boundaries, and reader-lock release.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 21:07:55 +08:00
Feng Ruohang e7103d77cb fix(ilm): constrain restored-copy cleanup to verified tiered versions
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 20:55:22 +08:00
Feng Ruohang 167b95dfd8 Integrate R2 restored-copy cleanup safety with R1
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 20:55:22 +08:00
Feng Ruohang 3a1e132f16 fix(ilm): preserve all-pool approval for tiered batch expiry
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 20:40:04 +08:00
Feng Ruohang 30588eb830 Merge PR #282 restore-copy version targeting for R2
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 20:37:15 +08:00
Feng Ruohang 393a84076f Merge commit '8c1473a618f89fda3b89462c69c2a3c1a320d4c6' into codex/silo-lifecycle-r1-r4
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-03 20:36:07 +08:00
Denis Babchuk a21f420de3 fix(sts): keep "not found" in the LDAP auth failure so the console can log in root
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-11-03 08:52:08 +08:00
Denis Babchuk dcad2ae3e7 fix(iam): decide unstorable IAM record names before asking the drives
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-11-03 08:38:24 +08:00
Denis Babchuk 525ab5fa40 fix(pools): do not panic when a rebalance stop finds no rebalance metadata
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-11-03 08:23:59 +08:00
Denis Babchuk 001078e9ca fix(ilm): expire a restored copy by the version it belongs to
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-11-02 21:41:37 +03:00
Denis Babchuk 8c1473a618 fix(pools): move versions whose ILM expiry does not hold with the versions in other pools
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-11-02 19:59:13 +03:00
Denis Babchuk 347d9763fd fix(ilm): recheck expiries decided in one pool against the versions of the object in all pools
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-11-02 19:58:46 +03:00
Feng Ruohang a47bacbc0f test: satisfy lint for lifecycle migration follow-up
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-02 14:37:04 +08:00
Feng Ruohang 0a546c7a76 fix(pools): preserve ILM cleanup during migration
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-02 14:20:17 +08:00
Feng Ruohang 4cc3bc1de6 Merge remote-tracking branch 'origin/main' into HEAD
Signed-off-by: Feng Ruohang <rh@vonng.com>

# Conflicts:
#	cmd/erasure-server-pool-decom.go
2026-11-02 12:29:08 +08:00
Feng Ruohang 0cfca29cb2 Merge pull request #264 from botdeniska/fix/free-versions-not-versions
fix(ilm): stop taking the free versions of deleted tiered versions for versions
2026-11-01 14:44:22 +08:00
Feng Ruohang a7310d59fe Fix cross-parity version listing after pool removal (#267)
Availability-optimized writes can leave a readable null version across separate EC groups when a disk is unavailable. Recount ordinary null versions for all non-strict reads and cover version listing and complete pool removal with end-to-end tests.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-11-01 14:08:09 +08:00
Denis Babchuk a995921e57 fix(pools): move ILM-expired current versions during rebalance and remove moved copies
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-10-29 22:43:26 +03:00
Denis Babchuk 19910230aa fix(pools): move ILM-expired current versions during decommission
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-10-29 22:42:17 +03:00
Denis Babchuk 7ce7fc8d1e fix(pools): do not list or move free versions as delete markers
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-10-29 22:32:44 +03:00
Denis Babchuk fb1a619ee1 fix(listing): skip free versions when looking for a latest delete marker
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
2026-10-29 22:08:34 +03:00