Merged master into NFSSVC-26

This commit is contained in:
Pavel Korotkov 2020-07-22 19:06:43 +03:00
commit 9662fb0019
15 changed files with 3877 additions and 23 deletions

17
auth/errors.go Normal file
View file

@ -0,0 +1,17 @@
package auth
import "fmt"
const (
// Minimum length for MinIO access key.
accessKeyMinLen = 3
// Minimum length for MinIO secret key for both server and gateway mode.
secretKeyMinLen = 8
)
// Common errors generated for access and secret key validation.
var (
ErrInvalidAccessKeyLength = fmt.Errorf("access key must be minimum %v or more characters long", accessKeyMinLen)
ErrInvalidSecretKeyLength = fmt.Errorf("secret key must be minimum %v or more characters long", secretKeyMinLen)
)

View file

@ -20,5 +20,7 @@ func attachNewUserAuth(router *mux.Router, center *auth.Center, log *zap.Logger)
})
}
// TODO: should not be used for all routes,
// only for API
router.Use(uamw)
}

View file

@ -39,6 +39,9 @@ const (
defaultKeepaliveTime = 10 * time.Second
defaultKeepaliveTimeout = 10 * time.Second
defaultMaxClientsCount = 100
defaultMaxClientsDeadline = time.Second * 30
)
const ( // settings
@ -69,6 +72,10 @@ const ( // settings
cfgRequestTimeout = "request_timeout"
cfgRebalanceTimer = "rebalance_timer"
// MaxClients
cfgMaxClientsCount = "max_clients_count"
cfgMaxClientsDeadline = "max_clients_deadline"
// gRPC
cfgGRPCVerbose = "verbose"
@ -108,14 +115,16 @@ func fetchAuthCenter(l *zap.Logger, v *viper.Viper) (*auth.Center, error) {
uapk := v.GetString(cfgUserAuthPrivateKey)
userAuthPrivateKey, err = auth.ReadRSAPrivateKeyFromPEMFile(uapk)
if err != nil {
return nil, errors.Wrap(err, "could not load UserAuth private key")
return nil, errors.Wrapf(err, "could not load UserAuth private key %q", uapk)
}
center, err := auth.NewCenter(l)
if err != nil {
return nil, errors.Wrap(err, "failed to create auth center")
}
center.SetUserAuthKeys(userAuthPrivateKey)
center.SetNeoFSKeys(neofsPrivateKey)
if err = center.SetNeoFSKeys(neofsPrivateKey); err != nil {
return nil, err
}
return center, nil
}
@ -168,6 +177,9 @@ func newSettings() *viper.Viper {
flags.Duration(cfgConnectTimeout, defaultConnectTimeout, "set gRPC connect timeout")
flags.Duration(cfgRebalanceTimer, defaultRebalanceTimer, "set gRPC connection rebalance timer")
flags.Int(cfgMaxClientsCount, defaultMaxClientsCount, "set max-clients count")
flags.Duration(cfgMaxClientsDeadline, defaultMaxClientsDeadline, "set max-clients deadline")
ttl := flags.DurationP(cfgConnectionTTL, "t", defaultTTL, "set gRPC connection time to live")
flags.String(cfgListenAddress, "0.0.0.0:8080", "set address to listen")

View file

@ -8,14 +8,17 @@ import (
"time"
"github.com/minio/minio/auth"
minio "github.com/minio/minio/legacy"
"github.com/minio/minio/legacy/config"
"github.com/minio/minio/neofs/api"
"github.com/minio/minio/neofs/api/handler"
"github.com/minio/minio/neofs/layer"
"github.com/minio/minio/neofs/metrics"
"github.com/minio/minio/neofs/pool"
"github.com/spf13/viper"
"go.uber.org/zap"
"google.golang.org/grpc/keepalive"
// should be removed in future
"github.com/minio/minio/legacy"
"github.com/minio/minio/legacy/config"
)
type (
@ -25,13 +28,16 @@ type (
log *zap.Logger
cfg *viper.Viper
tls *tlsConfig
obj minio.ObjectLayer
obj legacy.ObjectLayer
api api.Handler
conTimeout time.Duration
reqTimeout time.Duration
reBalance time.Duration
maxClients api.MaxClients
webDone chan struct{}
wrkDone chan struct{}
}
@ -47,10 +53,14 @@ func newApp(l *zap.Logger, v *viper.Viper) *App {
err error
cli pool.Pool
tls *tlsConfig
obj minio.ObjectLayer
caller api.Handler
obj legacy.ObjectLayer
reBalance = defaultRebalanceTimer
conTimeout = defaultConnectTimeout
reqTimeout = defaultRequestTimeout
maxClientsCount = defaultMaxClientsCount
maxClientsDeadline = defaultMaxClientsDeadline
)
center, err := fetchAuthCenter(l, v)
@ -60,6 +70,10 @@ func newApp(l *zap.Logger, v *viper.Viper) *App {
uid := center.GetOwnerID()
wif := center.GetWIFString()
if caller, err = handler.New(); err != nil {
l.Fatal("could not initialize API handler", zap.Error(err))
}
if v.IsSet(cfgTLSKeyFile) && v.IsSet(cfgTLSCertFile) {
tls = &tlsConfig{
KeyFile: v.GetString(cfgTLSKeyFile),
@ -75,6 +89,14 @@ func newApp(l *zap.Logger, v *viper.Viper) *App {
reqTimeout = v
}
if v := v.GetInt(cfgMaxClientsCount); v > 0 {
maxClientsCount = v
}
if v := v.GetDuration(cfgMaxClientsDeadline); v > 0 {
maxClientsDeadline = v
}
poolConfig := &pool.Config{
ConnectionTTL: v.GetDuration(cfgConnectionTTL),
ConnectTimeout: v.GetDuration(cfgConnectTimeout),
@ -133,12 +155,15 @@ func newApp(l *zap.Logger, v *viper.Viper) *App {
cfg: v,
obj: obj,
tls: tls,
api: caller,
webDone: make(chan struct{}, 1),
wrkDone: make(chan struct{}, 1),
reBalance: reBalance,
maxClients: api.NewMaxClientsMiddleware(maxClientsCount, maxClientsDeadline),
conTimeout: conTimeout,
reqTimeout: reqTimeout,
}
@ -179,23 +204,8 @@ func (a *App) Server(ctx context.Context) {
attachMetrics(router, a.cfg, a.log)
attachProfiler(router, a.cfg, a.log)
{ // Example for metrics.Middleware and metrics.APIStats
r := router.PathPrefix("/test-metrics").Subrouter()
r.Handle("/foo", metrics.APIStats("foo", func(w http.ResponseWriter, r *http.Request) {
// do something
}))
m := r.PathPrefix("/bar").Subrouter()
m.Use(metrics.Middleware)
m.Handle("", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// do something
}))
}
// Attach S3 API:
r := router.PathPrefix(minio.SlashSeparator).Subrouter()
r.Use(metrics.Middleware)
minio.AttachS3API(r, a.obj, a.log)
api.Attach(router, a.maxClients, a.api)
// Use mux.Router as http.Handler
srv.Handler = router

View file

@ -0,0 +1,63 @@
package crypto
import "fmt"
// Error is the generic type for any error happening during decrypting
// an object. It indicates that the object itself or its metadata was
// modified accidentally or maliciously.
type Error struct {
err error
}
// Errorf - formats according to a format specifier and returns
// the string as a value that satisfies error of type crypto.Error
func Errorf(format string, a ...interface{}) error {
return Error{err: fmt.Errorf(format, a...)}
}
// Unwrap the internal error.
func (e Error) Unwrap() error { return e.err }
// Error 'error' compatible method.
func (e Error) Error() string {
if e.err == nil {
return "crypto: cause <nil>"
}
return e.err.Error()
}
var (
// ErrInvalidEncryptionMethod indicates that the specified SSE encryption method
// is not supported.
ErrInvalidEncryptionMethod = Errorf("The encryption method is not supported")
// ErrInvalidCustomerAlgorithm indicates that the specified SSE-C algorithm
// is not supported.
ErrInvalidCustomerAlgorithm = Errorf("The SSE-C algorithm is not supported")
// ErrMissingCustomerKey indicates that the HTTP headers contains no SSE-C client key.
ErrMissingCustomerKey = Errorf("The SSE-C request is missing the customer key")
// ErrMissingCustomerKeyMD5 indicates that the HTTP headers contains no SSE-C client key
// MD5 checksum.
ErrMissingCustomerKeyMD5 = Errorf("The SSE-C request is missing the customer key MD5")
// ErrInvalidCustomerKey indicates that the SSE-C client key is not valid - e.g. not a
// base64-encoded string or not 256 bits long.
ErrInvalidCustomerKey = Errorf("The SSE-C client key is invalid")
// ErrSecretKeyMismatch indicates that the provided secret key (SSE-C client key / SSE-S3 KMS key)
// does not match the secret key used during encrypting the object.
ErrSecretKeyMismatch = Errorf("The secret key does not match the secret key used during upload")
// ErrCustomerKeyMD5Mismatch indicates that the SSE-C key MD5 does not match the
// computed MD5 sum. This means that the client provided either the wrong key for
// a certain MD5 checksum or the wrong MD5 for a certain key.
ErrCustomerKeyMD5Mismatch = Errorf("The provided SSE-C key MD5 does not match the computed MD5 of the SSE-C key")
// ErrIncompatibleEncryptionMethod indicates that both SSE-C headers and SSE-S3 headers were specified, and are incompatible
// The client needs to remove the SSE-S3 header or the SSE-C headers
ErrIncompatibleEncryptionMethod = Errorf("Server side encryption specified with both SSE-C and SSE-S3 headers")
// ErrKMSAuthLogin is raised when there is a failure authenticating to KMS
ErrKMSAuthLogin = Errorf("Vault service did not return auth info")
)

1964
neofs/api/errors.go Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,501 @@
package handler
import (
"net/http"
"github.com/minio/minio/neofs/api"
)
type handler struct{}
var _ api.Handler = (*handler)(nil)
func New() (api.Handler, error) { return new(handler), nil }
func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) CopyObjectPartHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) ListObjectPartsHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) NewMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutObjectACLHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) SelectObjectContentHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetObjectLegalHoldHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutObjectRetentionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutObjectLegalHoldHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketEncryptionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketACLHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketWebsiteHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketAccelerateHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketRequestPaymentHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketLoggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketReplicationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteBucketWebsiteHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketObjectLockConfigHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketVersioningHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) ListenBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) ListObjectsV2MHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) ListBucketObjectVersionsHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketEncryptionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketObjectLockConfigHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketVersioningHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteBucketEncryptionHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}
func (h *handler) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
api.WriteErrorResponse(r.Context(), w, api.Error{
Code: "XNeoFSUnimplemented",
Description: "implement me",
HTTPStatusCode: http.StatusNotImplemented,
}, r.URL)
}

