filer: allow clearing a bucket read-only flag stuck after quota removal (#10310)

* filer: allow clearing a bucket read-only flag stuck after quota removal

Once s3.bucket.quota.enforce marks a bucket read-only, removing or
disabling the quota orphans the flag: enforcement skips buckets with a
non-positive quota, and fs.configure merges booleans with OR so
-readOnly=false could never turn it off. The only way out was deleting
the whole path rule.

- s3.bucket.quota -op=remove/disable and the admin server quota update
  now lift the read-only flag on the bucket's path rule
- fs.configure now honors explicitly passed false boolean flags
  (-readOnly, -fsync, -worm) instead of OR-merging them away

* filer: ClearBucketReadOnly reports unchanged when the save fails
This commit is contained in:
Chris Lu
2026-07-10 22:09:39 -07:00
committed by GitHub
parent c006dc563e
commit e7be6bb2f8
5 changed files with 110 additions and 0 deletions
+18
View File
@@ -41,6 +41,9 @@ func (c *commandFsConfigure) Help() string {
# apply the changes
fs.configure -locationPrefix=/my/folder -collection=abc -apply
# example: unlock a bucket that quota enforcement made read-only
fs.configure -locationPrefix=/buckets/my_bucket/ -readOnly=false -apply
# delete the changes
fs.configure -locationPrefix=/my/folder -delete -apply
@@ -131,6 +134,21 @@ func (c *commandFsConfigure) Do(args []string, commandEnv *CommandEnv, writer io
fc.DeleteLocationConf(*locationPrefix)
} else {
fc.AddLocationConf(locConf)
// AddLocationConf merges boolean fields with OR, which can never turn
// a flag off; let an explicitly passed false win, e.g. -readOnly=false
// to reopen a bucket that quota enforcement locked
if mergedConf, found := fc.GetLocationConf(*locationPrefix); found {
fsConfigureCommand.Visit(func(f *flag.Flag) {
switch f.Name {
case "readOnly":
mergedConf.ReadOnly = *isReadOnly
case "fsync":
mergedConf.Fsync = *fsync
case "worm":
mergedConf.Worm = *worm
}
})
}
}
}
+19
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
)
@@ -25,6 +26,9 @@ func (c *commandS3BucketQuota) Help() string {
Example:
s3.bucket.quota -name=<bucket_name> -op=set -sizeMB=1024
Removing or disabling the quota also clears the read-only flag that
s3.bucket.quota.enforce may have set on the bucket.
`
}
@@ -65,6 +69,7 @@ func (c *commandS3BucketQuota) Do(args []string, commandEnv *CommandEnv, writer
}
bucketEntry := lookupResp.Entry
clearReadOnly := false
switch *operationName {
case "set":
bucketEntry.Quota = *sizeMB * 1024 * 1024
@@ -73,6 +78,7 @@ func (c *commandS3BucketQuota) Do(args []string, commandEnv *CommandEnv, writer
return nil
case "remove":
bucketEntry.Quota = 0
clearReadOnly = true
case "enable":
if bucketEntry.Quota < 0 {
bucketEntry.Quota = -bucketEntry.Quota
@@ -81,6 +87,7 @@ func (c *commandS3BucketQuota) Do(args []string, commandEnv *CommandEnv, writer
if bucketEntry.Quota > 0 {
bucketEntry.Quota = -bucketEntry.Quota
}
clearReadOnly = true
}
if err := filer_pb.UpdateEntry(context.Background(), client, &filer_pb.UpdateEntryRequest{
@@ -92,6 +99,18 @@ func (c *commandS3BucketQuota) Do(args []string, commandEnv *CommandEnv, writer
println("updated quota for bucket", *bucketName)
if clearReadOnly {
// with the quota removed or disabled, s3.bucket.quota.enforce can no
// longer clear a read-only flag it turned on, so lift it here
cleared, err := filer.ClearBucketReadOnly(ctx, client, filerBucketsPath, *bucketName)
if err != nil {
return err
}
if cleared {
fmt.Fprintf(writer, "cleared read-only for bucket %s\n", *bucketName)
}
}
return nil
})