mirror of
https://github.com/minio/minio.git
synced 2025-01-25 21:53:16 -05:00
validate bucket before attempting batch replication (#15861)
This commit is contained in:
parent
c79bcc8838
commit
c68910005b
@ -2228,6 +2228,12 @@ func toAPIError(ctx context.Context, err error) APIError {
|
|||||||
// their internal error types. This code is only
|
// their internal error types. This code is only
|
||||||
// useful with gateway implementations.
|
// useful with gateway implementations.
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
|
case batchReplicationJobError:
|
||||||
|
apiErr = APIError{
|
||||||
|
Code: e.Code,
|
||||||
|
Description: e.Description,
|
||||||
|
HTTPStatusCode: e.HTTPStatusCode,
|
||||||
|
}
|
||||||
case InvalidArgument:
|
case InvalidArgument:
|
||||||
apiErr = APIError{
|
apiErr = APIError{
|
||||||
Code: "InvalidArgument",
|
Code: "InvalidArgument",
|
||||||
|
@ -217,6 +217,8 @@ type BatchJobReplicateV1 struct {
|
|||||||
Flags BatchJobReplicateFlags `yaml:"flags" json:"flags"`
|
Flags BatchJobReplicateFlags `yaml:"flags" json:"flags"`
|
||||||
Target BatchJobReplicateTarget `yaml:"target" json:"target"`
|
Target BatchJobReplicateTarget `yaml:"target" json:"target"`
|
||||||
Source BatchJobReplicateSource `yaml:"source" json:"source"`
|
Source BatchJobReplicateSource `yaml:"source" json:"source"`
|
||||||
|
|
||||||
|
clnt *miniogo.Core `msg:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchJobRequest this is an internal data structure not for external consumption.
|
// BatchJobRequest this is an internal data structure not for external consumption.
|
||||||
@ -640,6 +642,17 @@ func (r *BatchJobReplicateV1) Start(ctx context.Context, api ObjectLayer, job Ba
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//msgp:ignore batchReplicationJobError
|
||||||
|
type batchReplicationJobError struct {
|
||||||
|
Code string
|
||||||
|
Description string
|
||||||
|
HTTPStatusCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e batchReplicationJobError) Error() string {
|
||||||
|
return e.Description
|
||||||
|
}
|
||||||
|
|
||||||
// Validate validates the job definition input
|
// Validate validates the job definition input
|
||||||
func (r *BatchJobReplicateV1) Validate(ctx context.Context, o ObjectLayer) error {
|
func (r *BatchJobReplicateV1) Validate(ctx context.Context, o ObjectLayer) error {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
@ -654,8 +667,15 @@ func (r *BatchJobReplicateV1) Validate(ctx context.Context, o ObjectLayer) error
|
|||||||
return errInvalidArgument
|
return errInvalidArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := o.GetBucketInfo(ctx, r.Source.Bucket, BucketOptions{})
|
info, err := o.GetBucketInfo(ctx, r.Source.Bucket, BucketOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if isErrBucketNotFound(err) {
|
||||||
|
return batchReplicationJobError{
|
||||||
|
Code: "NoSuchSourceBucket",
|
||||||
|
Description: "The specified source bucket does not exist",
|
||||||
|
HTTPStatusCode: http.StatusNotFound,
|
||||||
|
}
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,6 +715,44 @@ func (r *BatchJobReplicateV1) Validate(ctx context.Context, o ObjectLayer) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(r.Target.Endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cred := r.Target.Creds
|
||||||
|
|
||||||
|
c, err := miniogo.NewCore(u.Host, &miniogo.Options{
|
||||||
|
Creds: credentials.NewStaticV4(cred.AccessKey, cred.SecretKey, cred.SessionToken),
|
||||||
|
Secure: u.Scheme == "https",
|
||||||
|
Transport: getRemoteInstanceTransport,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
vcfg, err := c.GetBucketVersioning(ctx, r.Target.Bucket)
|
||||||
|
if err != nil {
|
||||||
|
if miniogo.ToErrorResponse(err).Code == "NoSuchBucket" {
|
||||||
|
return batchReplicationJobError{
|
||||||
|
Code: "NoSuchTargetBucket",
|
||||||
|
Description: "The specified target bucket does not exist",
|
||||||
|
HTTPStatusCode: http.StatusNotFound,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Versioning && !vcfg.Enabled() {
|
||||||
|
return batchReplicationJobError{
|
||||||
|
Code: "InvalidBucketState",
|
||||||
|
Description: fmt.Sprintf("The source '%s' has versioning enabled, target '%s' must have versioning enabled",
|
||||||
|
r.Source.Bucket, r.Target.Bucket),
|
||||||
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.clnt = c
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1588,6 +1588,8 @@ func (z *erasureServerPools) GetBucketInfo(ctx context.Context, bucket string, o
|
|||||||
meta, err := globalBucketMetadataSys.Get(bucket)
|
meta, err := globalBucketMetadataSys.Get(bucket)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
bucketInfo.Created = meta.Created
|
bucketInfo.Created = meta.Created
|
||||||
|
bucketInfo.Versioning = meta.LockEnabled || globalBucketVersioningSys.Enabled(bucket)
|
||||||
|
bucketInfo.ObjectLocking = meta.LockEnabled
|
||||||
}
|
}
|
||||||
return bucketInfo, nil
|
return bucketInfo, nil
|
||||||
}
|
}
|
||||||
@ -1602,6 +1604,8 @@ func (z *erasureServerPools) GetBucketInfo(ctx context.Context, bucket string, o
|
|||||||
meta, err := globalBucketMetadataSys.Get(bucket)
|
meta, err := globalBucketMetadataSys.Get(bucket)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
bucketInfo.Created = meta.Created
|
bucketInfo.Created = meta.Created
|
||||||
|
bucketInfo.Versioning = meta.LockEnabled || globalBucketVersioningSys.Enabled(bucket)
|
||||||
|
bucketInfo.ObjectLocking = meta.LockEnabled
|
||||||
}
|
}
|
||||||
return bucketInfo, nil
|
return bucketInfo, nil
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,14 @@ func (es *erasureSingle) GetBucketInfo(ctx context.Context, bucket string, opts
|
|||||||
}
|
}
|
||||||
return bi, toObjectErr(err, bucket)
|
return bi, toObjectErr(err, bucket)
|
||||||
}
|
}
|
||||||
return BucketInfo{Name: volInfo.Name, Created: volInfo.Created}, nil
|
bi = BucketInfo{Name: volInfo.Name, Created: volInfo.Created}
|
||||||
|
meta, err := globalBucketMetadataSys.Get(bucket)
|
||||||
|
if err == nil {
|
||||||
|
bi.Created = meta.Created
|
||||||
|
bi.Versioning = meta.LockEnabled || globalBucketVersioningSys.Enabled(bucket)
|
||||||
|
bi.ObjectLocking = meta.LockEnabled
|
||||||
|
}
|
||||||
|
return bi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBucket - deletes a bucket.
|
// DeleteBucket - deletes a bucket.
|
||||||
|
@ -79,6 +79,9 @@ type BucketInfo struct {
|
|||||||
// Date and time when the bucket was created.
|
// Date and time when the bucket was created.
|
||||||
Created time.Time
|
Created time.Time
|
||||||
Deleted time.Time
|
Deleted time.Time
|
||||||
|
|
||||||
|
// Bucket features enabled
|
||||||
|
Versioning, ObjectLocking bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectInfo - represents object metadata.
|
// ObjectInfo - represents object metadata.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user