56
neofs/api/max-clients.go Normal file
View file

@ -0,0 +1,56 @@
package api
import (
"net/http"
"time"
)
type (
MaxClients interface {
Handle(http.HandlerFunc) http.HandlerFunc
}
maxClients struct {
pool chan struct{}
timeout time.Duration
}
)
const defaultRequestDeadline = time.Second * 30
func NewMaxClientsMiddleware(count int, timeout time.Duration) MaxClients {
if timeout <= 0 {
timeout = defaultRequestDeadline
}
return &maxClients{
pool: make(chan struct{}, count),
timeout: timeout,
}
}
func (m *maxClients) Handle(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if m.pool == nil {
f.ServeHTTP(w, r)
return
}
deadline := time.NewTimer(m.timeout)
defer deadline.Stop()
select {
case m.pool <- struct{}{}:
defer func() { <-m.pool }()
f.ServeHTTP(w, r)
case <-deadline.C:
// Send a http timeout message
WriteErrorResponse(r.Context(), w,
errorCodes.ToAPIErr(ErrOperationMaxedOut),
r.URL)
return
case <-r.Context().Done():
return
}
}
}

474
neofs/api/object-errors.go Normal file
View file

@ -0,0 +1,474 @@
package api
import (
"context"
"errors"
"fmt"
"io"
"path"
)
// Converts underlying storage error. Convenience function written to
// handle all cases where we have known types of errors returned by
// underlying storage layer.
func toObjectErr(err error, params ...string) error {
switch err {
case errVolumeNotFound:
if len(params) >= 1 {
err = BucketNotFound{Bucket: params[0]}
}
case errVolumeNotEmpty:
if len(params) >= 1 {
err = BucketNotEmpty{Bucket: params[0]}
}
case errVolumeExists:
if len(params) >= 1 {
err = BucketExists{Bucket: params[0]}
}
case errDiskFull:
err = StorageFull{}
case errTooManyOpenFiles:
err = SlowDown{}
case errFileAccessDenied:
if len(params) >= 2 {
err = PrefixAccessDenied{
Bucket: params[0],
Object: params[1],
}
}
case errFileParentIsFile:
if len(params) >= 2 {
err = ParentIsObject{
Bucket: params[0],
Object: params[1],
}
}
case errIsNotRegular:
if len(params) >= 2 {
err = ObjectExistsAsDirectory{
Bucket: params[0],
Object: params[1],
}
}
case errFileNotFound:
switch len(params) {
case 2:
err = ObjectNotFound{
Bucket: params[0],
Object: params[1],
}
case 3:
err = InvalidUploadID{
Bucket: params[0],
Object: params[1],
UploadID: params[2],
}
}
case errFileNameTooLong:
if len(params) >= 2 {
err = ObjectNameInvalid{
Bucket: params[0],
Object: params[1],
}
}
case errDataTooLarge:
if len(params) >= 2 {
err = ObjectTooLarge{
Bucket: params[0],
Object: params[1],
}
}
case errDataTooSmall:
if len(params) >= 2 {
err = ObjectTooSmall{
Bucket: params[0],
Object: params[1],
}
}
case errXLReadQuorum:
err = InsufficientReadQuorum{}
case errXLWriteQuorum:
err = InsufficientWriteQuorum{}
case io.ErrUnexpectedEOF, io.ErrShortWrite:
err = IncompleteBody{}
case context.Canceled, context.DeadlineExceeded:
err = IncompleteBody{}
}
return err
}
// SignatureDoesNotMatch - when content md5 does not match with what was sent from client.
type SignatureDoesNotMatch struct{}
func (e SignatureDoesNotMatch) Error() string {
return "The request signature we calculated does not match the signature you provided. Check your key and signing method."
}
// StorageFull storage ran out of space.
type StorageFull struct{}
func (e StorageFull) Error() string {
return "Storage reached its minimum free disk threshold."
}
// SlowDown too many file descriptors open or backend busy .
type SlowDown struct{}
func (e SlowDown) Error() string {
return "Please reduce your request rate"
}
// InsufficientReadQuorum storage cannot satisfy quorum for read operation.
type InsufficientReadQuorum struct{}
func (e InsufficientReadQuorum) Error() string {
return "Storage resources are insufficient for the read operation."
}
// InsufficientWriteQuorum storage cannot satisfy quorum for write operation.
type InsufficientWriteQuorum struct{}
func (e InsufficientWriteQuorum) Error() string {
return "Storage resources are insufficient for the write operation."
}
// GenericError - generic object layer error.
type GenericError struct {
Bucket string
Object string
}
// BucketNotFound bucket does not exist.
type BucketNotFound GenericError
func (e BucketNotFound) Error() string {
return "Bucket not found: " + e.Bucket
}
// BucketAlreadyExists the requested bucket name is not available.
type BucketAlreadyExists GenericError
func (e BucketAlreadyExists) Error() string {
return "The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again."
}
// BucketAlreadyOwnedByYou already owned by you.
type BucketAlreadyOwnedByYou GenericError
func (e BucketAlreadyOwnedByYou) Error() string {
return "Bucket already owned by you: " + e.Bucket
}
// BucketNotEmpty bucket is not empty.
type BucketNotEmpty GenericError
func (e BucketNotEmpty) Error() string {
return "Bucket not empty: " + e.Bucket
}
// ObjectNotFound object does not exist.
type ObjectNotFound GenericError
func (e ObjectNotFound) Error() string {
return "Object not found: " + e.Bucket + "#" + e.Object
}
// ObjectAlreadyExists object already exists.
type ObjectAlreadyExists GenericError
func (e ObjectAlreadyExists) Error() string {
return "Object: " + e.Bucket + "#" + e.Object + " already exists"
}
// ObjectExistsAsDirectory object already exists as a directory.
type ObjectExistsAsDirectory GenericError
func (e ObjectExistsAsDirectory) Error() string {
return "Object exists on : " + e.Bucket + " as directory " + e.Object
}
// PrefixAccessDenied object access is denied.
type PrefixAccessDenied GenericError
func (e PrefixAccessDenied) Error() string {
return "Prefix access is denied: " + e.Bucket + SlashSeparator + e.Object
}
// ParentIsObject object access is denied.
type ParentIsObject GenericError
func (e ParentIsObject) Error() string {
return "Parent is object " + e.Bucket + SlashSeparator + path.Dir(e.Object)
}
// BucketExists bucket exists.
type BucketExists GenericError
func (e BucketExists) Error() string {
return "Bucket exists: " + e.Bucket
}
// UnsupportedDelimiter - unsupported delimiter.
type UnsupportedDelimiter struct {
Delimiter string
}
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.
type InvalidUploadIDKeyCombination struct {
UploadIDMarker, KeyMarker string
}
func (e InvalidUploadIDKeyCombination) Error() string {
return fmt.Sprintf("Invalid combination of uploadID marker '%s' and marker '%s'", e.UploadIDMarker, e.KeyMarker)
}
// InvalidMarkerPrefixCombination - invalid marker and prefix combination.
type InvalidMarkerPrefixCombination struct {
Marker, Prefix string
}
func (e InvalidMarkerPrefixCombination) Error() string {
return fmt.Sprintf("Invalid combination of marker '%s' and prefix '%s'", e.Marker, e.Prefix)
}
// BucketPolicyNotFound - no bucket policy found.
type BucketPolicyNotFound GenericError
func (e BucketPolicyNotFound) Error() string {
return "No bucket policy configuration found for bucket: " + e.Bucket
}
// BucketLifecycleNotFound - no bucket lifecycle found.
type BucketLifecycleNotFound GenericError
func (e BucketLifecycleNotFound) Error() string {
return "No bucket lifecycle configuration found for bucket : " + e.Bucket
}
// BucketSSEConfigNotFound - no bucket encryption found
type BucketSSEConfigNotFound GenericError
func (e BucketSSEConfigNotFound) Error() string {
return "No bucket encryption configuration found for bucket: " + e.Bucket
}
// BucketTaggingNotFound - no bucket tags found
type BucketTaggingNotFound GenericError
func (e BucketTaggingNotFound) Error() string {
return "No bucket tags found for bucket: " + e.Bucket
}
// BucketObjectLockConfigNotFound - no bucket object lock config found
type BucketObjectLockConfigNotFound GenericError
func (e BucketObjectLockConfigNotFound) Error() string {
return "No bucket object lock configuration found for bucket: " + e.Bucket
}
// BucketQuotaConfigNotFound - no bucket quota config found.
type BucketQuotaConfigNotFound GenericError
func (e BucketQuotaConfigNotFound) Error() string {
return "No quota config found for bucket : " + e.Bucket
}
// BucketQuotaExceeded - bucket quota exceeded.
type BucketQuotaExceeded GenericError
func (e BucketQuotaExceeded) Error() string {
return "Bucket quota exceeded for bucket: " + e.Bucket
}
// Bucket related errors.
// BucketNameInvalid - bucketname provided is invalid.
type BucketNameInvalid GenericError
// Error returns 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
// ObjectNameTooLong - object name too long.
type ObjectNameTooLong GenericError
// ObjectNamePrefixAsSlash - object name has a slash as prefix.
type ObjectNamePrefixAsSlash GenericError
// Error returns string an error formatted as the given text.
func (e ObjectNameInvalid) Error() string {
return "Object name invalid: " + e.Bucket + "#" + e.Object
}
// Error returns string an error formatted as the given text.
func (e ObjectNameTooLong) Error() string {
return "Object name too long: " + e.Bucket + "#" + e.Object
}
// Error returns string an error formatted as the given text.
func (e ObjectNamePrefixAsSlash) Error() string {
return "Object name contains forward slash as pefix: " + e.Bucket + "#" + e.Object
}
// AllAccessDisabled All access to this object has been disabled
type AllAccessDisabled GenericError
// Error returns string an error formatted as the given text.
func (e AllAccessDisabled) Error() string {
return "All access to this object has been disabled"
}
// IncompleteBody You did not provide the number of bytes specified by the Content-Length HTTP header.
type IncompleteBody GenericError
// Error returns string an error formatted as the given text.
func (e IncompleteBody) Error() string {
return e.Bucket + "#" + e.Object + "has incomplete body"
}
// InvalidRange - invalid range typed error.
type InvalidRange struct {
OffsetBegin int64
OffsetEnd int64
ResourceSize int64
}
func (e InvalidRange) Error() string {
return fmt.Sprintf("The requested range \"bytes %d-%d/%d\" is not satisfiable.", e.OffsetBegin, e.OffsetEnd, e.ResourceSize)
}
// ObjectTooLarge error returned when the size of the object > max object size allowed (5G) per request.
type ObjectTooLarge GenericError
func (e ObjectTooLarge) Error() string {
return "size of the object greater than what is allowed(5G)"
}
// ObjectTooSmall error returned when the size of the object < what is expected.
type ObjectTooSmall GenericError
func (e ObjectTooSmall) Error() string {
return "size of the object less than what is expected"
}
// OperationTimedOut - a timeout occurred.
type OperationTimedOut struct {
}
func (e OperationTimedOut) Error() string {
return "Operation timed out"
}
// Multipart related errors.
// MalformedUploadID malformed upload id.
type MalformedUploadID struct {
UploadID string
}
func (e MalformedUploadID) Error() string {
return "Malformed upload id " + e.UploadID
}
// InvalidUploadID invalid upload id.
type InvalidUploadID struct {
Bucket string
Object string
UploadID string
}
func (e InvalidUploadID) Error() string {
return "Invalid upload id " + e.UploadID
}
// InvalidPart One or more of the specified parts could not be found
type InvalidPart struct {
PartNumber int
ExpETag string
GotETag string
}
func (e InvalidPart) Error() string {
return fmt.Sprintf("Specified part could not be found. PartNumber %d, Expected %s, got %s",
e.PartNumber, e.ExpETag, e.GotETag)
}
// PartTooSmall - error if part size is less than 5MB.
type PartTooSmall struct {
PartSize int64
PartNumber int
PartETag string
}
func (e PartTooSmall) Error() string {
return fmt.Sprintf("Part size for %d should be at least 5MB", e.PartNumber)
}
// PartTooBig returned if size of part is bigger than the allowed limit.
type PartTooBig struct{}
func (e PartTooBig) Error() string {
return "Part size bigger than the allowed limit"
}
// InvalidETag error returned when the etag has changed on disk
type InvalidETag struct{}
func (e InvalidETag) Error() string {
return "etag of the object has changed"
}
// NotImplemented If a feature is not implemented
type NotImplemented struct{}
func (e NotImplemented) Error() string {
return "Not Implemented"
}
// UnsupportedMetadata - unsupported metadata
type UnsupportedMetadata struct{}
func (e UnsupportedMetadata) Error() string {
return "Unsupported headers in Metadata"
}
// BackendDown is returned for network errors or if the gateway's backend is down.
type BackendDown struct{}
func (e BackendDown) Error() string {
return "Backend down"
}
// isErrBucketNotFound - Check if error type is BucketNotFound.
func isErrBucketNotFound(err error) bool {
var bkNotFound BucketNotFound
return errors.As(err, &bkNotFound)
}
// isErrObjectNotFound - Check if error type is ObjectNotFound.
func isErrObjectNotFound(err error) bool {
var objNotFound ObjectNotFound
return errors.As(err, &objNotFound)
}
// PreConditionFailed - Check if copy precondition failed
type PreConditionFailed struct{}
func (e PreConditionFailed) Error() string {
return "At least one of the pre-conditions you specified did not hold"
}
func isErrPreconditionFailed(err error) bool {
_, ok := err.(PreConditionFailed)
return ok
}

