diff --git a/cmd/api-errors.go b/cmd/api-errors.go
index 35a34eea5..57d839067 100644
--- a/cmd/api-errors.go
+++ b/cmd/api-errors.go
@@ -1814,6 +1814,8 @@ func toAPIErrorCode(ctx context.Context, err error) (apiErr APIErrorCode) {
apiErr = ErrAdminInvalidAccessKey
case auth.ErrInvalidSecretKeyLength:
apiErr = ErrAdminInvalidSecretKey
+ case errInvalidStorageClass:
+ apiErr = ErrInvalidStorageClass
// SSE errors
case errInvalidEncryptionParameters:
apiErr = ErrInvalidEncryptionParameters
diff --git a/cmd/bucket-lifecycle-handlers.go b/cmd/bucket-lifecycle-handlers.go
index ef7f78ef3..76888f357 100644
--- a/cmd/bucket-lifecycle-handlers.go
+++ b/cmd/bucket-lifecycle-handlers.go
@@ -80,7 +80,7 @@ func (api objectAPIHandlers) PutBucketLifecycleHandler(w http.ResponseWriter, r
}
// Validate the transition storage ARNs
- if err = validateLifecycleTransition(ctx, bucket, bucketLifecycle); err != nil {
+ if err = validateTransitionTier(ctx, bucketLifecycle); err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return
}
diff --git a/cmd/bucket-lifecycle.go b/cmd/bucket-lifecycle.go
index bdfa3d208..bac908e3e 100644
--- a/cmd/bucket-lifecycle.go
+++ b/cmd/bucket-lifecycle.go
@@ -20,6 +20,7 @@ package cmd
import (
"context"
"encoding/xml"
+ "errors"
"fmt"
"io"
"net/http"
@@ -175,28 +176,16 @@ func initBackgroundTransition(ctx context.Context, objectAPI ObjectLayer) {
}
}
-func validateLifecycleTransition(ctx context.Context, bucket string, lfc *lifecycle.Lifecycle) error {
- for _, rule := range lfc.Rules {
- if rule.Transition.StorageClass != "" {
- err := validateTransitionDestination(rule.Transition.StorageClass)
- if err != nil {
- return err
- }
- }
- }
- return nil
-}
+var errInvalidStorageClass = errors.New("invalid storage class")
-// validateTransitionDestination returns error if transition destination bucket missing or not configured
-// It also returns true if transition destination is same as this server.
-func validateTransitionDestination(sc string) error {
- backend, err := globalTierConfigMgr.getDriver(sc)
- if err != nil {
- return TransitionStorageClassNotFound{}
- }
- _, err = backend.Get(context.Background(), "probeobject", WarmBackendGetOpts{})
- if !isErrObjectNotFound(err) {
- return err
+func validateTransitionTier(ctx context.Context, lfc *lifecycle.Lifecycle) error {
+ for _, rule := range lfc.Rules {
+ if rule.Transition.StorageClass == "" {
+ continue
+ }
+ if valid := globalTierConfigMgr.IsTierValid(rule.Transition.StorageClass); !valid {
+ return errInvalidStorageClass
+ }
}
return nil
}
diff --git a/cmd/bucket-lifecycle_test.go b/cmd/bucket-lifecycle_test.go
index b466afded..52b0bc641 100644
--- a/cmd/bucket-lifecycle_test.go
+++ b/cmd/bucket-lifecycle_test.go
@@ -18,6 +18,8 @@
package cmd
import (
+ "bytes"
+ "context"
"net/http"
"testing"
"time"
@@ -214,3 +216,33 @@ func TestObjectIsRemote(t *testing.T) {
t.Fatalf("Expected object not to be remote but got %v", got)
}
}
+
+func TestValidateTransitionTier(t *testing.T) {
+ globalTierConfigMgr = NewTierConfigMgr()
+ testCases := []struct {
+ xml []byte
+ expectedErr error
+ }{
+ {
+ // non-existent storage-class
+ xml: []byte(`ruleEnabled1"NONEXISTENT"`),
+ expectedErr: errInvalidStorageClass,
+ },
+ {
+ // no transition rule
+ xml: []byte(`ruleEnabled1`),
+ expectedErr: nil,
+ },
+ }
+ for i, tc := range testCases {
+ lc, err := lifecycle.ParseLifecycleConfig(bytes.NewReader(tc.xml))
+ if err != nil {
+ t.Fatalf("Test %d: Failed to parse lifecycle config %v", i+1, err)
+ }
+
+ err = validateTransitionTier(context.Background(), lc)
+ if err != tc.expectedErr {
+ t.Fatalf("Test %d: Expected %v but got %v", i+1, tc.expectedErr, err)
+ }
+ }
+}
diff --git a/pkg/bucket/lifecycle/transition.go b/pkg/bucket/lifecycle/transition.go
index 96494caec..db61e13fb 100644
--- a/pkg/bucket/lifecycle/transition.go
+++ b/pkg/bucket/lifecycle/transition.go
@@ -129,7 +129,7 @@ func (t *Transition) UnmarshalXML(d *xml.Decoder, startElement xml.StartElement)
return nil
}
-// Validate - validates the "Expiration" element
+// Validate - validates the "Transition" element
func (t Transition) Validate() error {
if !t.set {
return nil