add gateway object tagging support (#9124)

master
P R 5 years ago committed by GitHub
parent c138272d63
commit 3f6d624c7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      cmd/fs-v1.go
  2. 17
      cmd/gateway-unsupported.go
  3. 4
      cmd/gateway/nas/gateway-nas.go
  4. 4
      cmd/gateway/s3/gateway-s3-utils.go
  5. 81
      cmd/gateway/s3/gateway-s3.go
  6. 2
      cmd/http/headers.go
  7. 9
      cmd/object-api-interface.go
  8. 36
      cmd/object-handlers.go
  9. 22
      cmd/xl-sets.go
  10. 4
      cmd/xl-v1-bucket.go
  11. 14
      cmd/xl-v1-object.go
  12. 28
      cmd/xl-zones.go
  13. 2
      go.mod
  14. 4
      go.sum
  15. 2
      mint/run/core/aws-sdk-go/quick-tests.go

@ -1218,8 +1218,8 @@ func (fs *FSObjects) ListObjects(ctx context.Context, bucket, prefix, marker, de
fs.listDirFactory(), fs.getObjectInfo, fs.getObjectInfo) fs.listDirFactory(), fs.getObjectInfo, fs.getObjectInfo)
} }
// GetObjectTag - get object tags from an existing object // GetObjectTags - get object tags from an existing object
func (fs *FSObjects) GetObjectTag(ctx context.Context, bucket, object string) (*tags.Tags, error) { func (fs *FSObjects) GetObjectTags(ctx context.Context, bucket, object string) (*tags.Tags, error) {
oi, err := fs.GetObjectInfo(ctx, bucket, object, ObjectOptions{}) oi, err := fs.GetObjectInfo(ctx, bucket, object, ObjectOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
@ -1228,8 +1228,8 @@ func (fs *FSObjects) GetObjectTag(ctx context.Context, bucket, object string) (*
return tags.ParseObjectTags(oi.UserTags) return tags.ParseObjectTags(oi.UserTags)
} }
// PutObjectTag - replace or add tags to an existing object // PutObjectTags - replace or add tags to an existing object
func (fs *FSObjects) PutObjectTag(ctx context.Context, bucket, object string, tags string) error { func (fs *FSObjects) PutObjectTags(ctx context.Context, bucket, object string, tags string) error {
fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, object, fs.metaJSONFile) fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, object, fs.metaJSONFile)
fsMeta := fsMetaV1{} fsMeta := fsMetaV1{}
wlk, err := fs.rwPool.Write(fsMetaPath) wlk, err := fs.rwPool.Write(fsMetaPath)
@ -1260,9 +1260,9 @@ func (fs *FSObjects) PutObjectTag(ctx context.Context, bucket, object string, ta
return nil return nil
} }
// DeleteObjectTag - delete object tags from an existing object // DeleteObjectTags - delete object tags from an existing object
func (fs *FSObjects) DeleteObjectTag(ctx context.Context, bucket, object string) error { func (fs *FSObjects) DeleteObjectTags(ctx context.Context, bucket, object string) error {
return fs.PutObjectTag(ctx, bucket, object, "") return fs.PutObjectTags(ctx, bucket, object, "")
} }
// ReloadFormat - no-op for fs, Valid only for XL. // ReloadFormat - no-op for fs, Valid only for XL.
@ -1360,6 +1360,11 @@ func (fs *FSObjects) IsCompressionSupported() bool {
return true return true
} }
// IsTaggingSupported returns true, object tagging is supported in fs object layer.
func (fs *FSObjects) IsTaggingSupported() bool {
return true
}
// IsReady - Check if the backend disk is ready to accept traffic. // IsReady - Check if the backend disk is ready to accept traffic.
func (fs *FSObjects) IsReady(_ context.Context) bool { func (fs *FSObjects) IsReady(_ context.Context) bool {
if _, err := os.Stat(fs.fsPath); err != nil { if _, err := os.Stat(fs.fsPath); err != nil {

@ -228,20 +228,20 @@ func (a GatewayUnsupported) DeleteBucketTagging(ctx context.Context, bucket stri
return NotImplemented{} return NotImplemented{}
} }
// PutObjectTag - not implemented. // PutObjectTags - not implemented.
func (a GatewayUnsupported) PutObjectTag(ctx context.Context, bucket, object string, tags string) error { func (a GatewayUnsupported) PutObjectTags(ctx context.Context, bucket, object string, tags string) error {
logger.LogIf(ctx, NotImplemented{}) logger.LogIf(ctx, NotImplemented{})
return NotImplemented{} return NotImplemented{}
} }
// GetObjectTag - not implemented. // GetObjectTags - not implemented.
func (a GatewayUnsupported) GetObjectTag(ctx context.Context, bucket, object string) (*tags.Tags, error) { func (a GatewayUnsupported) GetObjectTags(ctx context.Context, bucket, object string) (*tags.Tags, error) {
logger.LogIf(ctx, NotImplemented{}) logger.LogIf(ctx, NotImplemented{})
return nil, NotImplemented{} return nil, NotImplemented{}
} }
// DeleteObjectTag - not implemented. // DeleteObjectTags - not implemented.
func (a GatewayUnsupported) DeleteObjectTag(ctx context.Context, bucket, object string) error { func (a GatewayUnsupported) DeleteObjectTags(ctx context.Context, bucket, object string) error {
logger.LogIf(ctx, NotImplemented{}) logger.LogIf(ctx, NotImplemented{})
return NotImplemented{} return NotImplemented{}
} }
@ -261,6 +261,11 @@ func (a GatewayUnsupported) IsEncryptionSupported() bool {
return false return false
} }
// IsTaggingSupported returns whether object tagging is supported or not for this layer.
func (a GatewayUnsupported) IsTaggingSupported() bool {
return false
}
// IsCompressionSupported returns whether compression is applicable for this layer. // IsCompressionSupported returns whether compression is applicable for this layer.
func (a GatewayUnsupported) IsCompressionSupported() bool { func (a GatewayUnsupported) IsCompressionSupported() bool {
return false return false

@ -137,3 +137,7 @@ func (n *nasObjects) IsReady(ctx context.Context) bool {
sinfo := n.ObjectLayer.StorageInfo(ctx, false) sinfo := n.ObjectLayer.StorageInfo(ctx, false)
return sinfo.Backend.Type == minio.BackendFS return sinfo.Backend.Type == minio.BackendFS
} }
func (n *nasObjects) IsTaggingSupported() bool {
return true
}

@ -16,7 +16,9 @@
package s3 package s3
import minio "github.com/minio/minio/cmd" import (
minio "github.com/minio/minio/cmd"
)
// List of header keys to be filtered, usually // List of header keys to be filtered, usually
// from all S3 API http responses. // from all S3 API http responses.

@ -29,10 +29,12 @@ import (
"github.com/minio/cli" "github.com/minio/cli"
miniogo "github.com/minio/minio-go/v6" miniogo "github.com/minio/minio-go/v6"
"github.com/minio/minio-go/v6/pkg/credentials" "github.com/minio/minio-go/v6/pkg/credentials"
"github.com/minio/minio-go/v6/pkg/tags"
minio "github.com/minio/minio/cmd" minio "github.com/minio/minio/cmd"
"github.com/minio/minio-go/v6/pkg/encrypt" "github.com/minio/minio-go/v6/pkg/encrypt"
"github.com/minio/minio-go/v6/pkg/s3utils" "github.com/minio/minio-go/v6/pkg/s3utils"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/bucket/policy" "github.com/minio/minio/pkg/bucket/policy"
@ -459,11 +461,25 @@ func (l *s3Objects) GetObjectInfo(ctx context.Context, bucket string, object str
// PutObject creates a new object with the incoming data, // PutObject creates a new object with the incoming data,
func (l *s3Objects) PutObject(ctx context.Context, bucket string, object string, r *minio.PutObjReader, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { func (l *s3Objects) PutObject(ctx context.Context, bucket string, object string, r *minio.PutObjReader, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) {
data := r.Reader data := r.Reader
var tagMap map[string]string
oi, err := l.Client.PutObject(bucket, object, data, data.Size(), data.MD5Base64String(), data.SHA256HexString(), minio.ToMinioClientMetadata(opts.UserDefined), opts.ServerSideEncryption) if tagstr, ok := opts.UserDefined[xhttp.AmzObjectTagging]; ok && tagstr != "" {
tagObj, err := tags.ParseObjectTags(tagstr)
if err != nil { if err != nil {
return objInfo, minio.ErrorRespToObjectError(err, bucket, object) return objInfo, minio.ErrorRespToObjectError(err, bucket, object)
} }
tagMap = tagObj.ToMap()
delete(opts.UserDefined, xhttp.AmzObjectTagging)
}
putOpts := miniogo.PutObjectOptions{
UserMetadata: opts.UserDefined,
ServerSideEncryption: opts.ServerSideEncryption,
UserTags: tagMap,
}
oi, err := l.Client.PutObject(bucket, object, data, data.Size(), data.MD5Base64String(), data.SHA256HexString(), putOpts)
if err != nil {
return objInfo, minio.ErrorRespToObjectError(err, bucket, object)
}
// On success, populate the key & metadata so they are present in the notification // On success, populate the key & metadata so they are present in the notification
oi.Key = object oi.Key = object
oi.Metadata = minio.ToMinioClientObjectInfoMetadata(opts.UserDefined) oi.Metadata = minio.ToMinioClientObjectInfoMetadata(opts.UserDefined)
@ -490,6 +506,7 @@ func (l *s3Objects) CopyObject(ctx context.Context, srcBucket string, srcObject
if dstOpts.ServerSideEncryption != nil { if dstOpts.ServerSideEncryption != nil {
dstOpts.ServerSideEncryption.Marshal(header) dstOpts.ServerSideEncryption.Marshal(header)
} }
for k, v := range header { for k, v := range header {
srcInfo.UserDefined[k] = v[0] srcInfo.UserDefined[k] = v[0]
} }
@ -530,8 +547,21 @@ func (l *s3Objects) ListMultipartUploads(ctx context.Context, bucket string, pre
// NewMultipartUpload upload object in multiple parts // NewMultipartUpload upload object in multiple parts
func (l *s3Objects) NewMultipartUpload(ctx context.Context, bucket string, object string, o minio.ObjectOptions) (uploadID string, err error) { func (l *s3Objects) NewMultipartUpload(ctx context.Context, bucket string, object string, o minio.ObjectOptions) (uploadID string, err error) {
var tagMap map[string]string
if tagStr, ok := o.UserDefined[xhttp.AmzObjectTagging]; ok {
tagObj, err := tags.Parse(tagStr, true)
if err != nil {
return uploadID, minio.ErrorRespToObjectError(err, bucket, object)
}
tagMap = tagObj.ToMap()
delete(o.UserDefined, xhttp.AmzObjectTagging)
}
// Create PutObject options // Create PutObject options
opts := miniogo.PutObjectOptions{UserMetadata: o.UserDefined, ServerSideEncryption: o.ServerSideEncryption} opts := miniogo.PutObjectOptions{
UserMetadata: o.UserDefined,
ServerSideEncryption: o.ServerSideEncryption,
UserTags: tagMap,
}
uploadID, err = l.Client.NewMultipartUpload(bucket, object, opts) uploadID, err = l.Client.NewMultipartUpload(bucket, object, opts)
if err != nil { if err != nil {
return uploadID, minio.ErrorRespToObjectError(err, bucket, object) return uploadID, minio.ErrorRespToObjectError(err, bucket, object)
@ -643,6 +673,47 @@ func (l *s3Objects) DeleteBucketPolicy(ctx context.Context, bucket string) error
return nil return nil
} }
// GetObjectTags gets the tags set on the object
func (l *s3Objects) GetObjectTags(ctx context.Context, bucket string, object string) (*tags.Tags, error) {
var err error
var tagObj *tags.Tags
var tagStr string
var opts minio.ObjectOptions
if _, err = l.GetObjectInfo(ctx, bucket, object, opts); err != nil {
return nil, minio.ErrorRespToObjectError(err, bucket, object)
}
if tagStr, err = l.Client.GetObjectTagging(bucket, object); err != nil {
return nil, minio.ErrorRespToObjectError(err, bucket, object)
}
if tagObj, err = tags.ParseObjectXML(strings.NewReader(tagStr)); err != nil {
return nil, minio.ErrorRespToObjectError(err, bucket, object)
}
return tagObj, err
}
// PutObjectTags attaches the tags to the object
func (l *s3Objects) PutObjectTags(ctx context.Context, bucket, object string, tagStr string) error {
tagObj, err := tags.Parse(tagStr, true)
if err != nil {
return minio.ErrorRespToObjectError(err, bucket, object)
}
if err = l.Client.PutObjectTagging(bucket, object, tagObj.ToMap()); err != nil {
return minio.ErrorRespToObjectError(err, bucket, object)
}
return nil
}
// DeleteObjectTags removes the tags attached to the object
func (l *s3Objects) DeleteObjectTags(ctx context.Context, bucket, object string) error {
if err := l.Client.RemoveObjectTagging(bucket, object); err != nil {
return minio.ErrorRespToObjectError(err, bucket, object)
}
return nil
}
// IsCompressionSupported returns whether compression is applicable for this layer. // IsCompressionSupported returns whether compression is applicable for this layer.
func (l *s3Objects) IsCompressionSupported() bool { func (l *s3Objects) IsCompressionSupported() bool {
return false return false
@ -657,3 +728,7 @@ func (l *s3Objects) IsEncryptionSupported() bool {
func (l *s3Objects) IsReady(ctx context.Context) bool { func (l *s3Objects) IsReady(ctx context.Context) bool {
return minio.IsBackendOnline(ctx, l.HTTPClient, l.Client.EndpointURL().String()) return minio.IsBackendOnline(ctx, l.HTTPClient, l.Client.EndpointURL().String())
} }
func (l *s3Objects) IsTaggingSupported() bool {
return true
}

@ -58,7 +58,7 @@ const (
// S3 object tagging // S3 object tagging
AmzObjectTagging = "X-Amz-Tagging" AmzObjectTagging = "X-Amz-Tagging"
AmzTagCount = "X-Amz-Tag-Count" AmzTagCount = "X-Amz-Tagging-Count"
AmzTagDirective = "X-Amz-Tagging-Directive" AmzTagDirective = "X-Amz-Tagging-Directive"
// S3 extensions // S3 extensions

@ -123,8 +123,11 @@ type ObjectLayer interface {
// Check Readiness // Check Readiness
IsReady(ctx context.Context) bool IsReady(ctx context.Context) bool
// Object Tagging Support check.
IsTaggingSupported() bool
// ObjectTagging operations // ObjectTagging operations
PutObjectTag(context.Context, string, string, string) error PutObjectTags(context.Context, string, string, string) error
GetObjectTag(context.Context, string, string) (*tags.Tags, error) GetObjectTags(context.Context, string, string) (*tags.Tags, error)
DeleteObjectTag(context.Context, string, string) error DeleteObjectTags(context.Context, string, string) error
} }

@ -1072,6 +1072,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
// If x-amz-tagging-directive header is REPLACE, get passed tags. // If x-amz-tagging-directive header is REPLACE, get passed tags.
if isDirectiveReplace(r.Header.Get(xhttp.AmzTagDirective)) { if isDirectiveReplace(r.Header.Get(xhttp.AmzTagDirective)) {
objTags = r.Header.Get(xhttp.AmzObjectTagging) objTags = r.Header.Get(xhttp.AmzObjectTagging)
srcInfo.UserDefined[xhttp.AmzTagDirective] = replaceDirective
if _, err := tags.ParseObjectTags(objTags); err != nil { if _, err := tags.ParseObjectTags(objTags); err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return return
@ -1147,8 +1148,18 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
writeErrorResponse(ctx, w, toAPIError(ctx, rerr), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, rerr), r.URL, guessIsBrowserReq(r))
return return
} }
tag, err := tags.ParseObjectTags(objTags)
if err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return
}
opts := miniogo.PutObjectOptions{
UserMetadata: srcInfo.UserDefined,
ServerSideEncryption: dstOpts.ServerSideEncryption,
UserTags: tag.ToMap(),
}
remoteObjInfo, rerr := client.PutObject(dstBucket, dstObject, srcInfo.Reader, remoteObjInfo, rerr := client.PutObject(dstBucket, dstObject, srcInfo.Reader,
srcInfo.Size, "", "", srcInfo.UserDefined, dstOpts.ServerSideEncryption) srcInfo.Size, "", "", opts)
if rerr != nil { if rerr != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, rerr), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, rerr), r.URL, guessIsBrowserReq(r))
return return
@ -1284,6 +1295,11 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
} }
if objTags := r.Header.Get(xhttp.AmzObjectTagging); objTags != "" { if objTags := r.Header.Get(xhttp.AmzObjectTagging); objTags != "" {
if !objectAPI.IsTaggingSupported() {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return
}
if _, err := tags.ParseObjectTags(objTags); err != nil { if _, err := tags.ParseObjectTags(objTags); err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return return
@ -2946,6 +2962,10 @@ func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *h
return return
} }
if !objAPI.IsTaggingSupported() {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return
}
// Allow getObjectTagging if policy action is set. // Allow getObjectTagging if policy action is set.
if s3Error := checkRequestAuthType(ctx, r, policy.GetObjectTaggingAction, bucket, object); s3Error != ErrNone { if s3Error := checkRequestAuthType(ctx, r, policy.GetObjectTaggingAction, bucket, object); s3Error != ErrNone {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r))
@ -2953,7 +2973,7 @@ func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *h
} }
// Get object tags // Get object tags
tags, err := objAPI.GetObjectTag(ctx, bucket, object) tags, err := objAPI.GetObjectTags(ctx, bucket, object)
if err != nil { if err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return return
@ -2980,6 +3000,10 @@ func (api objectAPIHandlers) PutObjectTaggingHandler(w http.ResponseWriter, r *h
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r))
return return
} }
if !objAPI.IsTaggingSupported() {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return
}
// Allow putObjectTagging if policy action is set // Allow putObjectTagging if policy action is set
if s3Error := checkRequestAuthType(ctx, r, policy.PutObjectTaggingAction, bucket, object); s3Error != ErrNone { if s3Error := checkRequestAuthType(ctx, r, policy.PutObjectTaggingAction, bucket, object); s3Error != ErrNone {
@ -2994,7 +3018,7 @@ func (api objectAPIHandlers) PutObjectTaggingHandler(w http.ResponseWriter, r *h
} }
// Put object tags // Put object tags
err = objAPI.PutObjectTag(ctx, bucket, object, tags.String()) err = objAPI.PutObjectTags(ctx, bucket, object, tags.String())
if err != nil { if err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return return
@ -3013,6 +3037,10 @@ func (api objectAPIHandlers) DeleteObjectTaggingHandler(w http.ResponseWriter, r
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r))
return return
} }
if !objAPI.IsTaggingSupported() {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return
}
vars := mux.Vars(r) vars := mux.Vars(r)
bucket := vars["bucket"] bucket := vars["bucket"]
@ -3029,7 +3057,7 @@ func (api objectAPIHandlers) DeleteObjectTaggingHandler(w http.ResponseWriter, r
} }
// Delete object tags // Delete object tags
if err = objAPI.DeleteObjectTag(ctx, bucket, object); err != nil && err != errConfigNotFound { if err = objAPI.DeleteObjectTags(ctx, bucket, object); err != nil && err != errConfigNotFound {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return return
} }

@ -588,6 +588,10 @@ func (s *xlSets) IsCompressionSupported() bool {
return s.getHashedSet("").IsCompressionSupported() return s.getHashedSet("").IsCompressionSupported()
} }
func (s *xlSets) IsTaggingSupported() bool {
return true
}
// DeleteBucket - deletes a bucket on all sets simultaneously, // DeleteBucket - deletes a bucket on all sets simultaneously,
// even if one of the sets fail to delete buckets, we proceed to // even if one of the sets fail to delete buckets, we proceed to
// undo a successful operation. // undo a successful operation.
@ -1684,19 +1688,19 @@ func (s *xlSets) HealObjects(ctx context.Context, bucket, prefix string, opts ma
return nil return nil
} }
// PutObjectTag - replace or add tags to an existing object // PutObjectTags - replace or add tags to an existing object
func (s *xlSets) PutObjectTag(ctx context.Context, bucket, object string, tags string) error { func (s *xlSets) PutObjectTags(ctx context.Context, bucket, object string, tags string) error {
return s.getHashedSet(object).PutObjectTag(ctx, bucket, object, tags) return s.getHashedSet(object).PutObjectTags(ctx, bucket, object, tags)
} }
// DeleteObjectTag - delete object tags from an existing object // DeleteObjectTags - delete object tags from an existing object
func (s *xlSets) DeleteObjectTag(ctx context.Context, bucket, object string) error { func (s *xlSets) DeleteObjectTags(ctx context.Context, bucket, object string) error {
return s.getHashedSet(object).DeleteObjectTag(ctx, bucket, object) return s.getHashedSet(object).DeleteObjectTags(ctx, bucket, object)
} }
// GetObjectTag - get object tags from an existing object // GetObjectTags - get object tags from an existing object
func (s *xlSets) GetObjectTag(ctx context.Context, bucket, object string) (*tags.Tags, error) { func (s *xlSets) GetObjectTags(ctx context.Context, bucket, object string) (*tags.Tags, error) {
return s.getHashedSet(object).GetObjectTag(ctx, bucket, object) return s.getHashedSet(object).GetObjectTags(ctx, bucket, object)
} }
// GetMetrics - no op // GetMetrics - no op

@ -269,3 +269,7 @@ func (xl xlObjects) IsEncryptionSupported() bool {
func (xl xlObjects) IsCompressionSupported() bool { func (xl xlObjects) IsCompressionSupported() bool {
return true return true
} }
func (xl xlObjects) IsTaggingSupported() bool {
return true
}

@ -1009,8 +1009,8 @@ func (xl xlObjects) addPartialUpload(bucket, key string) {
} }
} }
// PutObjectTag - replace or add tags to an existing object // PutObjectTags - replace or add tags to an existing object
func (xl xlObjects) PutObjectTag(ctx context.Context, bucket, object string, tags string) error { func (xl xlObjects) PutObjectTags(ctx context.Context, bucket, object string, tags string) error {
disks := xl.getDisks() disks := xl.getDisks()
// Read metadata associated with the object from all disks. // Read metadata associated with the object from all disks.
@ -1046,13 +1046,13 @@ func (xl xlObjects) PutObjectTag(ctx context.Context, bucket, object string, tag
return nil return nil
} }
// DeleteObjectTag - delete object tags from an existing object // DeleteObjectTags - delete object tags from an existing object
func (xl xlObjects) DeleteObjectTag(ctx context.Context, bucket, object string) error { func (xl xlObjects) DeleteObjectTags(ctx context.Context, bucket, object string) error {
return xl.PutObjectTag(ctx, bucket, object, "") return xl.PutObjectTags(ctx, bucket, object, "")
} }
// GetObjectTag - get object tags from an existing object // GetObjectTags - get object tags from an existing object
func (xl xlObjects) GetObjectTag(ctx context.Context, bucket, object string) (*tags.Tags, error) { func (xl xlObjects) GetObjectTags(ctx context.Context, bucket, object string) (*tags.Tags, error) {
// GetObjectInfo will return tag value as well // GetObjectInfo will return tag value as well
oi, err := xl.GetObjectInfo(ctx, bucket, object, ObjectOptions{}) oi, err := xl.GetObjectInfo(ctx, bucket, object, ObjectOptions{})
if err != nil { if err != nil {

@ -1223,6 +1223,10 @@ func (z *xlZones) IsCompressionSupported() bool {
return true return true
} }
func (z *xlZones) IsTaggingSupported() bool {
return true
}
// DeleteBucket - deletes a bucket on all zones simultaneously, // DeleteBucket - deletes a bucket on all zones simultaneously,
// even if one of the zones fail to delete buckets, we proceed to // even if one of the zones fail to delete buckets, we proceed to
// undo a successful operation. // undo a successful operation.
@ -1538,13 +1542,13 @@ func (z *xlZones) IsReady(ctx context.Context) bool {
return z.zones[0].IsReady(ctx) return z.zones[0].IsReady(ctx)
} }
// PutObjectTag - replace or add tags to an existing object // PutObjectTags - replace or add tags to an existing object
func (z *xlZones) PutObjectTag(ctx context.Context, bucket, object string, tags string) error { func (z *xlZones) PutObjectTags(ctx context.Context, bucket, object string, tags string) error {
if z.SingleZone() { if z.SingleZone() {
return z.zones[0].PutObjectTag(ctx, bucket, object, tags) return z.zones[0].PutObjectTags(ctx, bucket, object, tags)
} }
for _, zone := range z.zones { for _, zone := range z.zones {
err := zone.PutObjectTag(ctx, bucket, object, tags) err := zone.PutObjectTags(ctx, bucket, object, tags)
if err != nil { if err != nil {
if isErrBucketNotFound(err) { if isErrBucketNotFound(err) {
continue continue
@ -1558,13 +1562,13 @@ func (z *xlZones) PutObjectTag(ctx context.Context, bucket, object string, tags
} }
} }
// DeleteObjectTag - delete object tags from an existing object // DeleteObjectTags - delete object tags from an existing object
func (z *xlZones) DeleteObjectTag(ctx context.Context, bucket, object string) error { func (z *xlZones) DeleteObjectTags(ctx context.Context, bucket, object string) error {
if z.SingleZone() { if z.SingleZone() {
return z.zones[0].DeleteObjectTag(ctx, bucket, object) return z.zones[0].DeleteObjectTags(ctx, bucket, object)
} }
for _, zone := range z.zones { for _, zone := range z.zones {
err := zone.DeleteObjectTag(ctx, bucket, object) err := zone.DeleteObjectTags(ctx, bucket, object)
if err != nil { if err != nil {
if isErrBucketNotFound(err) { if isErrBucketNotFound(err) {
continue continue
@ -1578,13 +1582,13 @@ func (z *xlZones) DeleteObjectTag(ctx context.Context, bucket, object string) er
} }
} }
// GetObjectTag - get object tags from an existing object // GetObjectTags - get object tags from an existing object
func (z *xlZones) GetObjectTag(ctx context.Context, bucket, object string) (*tags.Tags, error) { func (z *xlZones) GetObjectTags(ctx context.Context, bucket, object string) (*tags.Tags, error) {
if z.SingleZone() { if z.SingleZone() {
return z.zones[0].GetObjectTag(ctx, bucket, object) return z.zones[0].GetObjectTags(ctx, bucket, object)
} }
for _, zone := range z.zones { for _, zone := range z.zones {
tags, err := zone.GetObjectTag(ctx, bucket, object) tags, err := zone.GetObjectTags(ctx, bucket, object)
if err != nil { if err != nil {
if isErrBucketNotFound(err) { if isErrBucketNotFound(err) {
continue continue

@ -66,7 +66,7 @@ require (
github.com/minio/hdfs/v3 v3.0.1 github.com/minio/hdfs/v3 v3.0.1
github.com/minio/highwayhash v1.0.0 github.com/minio/highwayhash v1.0.0
github.com/minio/lsync v1.0.1 github.com/minio/lsync v1.0.1
github.com/minio/minio-go/v6 v6.0.55-0.20200425081427-89eebdef2af0 github.com/minio/minio-go/v6 v6.0.56-0.20200522164946-44a5f2e3b76b
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61 github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61
github.com/minio/sha256-simd v0.1.1 github.com/minio/sha256-simd v0.1.1
github.com/minio/simdjson-go v0.1.5-0.20200303142138-b17fe061ea37 github.com/minio/simdjson-go v0.1.5-0.20200303142138-b17fe061ea37

@ -267,6 +267,10 @@ github.com/minio/lsync v1.0.1/go.mod h1:tCFzfo0dlvdGl70IT4IAK/5Wtgb0/BrTmo/jE8pA
github.com/minio/minio-go/v6 v6.0.53/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI= github.com/minio/minio-go/v6 v6.0.53/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI=
github.com/minio/minio-go/v6 v6.0.55-0.20200425081427-89eebdef2af0 h1:PdHKpM9h2vqCDr1AjJdK8e/6tRdOSjUNzIqeNmxu7ak= github.com/minio/minio-go/v6 v6.0.55-0.20200425081427-89eebdef2af0 h1:PdHKpM9h2vqCDr1AjJdK8e/6tRdOSjUNzIqeNmxu7ak=
github.com/minio/minio-go/v6 v6.0.55-0.20200425081427-89eebdef2af0/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI= github.com/minio/minio-go/v6 v6.0.55-0.20200425081427-89eebdef2af0/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
github.com/minio/minio-go/v6 v6.0.56-0.20200522005053-e9bc14bbccf9 h1:GpjSzFSjmNL9+SOzdJaQ6vxdvpFjhJR+xjtoK00Rle4=
github.com/minio/minio-go/v6 v6.0.56-0.20200522005053-e9bc14bbccf9/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
github.com/minio/minio-go/v6 v6.0.56-0.20200522164946-44a5f2e3b76b h1:hY8tAl7MwUuUB9ZqVDXEnrIqCuEy3dfU1RH0cZ7gu+o=
github.com/minio/minio-go/v6 v6.0.56-0.20200522164946-44a5f2e3b76b/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61 h1:pUSI/WKPdd77gcuoJkSzhJ4wdS8OMDOsOu99MtpXEQA= github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61 h1:pUSI/WKPdd77gcuoJkSzhJ4wdS8OMDOsOu99MtpXEQA=
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61/go.mod h1:4trzEJ7N1nBTd5Tt7OCZT5SEin+WiAXpdJ/WgPkESA8= github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61/go.mod h1:4trzEJ7N1nBTd5Tt7OCZT5SEin+WiAXpdJ/WgPkESA8=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=

@ -626,7 +626,7 @@ func testObjectTagging(s3Client *s3.S3) {
func testObjectTaggingErrors(s3Client *s3.S3) { func testObjectTaggingErrors(s3Client *s3.S3) {
startTime := time.Now() startTime := time.Now()
function := "testObjectTagging" function := "testObjectTaggingErrors"
bucket := randString(60, rand.NewSource(time.Now().UnixNano()), "aws-sdk-go-test-") bucket := randString(60, rand.NewSource(time.Now().UnixNano()), "aws-sdk-go-test-")
object := randString(60, rand.NewSource(time.Now().UnixNano()), "") object := randString(60, rand.NewSource(time.Now().UnixNano()), "")
args := map[string]interface{}{ args := map[string]interface{}{

Loading…
Cancel
Save