112
neofs/api/reqinfo.go Normal file
View file

@ -0,0 +1,112 @@
package api
import (
"context"
"sync"
)
type (
// KeyVal - appended to ReqInfo.Tags
KeyVal struct {
Key string
Val string
}
// ReqInfo stores the request info.
ReqInfo struct {
sync.RWMutex
RemoteHost string // Client Host/IP
Host string // Node Host/IP
UserAgent string // User Agent
DeploymentID string // x-minio-deployment-id
RequestID string // x-amz-request-id
API string // API name - GetObject PutObject NewMultipartUpload etc.
BucketName string // Bucket name
ObjectName string // Object name
tags []KeyVal // Any additional info not accommodated by above fields
}
)
// Key used for Get/SetReqInfo
type contextKeyType string
const ctxRequestInfo = contextKeyType("NeoFS-S3-Gate")
// NewReqInfo :
func NewReqInfo(remoteHost, userAgent, deploymentID, requestID, api, bucket, object string) *ReqInfo {
req := ReqInfo{}
req.RemoteHost = remoteHost
req.UserAgent = userAgent
req.API = api
req.DeploymentID = deploymentID
req.RequestID = requestID
req.BucketName = bucket
req.ObjectName = object
return &req
}
// AppendTags - appends key/val to ReqInfo.tags
func (r *ReqInfo) AppendTags(key string, val string) *ReqInfo {
if r == nil {
return nil
}
r.Lock()
defer r.Unlock()
r.tags = append(r.tags, KeyVal{key, val})
return r
}
// SetTags - sets key/val to ReqInfo.tags
func (r *ReqInfo) SetTags(key string, val string) *ReqInfo {
if r == nil {
return nil
}
r.Lock()
defer r.Unlock()
// Search of tag key already exists in tags
var updated bool
for _, tag := range r.tags {
if tag.Key == key {
tag.Val = val
updated = true
break
}
}
if !updated {
// Append to the end of tags list
r.tags = append(r.tags, KeyVal{key, val})
}
return r
}
// GetTags - returns the user defined tags
func (r *ReqInfo) GetTags() []KeyVal {
if r == nil {
return nil
}
r.RLock()
defer r.RUnlock()
return append([]KeyVal(nil), r.tags...)
}
// SetReqInfo sets ReqInfo in the context.
func SetReqInfo(ctx context.Context, req *ReqInfo) context.Context {
if ctx == nil {
return nil
}
return context.WithValue(ctx, ctxRequestInfo, req)
}
// GetReqInfo returns ReqInfo if set.
func GetReqInfo(ctx context.Context) *ReqInfo {
if ctx != nil {
r, ok := ctx.Value(ctxRequestInfo).(*ReqInfo)
if ok {
return r
}
r = &ReqInfo{}
SetReqInfo(ctx, r)
return r
}
return nil
}

