Skip to content

fix(replication): show stored delete flag and zero limits in rule editor - #283

Open
reatang wants to merge 1 commit into
mainfrom
fix/replication-rule-editor-state
Open

reatang wants to merge 1 commit into
mainfrom
fix/replication-rule-editor-state

Conversation

@reatang

@reatang reatang commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Pull Request

Description

The bucket replication rule editor misreported two stored values:

  • "Replicate Delete" showed off although GetBucketReplication returns <DeleteReplication><Status>Enabled</Status></DeleteReplication>. The console reads the configuration through @aws-sdk/client-s3, whose schema-driven deserializer drops the MinIO/RustFS <DeleteReplication> extension, so parsed rules never carried the field. The console only patched the element into PutBucketReplication bodies (contexts/s3-context.tsx), never on the read side. As a consequence every save that re-PUTs the fetched rules also silently rewrote delete replication as Disabled.
  • Health check showed 60 s and bandwidth 100 GiB/s for a remote target stored with 0/0. list-remote-targets encodes targets with madmin's JSON tags: the limit is bandwidthlimit (the form read bandwidth_limit, so every target showed the default regardless of the stored value) and healthCheckDuration is a Go time.Duration in nanoseconds. The form also folded a stored 0 into the defaults with || 60 and !bytes.

Changes:

  • lib/bucket-replication-delete.ts: moves the existing PUT-side patch out of contexts/s3-context.tsx and adds the GET side. A middleware below the SDK deserializer buffers the GetBucketReplication XML and hands it (keyed by request) to a middleware above the deserializer, which merges each rule's DeleteReplication status into the parsed output. The hand-over is needed because the S3 client's own throw200ExceptionsMiddleware sits between the two and re-wraps the body as a fresh stream.
  • lib/bucket-replication-target.ts: reads bandwidthlimit (falling back to the legacy bandwidth_limit), converts healthCheckDuration from nanoseconds using the same threshold the server uses for seconds-or-nanos input, and keeps a stored 0 distinct from an unreported field.
  • components/replication/edit-form.tsx: initialises the form and the bandwidth change detection through those helpers, accepts a 0 interval in validation and the input's min so a target stored with 0 stays saveable, and sends the displayed interval instead of coercing 0 back to 60.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Test improvements
  • Security fix

Testing

  • Unit tests added/updated
  • Manual testing completed
pnpm type-check
pnpm lint
pnpm format:check
pnpm test:run

All four pass (864 tests). New suites: tests/lib/bucket-replication-delete.test.ts (XML status extraction, merge, PUT injection, and the GET middleware pair run around a fake deserializer that re-wraps the body like the SDK does) and tests/lib/bucket-replication-target.test.ts (nanosecond and legacy second intervals, both bandwidth keys, 0 versus unreported).

Manual: two local single-disk RustFS instances (source with RUSTFS_REPLICATION_ALLOW_LOOPBACK_TARGET=true), a remote target created through set-remote-target with healthCheckDuration: 0 and bandwidth: 0, and a rule PUT with DeleteReplication, DeleteMarkerReplication and ExistingObjectReplication all Enabled. list-remote-targets returned "bandwidthlimit":0,"healthCheckDuration":0. The GET middleware was also exercised with the real SDK from Node against that server. Saving the rule unchanged from the editor returns "Update Success" and the server still reports DeleteReplication Enabled and the target 0/0.

Checklist

  • Code follows the project's style guidelines
  • Self-review completed
  • TypeScript types are properly defined
  • All commit messages are in English (Conventional Commits)
  • All existing tests pass
  • No new dependencies added, or they are justified

Related Issues

Fixes rustfs/rustfs#9068 (the Console part). The server side of that issue, the missing s3:ForceDeleteObject permission for the site replicator, is handled by rustfs/rustfs#9069; this PR only fixes what the editor displays and writes back.

Screenshots (if applicable)

No screenshots. Values of the edit dialog for the same rule and target, read from the DOM in the dev console:

Field Before After
Replicate Delete switch off on
Health Check Interval (seconds) 60 0
Bandwidth Limit 100 GiB/s 0 GiB/s

Additional Notes

set-remote-target?update=true rejects the healthcheck update op on current servers, so the health check interval shown in the edit dialog is display-only on update until the server supports that op; this PR does not change which ops are sent. The dialog still shows the stored interval rather than a default.

The bucket replication rule editor showed "Replicate Delete" off for rules
the server reports as Enabled, and showed the default 60 s health check and
100 GiB/s bandwidth for a remote target stored with 0/0.

GetBucketReplication goes through @aws-sdk/client-s3, whose schema-driven
deserializer drops the MinIO/RustFS <DeleteReplication> extension, so the
parsed rules never carried it; the console only patched the element into
PutBucketReplication bodies. Every re-PUT of fetched rules therefore also
silently disabled delete replication. Move the PUT patch into
lib/bucket-replication-delete and add the GET side: buffer the response XML
below the deserializer and merge each rule's status into the parsed output.

list-remote-targets encodes targets with madmin's JSON tags: the limit is
`bandwidthlimit` (the console read `bandwidth_limit`, so every target showed
the default) and `healthCheckDuration` is Go nanoseconds. Read both through
lib/bucket-replication-target, keep a stored 0 as 0 instead of falling back
to the form defaults, and let a 0 interval pass validation so such a target
stays saveable.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Site replication: force-delete (Console folder delete / rc rm --purge) is never applied on the peer; site-replicator-0 policy lacks s3:ForceDeleteObject

1 participant