satellite/metabase: better error message while move
Before this change we were returning full DB error message. That can be very confusing for end user. This change is translating error message into more user frindly version and fixes also DRPC error status code. Fixes https://github.com/storj/team-metainfo/issues/76 Change-Id: I29b06ab4ba50a0d14db7a822a2906d95d65ab524
This commit is contained in:
parent
bc161794fc
commit
2e31ef3f29
@ -192,7 +192,7 @@ func (db *DB) BeginObjectExactVersion(ctx context.Context, opts BeginObjectExact
|
|||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if code := pgerrcode.FromError(err); code == pgxerrcode.UniqueViolation {
|
if code := pgerrcode.FromError(err); code == pgxerrcode.UniqueViolation {
|
||||||
return Object{}, ErrConflict.New("object already exists")
|
return Object{}, Error.Wrap(ErrObjectAlreadyExists.New(""))
|
||||||
}
|
}
|
||||||
return Object{}, Error.New("unable to insert object: %w", err)
|
return Object{}, Error.New("unable to insert object: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -494,8 +494,7 @@ func TestBeginObjectExactVersion(t *testing.T) {
|
|||||||
Encryption: metabasetest.DefaultEncryption,
|
Encryption: metabasetest.DefaultEncryption,
|
||||||
},
|
},
|
||||||
Version: -1,
|
Version: -1,
|
||||||
ErrClass: &metabase.ErrConflict,
|
ErrClass: &metabase.ErrObjectAlreadyExists,
|
||||||
ErrText: "object already exists",
|
|
||||||
}.Check(ctx, t, db)
|
}.Check(ctx, t, db)
|
||||||
|
|
||||||
metabasetest.Verify{
|
metabasetest.Verify{
|
||||||
@ -545,8 +544,7 @@ func TestBeginObjectExactVersion(t *testing.T) {
|
|||||||
Encryption: metabasetest.DefaultEncryption,
|
Encryption: metabasetest.DefaultEncryption,
|
||||||
},
|
},
|
||||||
Version: -1,
|
Version: -1,
|
||||||
ErrClass: &metabase.ErrConflict,
|
ErrClass: &metabase.ErrObjectAlreadyExists,
|
||||||
ErrText: "object already exists",
|
|
||||||
}.Check(ctx, t, db)
|
}.Check(ctx, t, db)
|
||||||
|
|
||||||
metabasetest.Verify{
|
metabasetest.Verify{
|
||||||
|
@ -19,6 +19,9 @@ import (
|
|||||||
// Error is the default error for metabase.
|
// Error is the default error for metabase.
|
||||||
var Error = errs.Class("metabase")
|
var Error = errs.Class("metabase")
|
||||||
|
|
||||||
|
// ErrObjectAlreadyExists is used to indicate that object already exists.
|
||||||
|
var ErrObjectAlreadyExists = errs.Class("object already exists")
|
||||||
|
|
||||||
// Common constants for segment keys.
|
// Common constants for segment keys.
|
||||||
const (
|
const (
|
||||||
Delimiter = '/'
|
Delimiter = '/'
|
||||||
|
@ -8,9 +8,12 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
pgxerrcode "github.com/jackc/pgerrcode"
|
||||||
|
|
||||||
"storj.io/common/storj"
|
"storj.io/common/storj"
|
||||||
"storj.io/common/uuid"
|
"storj.io/common/uuid"
|
||||||
"storj.io/private/dbutil/pgutil"
|
"storj.io/private/dbutil/pgutil"
|
||||||
|
"storj.io/private/dbutil/pgutil/pgerrcode"
|
||||||
"storj.io/private/dbutil/txutil"
|
"storj.io/private/dbutil/txutil"
|
||||||
"storj.io/private/tagsql"
|
"storj.io/private/tagsql"
|
||||||
)
|
)
|
||||||
@ -167,7 +170,9 @@ func (db *DB) FinishMoveObject(ctx context.Context, opts FinishMoveObject) (err
|
|||||||
var segmentsCount int
|
var segmentsCount int
|
||||||
row := db.db.QueryRowContext(ctx, updateObjectsQuery, []byte(opts.NewBucket), opts.NewEncryptedObjectKey, opts.NewEncryptedMetadataKey, opts.NewEncryptedMetadataKeyNonce, opts.ProjectID, []byte(opts.BucketName), opts.ObjectKey, opts.Version, opts.StreamID)
|
row := db.db.QueryRowContext(ctx, updateObjectsQuery, []byte(opts.NewBucket), opts.NewEncryptedObjectKey, opts.NewEncryptedMetadataKey, opts.NewEncryptedMetadataKeyNonce, opts.ProjectID, []byte(opts.BucketName), opts.ObjectKey, opts.Version, opts.StreamID)
|
||||||
if err = row.Scan(&segmentsCount); err != nil {
|
if err = row.Scan(&segmentsCount); err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if code := pgerrcode.FromError(err); code == pgxerrcode.UniqueViolation {
|
||||||
|
return Error.Wrap(ErrObjectAlreadyExists.New(""))
|
||||||
|
} else if errors.Is(err, sql.ErrNoRows) {
|
||||||
return storj.ErrObjectNotFound.New("object not found")
|
return storj.ErrObjectNotFound.New("object not found")
|
||||||
}
|
}
|
||||||
return Error.New("unable to update object: %w", err)
|
return Error.New("unable to update object: %w", err)
|
||||||
|
@ -190,6 +190,28 @@ func TestFinishMoveObject(t *testing.T) {
|
|||||||
metabasetest.Verify{}.Check(ctx, t, db)
|
metabasetest.Verify{}.Check(ctx, t, db)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("object already exists", func(t *testing.T) {
|
||||||
|
defer metabasetest.DeleteAll{}.Check(ctx, t, db)
|
||||||
|
|
||||||
|
moveObjStream := metabasetest.RandObjectStream()
|
||||||
|
metabasetest.CreateObject(ctx, t, db, moveObjStream, 0)
|
||||||
|
|
||||||
|
conflictObjStream := metabasetest.RandObjectStream()
|
||||||
|
conflictObjStream.ProjectID = moveObjStream.ProjectID
|
||||||
|
metabasetest.CreateObject(ctx, t, db, conflictObjStream, 0)
|
||||||
|
|
||||||
|
metabasetest.FinishMoveObject{
|
||||||
|
Opts: metabase.FinishMoveObject{
|
||||||
|
NewBucket: conflictObjStream.BucketName,
|
||||||
|
ObjectStream: moveObjStream,
|
||||||
|
NewEncryptedObjectKey: []byte(conflictObjStream.ObjectKey),
|
||||||
|
NewEncryptedMetadataKeyNonce: testrand.Nonce().Bytes(),
|
||||||
|
NewEncryptedMetadataKey: testrand.Bytes(265),
|
||||||
|
},
|
||||||
|
ErrClass: &metabase.ErrObjectAlreadyExists,
|
||||||
|
}.Check(ctx, t, db)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("object does not exist", func(t *testing.T) {
|
t.Run("object does not exist", func(t *testing.T) {
|
||||||
defer metabasetest.DeleteAll{}.Check(ctx, t, db)
|
defer metabasetest.DeleteAll{}.Check(ctx, t, db)
|
||||||
|
|
||||||
|
@ -278,6 +278,8 @@ func (endpoint *Endpoint) convertMetabaseErr(err error) error {
|
|||||||
return rpcstatus.Error(rpcstatus.NotFound, err.Error())
|
return rpcstatus.Error(rpcstatus.NotFound, err.Error())
|
||||||
case metabase.ErrInvalidRequest.Has(err):
|
case metabase.ErrInvalidRequest.Has(err):
|
||||||
return rpcstatus.Error(rpcstatus.InvalidArgument, err.Error())
|
return rpcstatus.Error(rpcstatus.InvalidArgument, err.Error())
|
||||||
|
case metabase.ErrObjectAlreadyExists.Has(err):
|
||||||
|
return rpcstatus.Error(rpcstatus.AlreadyExists, err.Error())
|
||||||
default:
|
default:
|
||||||
endpoint.log.Error("internal", zap.Error(err))
|
endpoint.log.Error("internal", zap.Error(err))
|
||||||
return rpcstatus.Error(rpcstatus.Internal, err.Error())
|
return rpcstatus.Error(rpcstatus.Internal, err.Error())
|
||||||
|
Loading…
Reference in New Issue
Block a user