130
neofs/api/response.go Normal file
View file

@ -0,0 +1,130 @@
package api
import (
"bytes"
"context"
"encoding/xml"
"fmt"
"net/http"
"net/url"
"strconv"
"github.com/google/uuid"
"github.com/minio/minio/misc"
)
type (
// APIErrorResponse - error response format
ErrorResponse struct {
XMLName xml.Name `xml:"Error" json:"-"`
Code string
Message string
Key string `xml:"Key,omitempty" json:"Key,omitempty"`
BucketName string `xml:"BucketName,omitempty" json:"BucketName,omitempty"`
Resource string
Region string `xml:"Region,omitempty" json:"Region,omitempty"`
RequestID string `xml:"RequestId" json:"RequestId"`
HostID string `xml:"HostId" json:"HostId"`
}
// APIError structure
Error struct {
Code string
Description string
HTTPStatusCode int
}
)
const (
hdrServerInfo = "Server"
hdrAcceptRanges = "Accept-Ranges"
hdrContentType = "Content-Type"
hdrContentLength = "Content-Length"
hdrRetryAfter = "Retry-After"
hdrAmzCopySource = "X-Amz-Copy-Source"
// Response request id.
hdrAmzRequestID = "x-amz-request-id"
// hdrSSE is the general AWS SSE HTTP header key.
hdrSSE = "X-Amz-Server-Side-Encryption"
// hdrSSECustomerKey is the HTTP header key referencing the
// SSE-C client-provided key..
hdrSSECustomerKey = hdrSSE + "-Customer-Key"
// hdrSSECopyKey is the HTTP header key referencing the SSE-C
// client-provided key for SSE-C copy requests.
hdrSSECopyKey = "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key"
)
var deploymentID, _ = uuid.NewRandom()
// WriteErrorResponse writes error headers
func WriteErrorResponse(ctx context.Context, w http.ResponseWriter, err Error, reqURL *url.URL) {
switch err.Code {
case "SlowDown", "XNeoFSServerNotInitialized", "XNeoFSReadQuorum", "XNeoFSWriteQuorum":
// Set retry-after header to indicate user-agents to retry request after 120secs.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
w.Header().Set(hdrRetryAfter, "120")
case "AccessDenied":
// TODO process when the request is from browser and also if browser
}
// Generate error response.
errorResponse := getAPIErrorResponse(ctx, err, reqURL.Path,
w.Header().Get(hdrAmzRequestID), deploymentID.String())
encodedErrorResponse := encodeResponse(errorResponse)
writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML)
}
// If none of the http routes match respond with appropriate errors
func errorResponseHandler(w http.ResponseWriter, r *http.Request) {
desc := fmt.Sprintf("Unknown API request at %s", r.URL.Path)
WriteErrorResponse(r.Context(), w, Error{
Code: "XMinioUnknownAPIRequest",
Description: desc,
HTTPStatusCode: http.StatusBadRequest,
}, r.URL)
}
// Write http common headers
func setCommonHeaders(w http.ResponseWriter) {
w.Header().Set(hdrServerInfo, "NeoFS-S3-Gate/"+misc.Version)
w.Header().Set(hdrAcceptRanges, "bytes")
// Remove sensitive information
removeSensitiveHeaders(w.Header())
}
// removeSensitiveHeaders removes confidential encryption
// information - e.g. the SSE-C key - from the HTTP headers.
// It has the same semantics as RemoveSensitiveEntires.
func removeSensitiveHeaders(h http.Header) {
h.Del(hdrSSECustomerKey)
h.Del(hdrSSECopyKey)
}
func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
setCommonHeaders(w)
if mType != mimeNone {
w.Header().Set(hdrContentType, string(mType))
}
w.Header().Set(hdrContentLength, strconv.Itoa(len(response)))
w.WriteHeader(statusCode)
if response != nil {
_, _ = w.Write(response)
w.(http.Flusher).Flush()
}
}
// Encodes the response headers into XML format.
func encodeResponse(response interface{}) []byte {
var bytesBuffer bytes.Buffer
bytesBuffer.WriteString(xml.Header)
_ = xml.
NewEncoder(&bytesBuffer).
Encode(response)
return bytesBuffer.Bytes()
}

