allow forcibly creating metadata on buckets (#14820)

introduce x-minio-force-create environment variable
to force create a bucket and its metadata as required,
it is useful in some situations when bucket metadata
needs recovery.
This commit is contained in:
Harshavardhana 2022-04-27 04:44:07 -07:00 committed by GitHub
parent fe1fbe0005
commit 5a9a898ba2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 36 additions and 4 deletions

View File

@ -115,10 +115,12 @@ func (a adminAPIHandlers) SRPeerBucketOps(w http.ResponseWriter, r *http.Request
case madmin.MakeWithVersioningBktOp: case madmin.MakeWithVersioningBktOp:
_, isLockEnabled := r.Form["lockEnabled"] _, isLockEnabled := r.Form["lockEnabled"]
_, isVersioningEnabled := r.Form["versioningEnabled"] _, isVersioningEnabled := r.Form["versioningEnabled"]
_, isForceCreate := r.Form["forceCreate"]
opts := BucketOptions{ opts := BucketOptions{
Location: r.Form.Get("location"), Location: r.Form.Get("location"),
LockEnabled: isLockEnabled, LockEnabled: isLockEnabled,
VersioningEnabled: isVersioningEnabled, VersioningEnabled: isVersioningEnabled,
ForceCreate: isForceCreate,
} }
err = globalSiteReplicationSys.PeerBucketMakeWithVersioningHandler(ctx, bucket, opts) err = globalSiteReplicationSys.PeerBucketMakeWithVersioningHandler(ctx, bucket, opts)
case madmin.ConfigureReplBktOp: case madmin.ConfigureReplBktOp:

View File

@ -706,13 +706,27 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
bucket := vars["bucket"] bucket := vars["bucket"]
objectLockEnabled := false objectLockEnabled := false
if vs, found := r.Header[http.CanonicalHeaderKey("x-amz-bucket-object-lock-enabled")]; found { if vs := r.Header.Get(xhttp.AmzObjectLockEnabled); len(vs) > 0 {
v := strings.ToLower(strings.Join(vs, "")) v := strings.ToLower(vs)
if v != "true" && v != "false" { switch v {
case "true", "false":
objectLockEnabled = v == "true"
default:
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
return
}
}
forceCreate := false
if vs := r.Header.Get(xhttp.MinIOForceCreate); len(vs) > 0 {
v := strings.ToLower(vs)
switch v {
case "true", "false":
forceCreate = v == "true"
default:
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
return return
} }
objectLockEnabled = v == "true"
} }
if s3Error := checkRequestAuthType(ctx, r, policy.CreateBucketAction, bucket, ""); s3Error != ErrNone { if s3Error := checkRequestAuthType(ctx, r, policy.CreateBucketAction, bucket, ""); s3Error != ErrNone {
@ -737,6 +751,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
opts := BucketOptions{ opts := BucketOptions{
Location: location, Location: location,
LockEnabled: objectLockEnabled, LockEnabled: objectLockEnabled,
ForceCreate: forceCreate,
} }
if globalDNSConfig != nil { if globalDNSConfig != nil {

View File

@ -55,6 +55,11 @@ func (er erasureObjects) MakeBucketWithLocation(ctx context.Context, bucket stri
g.Go(func() error { g.Go(func() error {
if storageDisks[index] != nil { if storageDisks[index] != nil {
if err := storageDisks[index].MakeVol(ctx, bucket); err != nil { if err := storageDisks[index].MakeVol(ctx, bucket); err != nil {
if opts.ForceCreate && errors.Is(err, errVolumeExists) {
// No need to return error when force create was
// requested.
return nil
}
if !errors.Is(err, errVolumeExists) { if !errors.Is(err, errVolumeExists) {
logger.LogIf(ctx, err) logger.LogIf(ctx, err)
} }

View File

@ -98,6 +98,7 @@ type BucketOptions struct {
Location string Location string
LockEnabled bool LockEnabled bool
VersioningEnabled bool VersioningEnabled bool
ForceCreate bool // Create buckets even if they are already created.
} }
// DeleteBucketOptions provides options for DeleteBucket calls. // DeleteBucketOptions provides options for DeleteBucket calls.

View File

@ -625,6 +625,9 @@ func (c *SiteReplicationSys) MakeBucketHook(ctx context.Context, bucket string,
if opts.VersioningEnabled { if opts.VersioningEnabled {
optsMap["versioningEnabled"] = "true" optsMap["versioningEnabled"] = "true"
} }
if opts.ForceCreate {
optsMap["forceCreate"] = "true"
}
// Create bucket and enable versioning on all peers. // Create bucket and enable versioning on all peers.
makeBucketConcErr := c.concDo( makeBucketConcErr := c.concDo(

View File

@ -91,6 +91,9 @@ const (
AmzBucketReplicationStatus = "X-Amz-Replication-Status" AmzBucketReplicationStatus = "X-Amz-Replication-Status"
AmzSnowballExtract = "X-Amz-Meta-Snowball-Auto-Extract" AmzSnowballExtract = "X-Amz-Meta-Snowball-Auto-Extract"
// Object lock enabled
AmzObjectLockEnabled = "x-amz-bucket-object-lock-enabled"
// Multipart parts count // Multipart parts count
AmzMpPartsCount = "x-amz-mp-parts-count" AmzMpPartsCount = "x-amz-mp-parts-count"
@ -144,6 +147,9 @@ const (
// Delete special flag to force delete a bucket or a prefix // Delete special flag to force delete a bucket or a prefix
MinIOForceDelete = "x-minio-force-delete" MinIOForceDelete = "x-minio-force-delete"
// Create special flag to force create a bucket
MinIOForceCreate = "x-minio-force-create"
// Header indicates if the mtime should be preserved by client // Header indicates if the mtime should be preserved by client
MinIOSourceMTime = "x-minio-source-mtime" MinIOSourceMTime = "x-minio-source-mtime"