1
0
mirror of https://github.com/openshift/image-registry.git synced 2026-02-05 09:45:55 +01:00

metrics: report filesystem errors

to help customers detect and solve errors, we specifically report
metrics on a few filesystem specific errors.

we have seen customers configure the registry with a read-only
filesystem without noticing until it's too late. more specifically, when
using the registry only as a pull-through cache, a read-only filesystem
will be imperceptible to clients unless the upstream registry
experiences an outage, then it'll be too late to fix the cache.

the file too large (EFBIG) and device out of space (ENOSPC) errors were
added just in case. there have not been (so far) reports of customers
silently running into this errors on their PVCs.
This commit is contained in:
Flavian Missi
2024-09-25 15:52:41 +02:00
parent 8317f5e28b
commit c14ef8b7f5

View File

@@ -1,13 +1,33 @@
package metrics
import storagedriver "github.com/distribution/distribution/v3/registry/storage/driver"
import (
"errors"
"io/fs"
"syscall"
storagedriver "github.com/distribution/distribution/v3/registry/storage/driver"
)
const (
errCodeUnsupportedMethod = "UNSUPPORTED_METHOD"
errCodePathNotFound = "PATH_NOT_FOUND"
errCodeInvalidPath = "INVALID_PATH"
errCodeInvalidOffset = "INVALID_OFFSET"
errCodeReadOnlyFS = "READ_ONLY_FILESYSTEM"
errCodeFileTooLarge = "FILE_TOO_LARGE"
errCodeDeviceOutOfSpace = "DEVICE_OUT_OF_SPACE"
errCodeUnknown = "UNKNOWN"
// errnoEFBIG represents a file too large error.
// See `man errno` for more.
errnoEFBIG = 27
// errnoENOSPC represents a device out of space error.
// See `man errno` for more.
errnoENOSPC = 28
// errnoEROFS represents the syscall error number returned when an attempt
// to write to a read-only filesystem was made.
// See `man errno` for more.
errnoEROFS = 30
)
func storageErrorCode(err error) string {
@@ -20,7 +40,38 @@ func storageErrorCode(err error) string {
return errCodeInvalidPath
case storagedriver.InvalidOffsetError:
return errCodeInvalidOffset
case storagedriver.Error:
var perr *fs.PathError
if !errors.As(actual.Enclosed, &perr) {
return errCodeUnknown
}
unwrapped := perr.Unwrap()
if unwrapped == nil {
return errCodeUnknown
}
errno, ok := unwrapped.(syscall.Errno)
if !ok {
return errCodeUnknown
}
return syscallErrnoToErrorCode(errno)
}
return errCodeUnknown
}
// syscallErrnoToErrorCode transforms the errno in an unwrapped fs.PathErr into
// a storage error code used to report metrics.
//
// if the given errno is not known to us, return errCodeUnknown.
func syscallErrnoToErrorCode(errno syscall.Errno) string {
switch errno {
case errnoEROFS:
return errCodeReadOnlyFS
case errnoEFBIG:
return errCodeFileTooLarge
case errnoENOSPC:
return errCodeDeviceOutOfSpace
}
return errCodeUnknown
}