301
neofs/api/router.go Normal file
View file

@ -0,0 +1,301 @@
package api
import (
"net/http"
"github.com/gorilla/mux"
"github.com/minio/minio/neofs/metrics"
)
type (
Handler interface {
HeadObjectHandler(http.ResponseWriter, *http.Request)
CopyObjectPartHandler(http.ResponseWriter, *http.Request)
PutObjectPartHandler(http.ResponseWriter, *http.Request)
ListObjectPartsHandler(http.ResponseWriter, *http.Request)
CompleteMultipartUploadHandler(http.ResponseWriter, *http.Request)
NewMultipartUploadHandler(http.ResponseWriter, *http.Request)
AbortMultipartUploadHandler(http.ResponseWriter, *http.Request)
GetObjectACLHandler(http.ResponseWriter, *http.Request)
PutObjectACLHandler(http.ResponseWriter, *http.Request)
GetObjectTaggingHandler(http.ResponseWriter, *http.Request)
PutObjectTaggingHandler(http.ResponseWriter, *http.Request)
DeleteObjectTaggingHandler(http.ResponseWriter, *http.Request)
SelectObjectContentHandler(http.ResponseWriter, *http.Request)
GetObjectRetentionHandler(http.ResponseWriter, *http.Request)
GetObjectLegalHoldHandler(http.ResponseWriter, *http.Request)
GetObjectHandler(http.ResponseWriter, *http.Request)
CopyObjectHandler(http.ResponseWriter, *http.Request)
PutObjectRetentionHandler(http.ResponseWriter, *http.Request)
PutObjectLegalHoldHandler(http.ResponseWriter, *http.Request)
PutObjectHandler(http.ResponseWriter, *http.Request)
DeleteObjectHandler(http.ResponseWriter, *http.Request)
GetBucketLocationHandler(http.ResponseWriter, *http.Request)
GetBucketPolicyHandler(http.ResponseWriter, *http.Request)
GetBucketLifecycleHandler(http.ResponseWriter, *http.Request)
GetBucketEncryptionHandler(http.ResponseWriter, *http.Request)
GetBucketACLHandler(http.ResponseWriter, *http.Request)
PutBucketACLHandler(http.ResponseWriter, *http.Request)
GetBucketCorsHandler(http.ResponseWriter, *http.Request)
GetBucketWebsiteHandler(http.ResponseWriter, *http.Request)
GetBucketAccelerateHandler(http.ResponseWriter, *http.Request)
GetBucketRequestPaymentHandler(http.ResponseWriter, *http.Request)
GetBucketLoggingHandler(http.ResponseWriter, *http.Request)
GetBucketReplicationHandler(http.ResponseWriter, *http.Request)
GetBucketTaggingHandler(http.ResponseWriter, *http.Request)
DeleteBucketWebsiteHandler(http.ResponseWriter, *http.Request)
DeleteBucketTaggingHandler(http.ResponseWriter, *http.Request)
GetBucketObjectLockConfigHandler(http.ResponseWriter, *http.Request)
GetBucketVersioningHandler(http.ResponseWriter, *http.Request)
GetBucketNotificationHandler(http.ResponseWriter, *http.Request)
ListenBucketNotificationHandler(http.ResponseWriter, *http.Request)
ListMultipartUploadsHandler(http.ResponseWriter, *http.Request)
ListObjectsV2MHandler(http.ResponseWriter, *http.Request)
ListObjectsV2Handler(http.ResponseWriter, *http.Request)
ListBucketObjectVersionsHandler(http.ResponseWriter, *http.Request)
ListObjectsV1Handler(http.ResponseWriter, *http.Request)
PutBucketLifecycleHandler(http.ResponseWriter, *http.Request)
PutBucketEncryptionHandler(http.ResponseWriter, *http.Request)
PutBucketPolicyHandler(http.ResponseWriter, *http.Request)
PutBucketObjectLockConfigHandler(http.ResponseWriter, *http.Request)
PutBucketTaggingHandler(http.ResponseWriter, *http.Request)
PutBucketVersioningHandler(http.ResponseWriter, *http.Request)
PutBucketNotificationHandler(http.ResponseWriter, *http.Request)
PutBucketHandler(http.ResponseWriter, *http.Request)
HeadBucketHandler(http.ResponseWriter, *http.Request)
PostPolicyBucketHandler(http.ResponseWriter, *http.Request)
DeleteMultipleObjectsHandler(http.ResponseWriter, *http.Request)
DeleteBucketPolicyHandler(http.ResponseWriter, *http.Request)
DeleteBucketLifecycleHandler(http.ResponseWriter, *http.Request)
DeleteBucketEncryptionHandler(http.ResponseWriter, *http.Request)
DeleteBucketHandler(http.ResponseWriter, *http.Request)
ListBucketsHandler(http.ResponseWriter, *http.Request)
}
// mimeType represents various MIME type used API responses.
mimeType string
)
const (
// SlashSeparator - slash separator.
SlashSeparator = "/"
// Means no response type.
mimeNone mimeType = ""
// Means response type is JSON.
// mimeJSON mimeType = "application/json"
// Means response type is XML.
mimeXML mimeType = "application/xml"
)
func Attach(r *mux.Router, m MaxClients, h Handler) {
api := r.PathPrefix(SlashSeparator).Subrouter()
bucket := api.PathPrefix("/{bucket}").Subrouter()
// Object operations
// HeadObject
bucket.Methods(http.MethodHead).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("headobject", h.HeadObjectHandler)))
// CopyObjectPart
bucket.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(hdrAmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(m.Handle(metrics.APIStats("copyobjectpart", h.CopyObjectPartHandler))).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}")
// PutObjectPart
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjectpart", h.PutObjectPartHandler))).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}")
// ListObjectParts
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("listobjectparts", h.ListObjectPartsHandler))).Queries("uploadId", "{uploadId:.*}")
// CompleteMultipartUpload
bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("completemutipartupload", h.CompleteMultipartUploadHandler))).Queries("uploadId", "{uploadId:.*}")
// NewMultipartUpload
bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("newmultipartupload", h.NewMultipartUploadHandler))).Queries("uploads", "")
// AbortMultipartUpload
bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("abortmultipartupload", h.AbortMultipartUploadHandler))).Queries("uploadId", "{uploadId:.*}")
// GetObjectACL - this is a dummy call.
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobjectacl", h.GetObjectACLHandler))).Queries("acl", "")
// PutObjectACL - this is a dummy call.
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjectacl", h.PutObjectACLHandler))).Queries("acl", "")
// GetObjectTagging
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobjecttagging", h.GetObjectTaggingHandler))).Queries("tagging", "")
// PutObjectTagging
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjecttagging", h.PutObjectTaggingHandler))).Queries("tagging", "")
// DeleteObjectTagging
bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("deleteobjecttagging", h.DeleteObjectTaggingHandler))).Queries("tagging", "")
// SelectObjectContent
bucket.Methods(http.MethodPost).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("selectobjectcontent", h.SelectObjectContentHandler))).Queries("select", "").Queries("select-type", "2")
// GetObjectRetention
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobjectretention", h.GetObjectRetentionHandler))).Queries("retention", "")
// GetObjectLegalHold
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobjectlegalhold", h.GetObjectLegalHoldHandler))).Queries("legal-hold", "")
// GetObject
bucket.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("getobject", h.GetObjectHandler)))
// CopyObject
bucket.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(hdrAmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(m.Handle(metrics.APIStats("copyobject", h.CopyObjectHandler)))
// PutObjectRetention
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjectretention", h.PutObjectRetentionHandler))).Queries("retention", "")
// PutObjectLegalHold
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobjectlegalhold", h.PutObjectLegalHoldHandler))).Queries("legal-hold", "")
// PutObject
bucket.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("putobject", h.PutObjectHandler)))
// DeleteObject
bucket.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(
m.Handle(metrics.APIStats("deleteobject", h.DeleteObjectHandler)))
// Bucket operations
// GetBucketLocation
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketlocation", h.GetBucketLocationHandler))).Queries("location", "")
// GetBucketPolicy
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketpolicy", h.GetBucketPolicyHandler))).Queries("policy", "")
// GetBucketLifecycle
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketlifecycle", h.GetBucketLifecycleHandler))).Queries("lifecycle", "")
// GetBucketEncryption
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketencryption", h.GetBucketEncryptionHandler))).Queries("encryption", "")
// Dummy Bucket Calls
// GetBucketACL -- this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketacl", h.GetBucketACLHandler))).Queries("acl", "")
// PutBucketACL -- this is a dummy call.
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketacl", h.PutBucketACLHandler))).Queries("acl", "")
// GetBucketCors - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketcors", h.GetBucketCorsHandler))).Queries("cors", "")
// GetBucketWebsiteHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketwebsite", h.GetBucketWebsiteHandler))).Queries("website", "")
// GetBucketAccelerateHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketaccelerate", h.GetBucketAccelerateHandler))).Queries("accelerate", "")
// GetBucketRequestPaymentHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketrequestpayment", h.GetBucketRequestPaymentHandler))).Queries("requestPayment", "")
// GetBucketLoggingHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketlogging", h.GetBucketLoggingHandler))).Queries("logging", "")
// GetBucketLifecycleHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketlifecycle", h.GetBucketLifecycleHandler))).Queries("lifecycle", "")
// GetBucketReplicationHandler - this is a dummy call.
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketreplication", h.GetBucketReplicationHandler))).Queries("replication", "")
// GetBucketTaggingHandler
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbuckettagging", h.GetBucketTaggingHandler))).Queries("tagging", "")
// DeleteBucketWebsiteHandler
bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucketwebsite", h.DeleteBucketWebsiteHandler))).Queries("website", "")
// DeleteBucketTaggingHandler
bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebuckettagging", h.DeleteBucketTaggingHandler))).Queries("tagging", "")
// GetBucketObjectLockConfig
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketobjectlockconfiguration", h.GetBucketObjectLockConfigHandler))).Queries("object-lock", "")
// GetBucketVersioning
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketversioning", h.GetBucketVersioningHandler))).Queries("versioning", "")
// GetBucketNotification
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("getbucketnotification", h.GetBucketNotificationHandler))).Queries("notification", "")
// ListenBucketNotification
bucket.Methods(http.MethodGet).HandlerFunc(metrics.APIStats("listenbucketnotification", h.ListenBucketNotificationHandler)).Queries("events", "{events:.*}")
// ListMultipartUploads
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listmultipartuploads", h.ListMultipartUploadsHandler))).Queries("uploads", "")
// ListObjectsV2M
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listobjectsv2M", h.ListObjectsV2MHandler))).Queries("list-type", "2", "metadata", "true")
// ListObjectsV2
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listobjectsv2", h.ListObjectsV2Handler))).Queries("list-type", "2")
// ListBucketVersions
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listbucketversions", h.ListBucketObjectVersionsHandler))).Queries("versions", "")
// ListObjectsV1 (Legacy)
bucket.Methods(http.MethodGet).HandlerFunc(
m.Handle(metrics.APIStats("listobjectsv1", h.ListObjectsV1Handler)))
// PutBucketLifecycle
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketlifecycle", h.PutBucketLifecycleHandler))).Queries("lifecycle", "")
// PutBucketEncryption
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketencryption", h.PutBucketEncryptionHandler))).Queries("encryption", "")
// PutBucketPolicy
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketpolicy", h.PutBucketPolicyHandler))).Queries("policy", "")
// PutBucketObjectLockConfig
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketobjectlockconfig", h.PutBucketObjectLockConfigHandler))).Queries("object-lock", "")
// PutBucketTaggingHandler
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbuckettagging", h.PutBucketTaggingHandler))).Queries("tagging", "")
// PutBucketVersioning
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketversioning", h.PutBucketVersioningHandler))).Queries("versioning", "")
// PutBucketNotification
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucketnotification", h.PutBucketNotificationHandler))).Queries("notification", "")
// PutBucket
bucket.Methods(http.MethodPut).HandlerFunc(
m.Handle(metrics.APIStats("putbucket", h.PutBucketHandler)))
// HeadBucket
bucket.Methods(http.MethodHead).HandlerFunc(
m.Handle(metrics.APIStats("headbucket", h.HeadBucketHandler)))
// PostPolicy
bucket.Methods(http.MethodPost).HeadersRegexp(hdrContentType, "multipart/form-data*").HandlerFunc(
m.Handle(metrics.APIStats("postpolicybucket", h.PostPolicyBucketHandler)))
// DeleteMultipleObjects
bucket.Methods(http.MethodPost).HandlerFunc(
m.Handle(metrics.APIStats("deletemultipleobjects", h.DeleteMultipleObjectsHandler))).Queries("delete", "")
// DeleteBucketPolicy
bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucketpolicy", h.DeleteBucketPolicyHandler))).Queries("policy", "")
// DeleteBucketLifecycle
bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucketlifecycle", h.DeleteBucketLifecycleHandler))).Queries("lifecycle", "")
// DeleteBucketEncryption
bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucketencryption", h.DeleteBucketEncryptionHandler))).Queries("encryption", "")
// DeleteBucket
bucket.Methods(http.MethodDelete).HandlerFunc(
m.Handle(metrics.APIStats("deletebucket", h.DeleteBucketHandler)))
// Root operation
// ListBuckets
api.Methods(http.MethodGet).Path(SlashSeparator).HandlerFunc(
m.Handle(metrics.APIStats("listbuckets", h.ListBucketsHandler)))
// S3 browser with signature v4 adds '//' for ListBuckets request, so rather
// than failing with UnknownAPIRequest we simply handle it for now.
api.Methods(http.MethodGet).Path(SlashSeparator + SlashSeparator).HandlerFunc(
m.Handle(metrics.APIStats("listbuckets", h.ListBucketsHandler)))
// If none of the routes match add default error handler routes
api.NotFoundHandler = metrics.APIStats("notfound", errorResponseHandler)
api.MethodNotAllowedHandler = metrics.APIStats("methodnotallowed", errorResponseHandler)
}

