object: handle Error responses and handle errDiskFull. (#1331)

This commit is contained in:
Harshavardhana 2016-04-19 02:42:10 -07:00 committed by Anand Babu (AB) Periasamy
parent 6bc17a3aea
commit e0f8fed011
11 changed files with 77 additions and 202 deletions

View file

@ -83,7 +83,7 @@ const (
ErrMalformedPOSTRequest
ErrSignatureVersionNotSupported
ErrBucketNotEmpty
ErrRootPathFull
ErrStorageFull
ErrObjectExistsAsPrefix
ErrAllAccessDisabled
ErrMalformedPolicy
@ -295,9 +295,9 @@ var errorCodeResponse = map[APIErrorCode]APIError{
Description: "The bucket you tried to delete is not empty.",
HTTPStatusCode: http.StatusConflict,
},
ErrRootPathFull: {
Code: "RootPathFull",
Description: "Root path has reached its minimum free disk threshold. Please delete few objects to proceed.",
ErrStorageFull: {
Code: "StorageFull",
Description: "Storage backend has reached its minimum free disk threshold. Please delete few objects to proceed.",
HTTPStatusCode: http.StatusInternalServerError,
},
ErrObjectExistsAsPrefix: {

View file

@ -562,8 +562,8 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
if err != nil {
errorIf(err.Trace(), "PutObject failed.", nil)
switch err.ToGoError().(type) {
case RootPathFull:
writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case StorageFull:
writeErrorResponse(w, r, ErrStorageFull, r.URL.Path)
case BucketNotFound:
writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case BucketNameInvalid:

2
fs.go
View file

@ -111,7 +111,7 @@ func checkDiskFree(diskPath string, minFreeDisk int64) (err error) {
// space used for journalling, inodes etc.
availableDiskSpace := (float64(di.Free) / (float64(di.Total) - (0.05 * float64(di.Total)))) * 100
if int64(availableDiskSpace) <= minFreeDisk {
return errDiskPathFull
return errDiskFull
}
// Success.

View file

@ -29,6 +29,16 @@ const (
b = "bytes="
)
// InvalidRange - invalid range
type InvalidRange struct {
Start int64
Length int64
}
func (e InvalidRange) Error() string {
return fmt.Sprintf("Invalid range start:%d length:%d", e.Start, e.Length)
}
// HttpRange specifies the byte range to be sent to the client.
type httpRange struct {
start, length, size int64

View file

@ -54,6 +54,8 @@ func splitNetPath(networkPath string) (netAddr, netPath string) {
// disks as well.
func toStorageErr(err error) error {
switch err.Error() {
case errDiskFull.Error():
return errDiskFull
case errVolumeNotFound.Error():
return errVolumeNotFound
case errVolumeExists.Error():

View file

@ -250,6 +250,9 @@ func (o objectAPI) NewMultipartUpload(bucket, object string) (string, *probe.Err
if e == errVolumeNotFound {
e = o.storage.MakeVol(minioMetaVolume)
if e != nil {
if e == errDiskFull {
return "", probe.NewError(StorageFull{})
}
return "", probe.NewError(e)
}
}
@ -272,6 +275,9 @@ func (o objectAPI) NewMultipartUpload(bucket, object string) (string, *probe.Err
return "", probe.NewError(e)
}
} else {
if e == errDiskFull {
return "", probe.NewError(StorageFull{})
}
return "", probe.NewError(e)
}
return uploadID, nil
@ -320,8 +326,10 @@ func (o objectAPI) PutObjectPart(bucket, object, uploadID string, partID int, si
} else if e == errIsNotRegular {
return "", probe.NewError(ObjectExistsAsPrefix{
Bucket: bucket,
Prefix: object,
Object: object,
})
} else if e == errDiskFull {
return "", probe.NewError(StorageFull{})
}
return "", probe.NewError(e)
}
@ -336,6 +344,9 @@ func (o objectAPI) PutObjectPart(bucket, object, uploadID string, partID int, si
if size > 0 {
if _, e = io.CopyN(multiWriter, data, size); e != nil {
safeCloseAndRemove(fileWriter)
if e == io.ErrUnexpectedEOF {
return "", probe.NewError(IncompleteBody{})
}
return "", probe.NewError(e)
}
} else {
@ -468,8 +479,10 @@ func (o objectAPI) CompleteMultipartUpload(bucket string, object string, uploadI
} else if e == errIsNotRegular {
return "", probe.NewError(ObjectExistsAsPrefix{
Bucket: bucket,
Prefix: object,
Object: object,
})
} else if e == errDiskFull {
return "", probe.NewError(StorageFull{})
}
return "", probe.NewError(e)
}

View file

@ -48,6 +48,8 @@ func (o objectAPI) MakeBucket(bucket string) *probe.Error {
if e := o.storage.MakeVol(bucket); e != nil {
if e == errVolumeExists {
return probe.NewError(BucketExists{Bucket: bucket})
} else if e == errDiskFull {
return probe.NewError(StorageFull{})
}
return probe.NewError(e)
}
@ -209,8 +211,10 @@ func (o objectAPI) PutObject(bucket string, object string, size int64, data io.R
} else if e == errIsNotRegular {
return "", probe.NewError(ObjectExistsAsPrefix{
Bucket: bucket,
Prefix: object,
Object: object,
})
} else if e == errDiskFull {
return "", probe.NewError(StorageFull{})
}
return "", probe.NewError(e)
}
@ -225,6 +229,9 @@ func (o objectAPI) PutObject(bucket string, object string, size int64, data io.R
if size > 0 {
if _, e = io.CopyN(multiWriter, data, size); e != nil {
safeCloseAndRemove(fileWriter)
if e == io.ErrUnexpectedEOF {
return "", probe.NewError(IncompleteBody{})
}
return "", probe.NewError(e)
}
} else {

View file

@ -18,112 +18,54 @@ package main
import "fmt"
// InvalidArgument invalid argument
type InvalidArgument struct{}
// StorageFull storage ran out of space
type StorageFull struct{}
func (e InvalidArgument) Error() string {
return "Invalid argument"
func (e StorageFull) Error() string {
return "Storage reached its minimum free disk threshold."
}
// UnsupportedFilesystem unsupported filesystem type
type UnsupportedFilesystem struct {
Type string
}
func (e UnsupportedFilesystem) Error() string {
return "Unsupported filesystem: " + e.Type
}
// RootPathFull root path out of space
type RootPathFull struct {
Path string
}
func (e RootPathFull) Error() string {
return "Root path " + e.Path + " reached its minimum free disk threshold."
// GenericError - generic object layer error.
type GenericError struct {
Bucket string
Object string
}
// BucketNotFound bucket does not exist
type BucketNotFound struct {
Bucket string
}
type BucketNotFound GenericError
func (e BucketNotFound) Error() string {
return "Bucket not found: " + e.Bucket
}
// BucketNotEmpty bucket is not empty
type BucketNotEmpty struct {
Bucket string
}
type BucketNotEmpty GenericError
func (e BucketNotEmpty) Error() string {
return "Bucket not empty: " + e.Bucket
}
// ObjectNotFound object does not exist
type ObjectNotFound struct {
Bucket string
Object string
}
type ObjectNotFound GenericError
func (e ObjectNotFound) Error() string {
return "Object not found: " + e.Bucket + "#" + e.Object
}
// ObjectExistsAsPrefix object already exists with a requested prefix.
type ObjectExistsAsPrefix struct {
Bucket string
Prefix string
}
type ObjectExistsAsPrefix GenericError
func (e ObjectExistsAsPrefix) Error() string {
return "Object exists on : " + e.Bucket + " as prefix " + e.Prefix
}
// ObjectCorrupted object found to be corrupted
type ObjectCorrupted struct {
Object string
}
func (e ObjectCorrupted) Error() string {
return "Object found corrupted: " + e.Object
return "Object exists on : " + e.Bucket + " as prefix " + e.Object
}
// BucketExists bucket exists
type BucketExists struct {
Bucket string
}
type BucketExists GenericError
func (e BucketExists) Error() string {
return "Bucket exists: " + e.Bucket
}
// CorruptedBackend backend found to be corrupted
type CorruptedBackend struct {
Backend string
}
func (e CorruptedBackend) Error() string {
return "Corrupted backend: " + e.Backend
}
// NotImplemented function not implemented
type NotImplemented struct {
Function string
}
func (e NotImplemented) Error() string {
return "Not implemented: " + e.Function
}
// InvalidDisksArgument invalid number of disks per node
type InvalidDisksArgument struct{}
func (e InvalidDisksArgument) Error() string {
return "Invalid number of disks per node"
}
// BadDigest - Content-MD5 you specified did not match what we received.
type BadDigest struct {
ExpectedMD5 string
@ -143,8 +85,7 @@ func (e UnsupportedDelimiter) Error() string {
return fmt.Sprintf("delimiter '%s' is not supported. Only '/' is supported", e.Delimiter)
}
// InvalidUploadIDKeyCombination - invalid upload id and key marker
// combination.
// InvalidUploadIDKeyCombination - invalid upload id and key marker combination.
type InvalidUploadIDKeyCombination struct {
UploadIDMarker, KeyMarker string
}
@ -162,132 +103,41 @@ func (e InvalidMarkerPrefixCombination) Error() string {
return fmt.Sprintf("Invalid combination of marker '%s' and prefix '%s'", e.Marker, e.Prefix)
}
// InternalError - generic internal error
type InternalError struct{}
// BackendError - generic disk backend error
type BackendError struct {
Path string
}
// BackendCorrupted - path has corrupted data
type BackendCorrupted BackendError
// APINotImplemented - generic API not implemented error
type APINotImplemented struct {
API string
}
// GenericBucketError - generic bucket error
type GenericBucketError struct {
Bucket string
}
// BucketPolicyNotFound - no bucket policy found.
type BucketPolicyNotFound GenericBucketError
type BucketPolicyNotFound GenericError
func (e BucketPolicyNotFound) Error() string {
return "No bucket policy found for bucket: " + e.Bucket
}
// GenericObjectError - generic object error
type GenericObjectError struct {
Bucket string
Object string
}
// ImplementationError - generic implementation error
type ImplementationError struct {
Bucket string
Object string
Err error
}
/// Bucket related errors
// BucketNameInvalid - bucketname provided is invalid
type BucketNameInvalid GenericBucketError
/// Object related errors
// ObjectNameInvalid - object name provided is invalid
type ObjectNameInvalid GenericObjectError
// Return string an error formatted as the given text
func (e ImplementationError) Error() string {
error := ""
if e.Bucket != "" {
error = error + "Bucket: " + e.Bucket + " "
}
if e.Object != "" {
error = error + "Object: " + e.Object + " "
}
error = error + "Error: " + e.Err.Error()
return error
}
// EmbedError - wrapper function for error object
func EmbedError(bucket, object string, err error) ImplementationError {
return ImplementationError{
Bucket: bucket,
Object: object,
Err: err,
}
}
// Return string an error formatted as the given text
func (e InternalError) Error() string {
return "Internal error occured"
}
// Return string an error formatted as the given text
func (e APINotImplemented) Error() string {
return "Api not implemented: " + e.API
}
type BucketNameInvalid GenericError
// Return string an error formatted as the given text
func (e BucketNameInvalid) Error() string {
return "Bucket name invalid: " + e.Bucket
}
/// Object related errors
// ObjectNameInvalid - object name provided is invalid
type ObjectNameInvalid GenericError
// Return string an error formatted as the given text
func (e ObjectNameInvalid) Error() string {
return "Object name invalid: " + e.Bucket + "#" + e.Object
}
// IncompleteBody You did not provide the number of bytes specified by the Content-Length HTTP header
type IncompleteBody GenericObjectError
type IncompleteBody GenericError
// Return string an error formatted as the given text
func (e IncompleteBody) Error() string {
return e.Bucket + "#" + e.Object + "has incomplete body"
}
// Return string an error formatted as the given text
func (e BackendCorrupted) Error() string {
return "Backend corrupted: " + e.Path
}
// OperationNotPermitted - operation not permitted
type OperationNotPermitted struct {
Op string
Reason string
}
func (e OperationNotPermitted) Error() string {
return "Operation " + e.Op + " not permitted for reason: " + e.Reason
}
// InvalidRange - invalid range
type InvalidRange struct {
Start int64
Length int64
}
func (e InvalidRange) Error() string {
return fmt.Sprintf("Invalid range start:%d length:%d", e.Start, e.Length)
}
/// Multipart related errors
// MalformedUploadID malformed upload id.
@ -323,10 +173,3 @@ type InvalidPartOrder struct {
func (e InvalidPartOrder) Error() string {
return "Invalid part order sent for " + e.UploadID
}
// MalformedXML invalid xml format
type MalformedXML struct{}
func (e MalformedXML) Error() string {
return "Malformed XML"
}

View file

@ -460,8 +460,8 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
md5Sum, err := api.ObjectAPI.PutObject(bucket, object, size, readCloser, metadata)
if err != nil {
switch err.ToGoError().(type) {
case RootPathFull:
writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case StorageFull:
writeErrorResponse(w, r, ErrStorageFull, r.URL.Path)
case BucketNotFound:
writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case BucketNameInvalid:
@ -684,8 +684,8 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
return
}
switch e.(type) {
case RootPathFull:
writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case StorageFull:
writeErrorResponse(w, r, ErrStorageFull, r.URL.Path)
case BucketNotFound:
writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case BucketNameInvalid:
@ -738,8 +738,8 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
if err != nil {
errorIf(err.Trace(), "NewMultipartUpload failed.", nil)
switch err.ToGoError().(type) {
case RootPathFull:
writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case StorageFull:
writeErrorResponse(w, r, ErrStorageFull, r.URL.Path)
case BucketNameInvalid:
writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case BucketNotFound:
@ -856,8 +856,8 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
return
}
switch e.(type) {
case RootPathFull:
writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case StorageFull:
writeErrorResponse(w, r, ErrStorageFull, r.URL.Path)
case InvalidUploadID:
writeErrorResponse(w, r, ErrNoSuchUpload, r.URL.Path)
case BadDigest:

View file

@ -18,8 +18,8 @@ package main
import "errors"
// errDiskPathFull - cannot create volume or files when disk is full.
var errDiskPathFull = errors.New("Disk path full.")
// errDiskFull - cannot create volume or files when disk is full.
var errDiskFull = errors.New("Disk path full.")
// errFileNotFound - cannot find the file.
var errFileNotFound = errors.New("File not found.")

View file

@ -413,8 +413,8 @@ func writeWebErrorResponse(w http.ResponseWriter, err error) {
// Convert error type to api error code.
var apiErrCode APIErrorCode
switch err.(type) {
case RootPathFull:
apiErrCode = ErrRootPathFull
case StorageFull:
apiErrCode = ErrStorageFull
case BucketNotFound:
apiErrCode = ErrNoSuchBucket
case BucketNameInvalid: