mirror of
https://github.com/versity/versitygw.git
synced 2026-04-30 17:25:43 +00:00
feat: add new ErrNoSpaceLeftOnDevice API error for ENOSPC errors
Add a new non-AWS error ErrNoSpaceLeftOnDevice (HTTP 507 Insufficient Storage) to s3err. Update all call sites in the posix backend that could return ENOSPC and return the new error when the underlying filesystem has no space remaining. Fixes #2093
This commit is contained in:
@@ -20,6 +20,9 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/versity/versitygw/s3err"
|
||||
)
|
||||
|
||||
// SideCar is a metadata storer that uses sidecar files to store metadata.
|
||||
@@ -71,12 +74,18 @@ func (s SideCar) StoreAttribute(_ *os.File, bucket, object, attribute string, va
|
||||
}
|
||||
err := os.MkdirAll(metadir, 0777)
|
||||
if err != nil {
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return fmt.Errorf("failed to create metadata directory: %v", err)
|
||||
}
|
||||
|
||||
attr := filepath.Join(metadir, attribute)
|
||||
tempfile, err := os.CreateTemp(metadir, attribute)
|
||||
if err != nil {
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return fmt.Errorf("failed to create temporary file: %v", err)
|
||||
}
|
||||
defer os.Remove(tempfile.Name())
|
||||
@@ -84,6 +93,9 @@ func (s SideCar) StoreAttribute(_ *os.File, bucket, object, attribute string, va
|
||||
_, err = tempfile.Write(value)
|
||||
if err != nil {
|
||||
tempfile.Close()
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return fmt.Errorf("failed to write attribute: %v", err)
|
||||
}
|
||||
|
||||
@@ -176,6 +188,9 @@ func (s SideCar) RenameObject(bucket, oldObject, newObject string) error {
|
||||
newPath := filepath.Join(s.dir, bucket, newObject)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(newPath), 0777); err != nil {
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return fmt.Errorf("create parent for renamed metadata: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ func (x XattrMeta) StoreAttribute(f *os.File, bucket, object, attribute string,
|
||||
if errors.Is(err, syscall.EROFS) {
|
||||
return s3err.GetAPIError(s3err.ErrMethodNotAllowed)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -64,6 +67,9 @@ func (x XattrMeta) StoreAttribute(f *os.File, bucket, object, attribute string,
|
||||
if errors.Is(err, syscall.EROFS) {
|
||||
return s3err.GetAPIError(s3err.ErrMethodNotAllowed)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -1989,6 +1989,9 @@ func (p *Posix) CompleteMultipartUploadWithCopy(ctx context.Context, input *s3.C
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return res, "", s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return res, "", s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return res, "", fmt.Errorf("open temp file: %w", err)
|
||||
}
|
||||
defer f.cleanup()
|
||||
@@ -2044,6 +2047,9 @@ func (p *Posix) CompleteMultipartUploadWithCopy(ctx context.Context, input *s3.C
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return res, "", s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return res, "", s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return res, "", fmt.Errorf("copy part %v: %v", part.PartNumber, err)
|
||||
}
|
||||
}
|
||||
@@ -2877,6 +2883,9 @@ func (p *Posix) UploadPartWithPostFunc(ctx context.Context, input *s3.UploadPart
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return nil, fmt.Errorf("open temp file: %w", err)
|
||||
}
|
||||
defer f.cleanup()
|
||||
@@ -2989,6 +2998,9 @@ func (p *Posix) UploadPartWithPostFunc(ctx context.Context, input *s3.UploadPart
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
// Return the error itself, if it's an 's3err.APIError'
|
||||
if _, ok := err.(s3err.APIError); ok {
|
||||
return nil, err
|
||||
@@ -3253,6 +3265,9 @@ func (p *Posix) UploadPartCopy(ctx context.Context, upi *s3.UploadPartCopyInput)
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return s3response.CopyPartResult{}, s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3response.CopyPartResult{}, s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return s3response.CopyPartResult{}, fmt.Errorf("open temp file: %w", err)
|
||||
}
|
||||
defer f.cleanup()
|
||||
@@ -3298,6 +3313,9 @@ func (p *Posix) UploadPartCopy(ctx context.Context, upi *s3.UploadPartCopyInput)
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return s3response.CopyPartResult{}, s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3response.CopyPartResult{}, s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return s3response.CopyPartResult{}, fmt.Errorf("copy part data: %w", err)
|
||||
}
|
||||
|
||||
@@ -3494,6 +3512,9 @@ func (p *Posix) PutObjectWithPostFunc(ctx context.Context, po s3response.PutObje
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return s3response.PutObjectOutput{}, err
|
||||
}
|
||||
|
||||
@@ -3622,6 +3643,9 @@ func (p *Posix) PutObjectWithPostFunc(ctx context.Context, po s3response.PutObje
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
return s3response.PutObjectOutput{}, fmt.Errorf("open temp file: %w", err)
|
||||
}
|
||||
defer f.cleanup()
|
||||
@@ -3646,6 +3670,9 @@ func (p *Posix) PutObjectWithPostFunc(ctx context.Context, po s3response.PutObje
|
||||
if errors.Is(err, syscall.EDQUOT) {
|
||||
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrQuotaExceeded)
|
||||
}
|
||||
if errors.Is(err, syscall.ENOSPC) {
|
||||
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
||||
}
|
||||
// Return the error itself, if it's an 's3err.APIError'
|
||||
if _, ok := err.(s3err.APIError); ok {
|
||||
return s3response.PutObjectOutput{}, err
|
||||
|
||||
@@ -199,6 +199,7 @@ const (
|
||||
ErrQuotaExceeded
|
||||
ErrVersioningNotConfigured
|
||||
ErrACLsDisabled
|
||||
ErrNoSpaceLeftOnDevice
|
||||
|
||||
// Admin api errors
|
||||
ErrAdminAccessDenied
|
||||
@@ -904,6 +905,11 @@ var errorCodeResponse = map[ErrorCode]APIError{
|
||||
Description: "Access control lists are disabled at the gateway level",
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
},
|
||||
ErrNoSpaceLeftOnDevice: {
|
||||
Code: "InsufficientStorage",
|
||||
Description: "No space left on device.",
|
||||
HTTPStatusCode: http.StatusInsufficientStorage,
|
||||
},
|
||||
|
||||
// Admin api errors
|
||||
ErrAdminAccessDenied: {
|
||||
|
||||
Reference in New Issue
Block a user