View file

@ -0,0 +1,93 @@
package api
// errUnexpected - unexpected error, requires manual intervention.
var errUnexpected = StorageErr("Unexpected error, please report this issue at https://github.com/minio/minio/issues")
// errCorruptedFormat - corrupted backend format.
var errCorruptedFormat = StorageErr("corrupted backend format, please join https://slack.min.io for assistance")
// errUnformattedDisk - unformatted disk found.
var errUnformattedDisk = StorageErr("unformatted disk found")
// errUnsupporteDisk - when disk does not support O_DIRECT flag.
var errUnsupportedDisk = StorageErr("disk does not support O_DIRECT")
// errDiskFull - cannot create volume or files when disk is full.
var errDiskFull = StorageErr("disk path full")
// errDiskNotFound - cannot find the underlying configured disk anymore.
var errDiskNotFound = StorageErr("disk not found")
// errFaultyRemoteDisk - remote disk is faulty.
var errFaultyRemoteDisk = StorageErr("remote disk is faulty")
// errFaultyDisk - disk is faulty.
var errFaultyDisk = StorageErr("disk is faulty")
// errDiskAccessDenied - we don't have write permissions on disk.
var errDiskAccessDenied = StorageErr("disk access denied")
// errFileNotFound - cannot find the file.
var errFileNotFound = StorageErr("file not found")
// errTooManyOpenFiles - too many open files.
var errTooManyOpenFiles = StorageErr("too many open files")
// errFileNameTooLong - given file name is too long than supported length.
var errFileNameTooLong = StorageErr("file name too long")
// errVolumeExists - cannot create same volume again.
var errVolumeExists = StorageErr("volume already exists")
// errIsNotRegular - not of regular file type.
var errIsNotRegular = StorageErr("not of regular file type")
// errVolumeNotFound - cannot find the volume.
var errVolumeNotFound = StorageErr("volume not found")
// errVolumeNotEmpty - volume not empty.
var errVolumeNotEmpty = StorageErr("volume is not empty")
// errVolumeAccessDenied - cannot access volume, insufficient permissions.
var errVolumeAccessDenied = StorageErr("volume access denied")
// errFileAccessDenied - cannot access file, insufficient permissions.
var errFileAccessDenied = StorageErr("file access denied")
// errFileCorrupt - file has an unexpected size, or is not readable
var errFileCorrupt = StorageErr("file is corrupted")
// errFileParentIsFile - cannot have overlapping objects, parent is already a file.
var errFileParentIsFile = StorageErr("parent is a file")
// errBitrotHashAlgoInvalid - the algo for bit-rot hash
// verification is empty or invalid.
var errBitrotHashAlgoInvalid = StorageErr("bit-rot hash algorithm is invalid")
// errCrossDeviceLink - rename across devices not allowed.
var errCrossDeviceLink = StorageErr("Rename across devices not allowed, please fix your backend configuration")
// errMinDiskSize - cannot create volume or files when disk size is less than threshold.
var errMinDiskSize = StorageErr("The disk size is less than 900MiB threshold")
// errLessData - returned when less data available than what was requested.
var errLessData = StorageErr("less data available than what was requested")
// errMoreData = returned when more data was sent by the caller than what it was supposed to.
var errMoreData = StorageErr("more data was sent than what was advertised")
// StorageErr represents error generated by posix call.
type StorageErr string
func (h StorageErr) Error() string {
return string(h)
}
// Collection of basic errors.
var baseErrs = []error{
errDiskNotFound,
errFaultyDisk,
errFaultyRemoteDisk,
}
var baseIgnoredErrs = baseErrs

107
neofs/api/typed-errors.go Normal file
View file

@ -0,0 +1,107 @@
package api
import (
"github.com/pkg/errors"
)
// errInvalidArgument means that input argument is invalid.
var errInvalidArgument = errors.New("Invalid arguments specified")
// errMethodNotAllowed means that method is not allowed.
var errMethodNotAllowed = errors.New("Method not allowed")
// errSignatureMismatch means signature did not match.
var errSignatureMismatch = errors.New("Signature does not match")
// used when we deal with data larger than expected
var errSizeUnexpected = errors.New("Data size larger than expected")
// used when we deal with data with unknown size
var errSizeUnspecified = errors.New("Data size is unspecified")
// When upload object size is greater than 5G in a single PUT/POST operation.
var errDataTooLarge = errors.New("Object size larger than allowed limit")
// When upload object size is less than what was expected.
var errDataTooSmall = errors.New("Object size smaller than expected")
// errServerNotInitialized - server not initialized.
var errServerNotInitialized = errors.New("Server not initialized, please try again")
// errRPCAPIVersionUnsupported - unsupported rpc API version.
var errRPCAPIVersionUnsupported = errors.New("Unsupported rpc API version")
// errServerTimeMismatch - server times are too far apart.
var errServerTimeMismatch = errors.New("Server times are too far apart")
// errInvalidBucketName - bucket name is reserved for MinIO, usually
// returned for 'minio', '.minio.sys', buckets with capital letters.
var errInvalidBucketName = errors.New("The specified bucket is not valid")
// errInvalidRange - returned when given range value is not valid.
var errInvalidRange = errors.New("Invalid range")
// errInvalidRangeSource - returned when given range value exceeds
// the source object size.
var errInvalidRangeSource = errors.New("Range specified exceeds source object size")
// error returned by disks which are to be initialized are waiting for the
// first server to initialize them in distributed set to initialize them.
var errNotFirstDisk = errors.New("Not first disk")
// error returned by first disk waiting to initialize other servers.
var errFirstDiskWait = errors.New("Waiting on other disks")
// error returned when a bucket already exists
var errBucketAlreadyExists = errors.New("Your previous request to create the named bucket succeeded and you already own it")
// error returned for a negative actual size.
var errInvalidDecompressedSize = errors.New("Invalid Decompressed Size")
// error returned in IAM subsystem when user doesn't exist.
var errNoSuchUser = errors.New("Specified user does not exist")
// error returned in IAM subsystem when groups doesn't exist.
var errNoSuchGroup = errors.New("Specified group does not exist")
// error returned in IAM subsystem when a non-empty group needs to be
// deleted.
var errGroupNotEmpty = errors.New("Specified group is not empty - cannot remove it")
// error returned in IAM subsystem when policy doesn't exist.
var errNoSuchPolicy = errors.New("Specified canned policy does not exist")
// error returned in IAM subsystem when an external users systems is configured.
var errIAMActionNotAllowed = errors.New("Specified IAM action is not allowed with LDAP configuration")
// error returned in IAM subsystem when IAM sub-system is still being initialized.
var errIAMNotInitialized = errors.New("IAM sub-system is being initialized, please try again")
// error returned when access is denied.
var errAccessDenied = errors.New("Do not have enough permissions to access this resource")
// error returned when object is locked.
var errLockedObject = errors.New("Object is WORM protected and cannot be overwritten or deleted")
var (
errInvalidAccessKeyID = errors.New("The access key ID you provided does not exist in our records")
errChangeCredNotAllowed = errors.New("Changing access key and secret key not allowed")
errAuthentication = errors.New("Authentication failed, check your access credentials")
errNoAuthToken = errors.New("JWT token missing")
errIncorrectCreds = errors.New("Current access key or secret key is incorrect")
errPresignedNotAllowed = errors.New("Unable to generate shareable URL due to lack of read permissions")
)
var (
// AWS errors for invalid SSE-C requests.
errEncryptedObject = errors.New("The object was stored using a form of SSE")
errInvalidSSEParameters = errors.New("The SSE-C key for key-rotation is not correct") // special access denied
errKMSNotConfigured = errors.New("KMS not configured for a server side encrypted object")
// Additional MinIO errors for SSE-C requests.
errObjectTampered = errors.New("The requested object was modified and may be compromised")
// error returned when invalid encryption parameters are specified
errInvalidEncryptionParameters = errors.New("The encryption parameters are not applicable to this object")
)
// ErrNoEntriesFound - Indicates no entries were found for the given key (directory)
var ErrNoEntriesFound = errors.New("No entries found for this key")

12
neofs/api/xl-v1-errors.go Normal file
View file

@ -0,0 +1,12 @@
package api
import "errors"
// errXLReadQuorum - did not meet read quorum.
var errXLReadQuorum = errors.New("Read failed. Insufficient number of disks online")
// errXLWriteQuorum - did not meet write quorum.
var errXLWriteQuorum = errors.New("Write failed. Insufficient number of disks online")
// errNoHealRequired - returned when healing is attempted on a previously healed disks.
var errNoHealRequired = errors.New("No healing is required")