From 4e63e0e3724de81fb21e5de812dc768a2baf66ed Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Mon, 4 Nov 2019 09:30:59 -0800 Subject: [PATCH] Return appropriate errors API versions changes across REST APIs (#8480) This PR adds code to appropriately handle versioning issues that come up quite constantly across our API changes. Currently we were also routing our requests wrong which sort of made it harder to write a consistent error handling code to appropriately reject or honor requests. This PR potentially fixes issues - old mc is used against new minio release which is incompatible returns an appropriate for client action. - any older servers talking to each other, report appropriate error - incompatible peer servers should report error and reject the calls with appropriate error --- cmd/admin-handlers.go | 6 -- cmd/admin-handlers_test.go | 4 +- cmd/admin-router.go | 95 ++++++++++--------- cmd/api-errors.go | 6 -- cmd/api-response.go | 5 + cmd/api-router.go | 6 +- cmd/config-encrypted.go | 29 +++--- cmd/config-migrate.go | 42 +------- cmd/config.go | 16 +++- cmd/format-disk-cache_test.go | 2 +- cmd/format-fs_test.go | 2 +- ...gateway-router.go => gateway-interface.go} | 0 cmd/generic-handlers.go | 8 +- cmd/handler-utils.go | 67 ++++++++++--- cmd/lock-rest-server-common.go | 23 ++--- cmd/lock-rest-server.go | 23 +++-- cmd/namespace-lock.go | 2 +- cmd/peer-rest-common.go | 76 ++++++++------- cmd/peer-rest-server.go | 88 ++++++++--------- cmd/posix_test.go | 2 +- cmd/rest/client.go | 5 +- cmd/server-main.go | 6 +- cmd/storage-rest-client.go | 2 +- cmd/storage-rest-common.go | 41 ++++---- cmd/storage-rest-server.go | 42 ++++---- cmd/xl-v1-healing-common_test.go | 4 +- 26 files changed, 312 insertions(+), 290 deletions(-) rename cmd/{gateway-router.go => gateway-interface.go} (100%) diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index 2f249fcd1..228222743 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -530,12 +530,6 @@ func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request return } - // Method only allowed in Distributed XL mode. - if !globalIsDistXL { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - peerLocks := globalNotificationSys.GetLocks(ctx) // Once we have received all the locks currently used from peers // add the local peer locks list as well. diff --git a/cmd/admin-handlers_test.go b/cmd/admin-handlers_test.go index a4937c429..b1d7f372a 100644 --- a/cmd/admin-handlers_test.go +++ b/cmd/admin-handlers_test.go @@ -188,7 +188,7 @@ func testServiceSignalReceiver(cmd cmdType, t *testing.T) { func getServiceCmdRequest(cmd cmdType, cred auth.Credentials) (*http.Request, error) { queryVal := url.Values{} queryVal.Set("action", string(cmd.toServiceAction())) - resource := adminAPIPathPrefix + "/service?" + queryVal.Encode() + resource := adminPathPrefix + adminAPIVersionPrefix + "/service?" + queryVal.Encode() req, err := newTestRequest(http.MethodPost, resource, 0, nil) if err != nil { return nil, err @@ -257,7 +257,7 @@ func buildAdminRequest(queryVal url.Values, method, path string, contentLength int64, bodySeeker io.ReadSeeker) (*http.Request, error) { req, err := newTestRequest(method, - adminAPIPathPrefix+path+"?"+queryVal.Encode(), + adminPathPrefix+adminAPIVersionPrefix+path+"?"+queryVal.Encode(), contentLength, bodySeeker) if err != nil { return nil, err diff --git a/cmd/admin-router.go b/cmd/admin-router.go index 140eca3fa..973f0bbd7 100644 --- a/cmd/admin-router.go +++ b/cmd/admin-router.go @@ -24,138 +24,141 @@ import ( ) const ( - adminAPIPathPrefix = minioReservedBucketPath + "/admin/" + madmin.AdminAPIVersion + adminPathPrefix = minioReservedBucketPath + "/admin" + adminAPIVersion = madmin.AdminAPIVersion + adminAPIVersionPrefix = SlashSeparator + madmin.AdminAPIVersion ) // adminAPIHandlers provides HTTP handlers for MinIO admin API. -type adminAPIHandlers struct { -} +type adminAPIHandlers struct{} // registerAdminRouter - Add handler functions for each service REST API routes. func registerAdminRouter(router *mux.Router, enableConfigOps, enableIAMOps bool) { adminAPI := adminAPIHandlers{} // Admin router - adminRouter := router.PathPrefix(adminAPIPathPrefix).Subrouter() + adminRouter := router.PathPrefix(adminPathPrefix).Subrouter() /// Service operations // Restart and stop MinIO service. - adminRouter.Methods(http.MethodPost).Path("/service").HandlerFunc(httpTraceAll(adminAPI.ServiceActionHandler)).Queries("action", "{action:.*}") + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix+"/service").HandlerFunc(httpTraceAll(adminAPI.ServiceActionHandler)).Queries("action", "{action:.*}") // Update MinIO servers. - adminRouter.Methods(http.MethodPost).Path("/update").HandlerFunc(httpTraceAll(adminAPI.ServerUpdateHandler)).Queries("updateURL", "{updateURL:.*}") + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix+"/update").HandlerFunc(httpTraceAll(adminAPI.ServerUpdateHandler)).Queries("updateURL", "{updateURL:.*}") // Info operations - adminRouter.Methods(http.MethodGet).Path("/info").HandlerFunc(httpTraceAll(adminAPI.ServerInfoHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/info").HandlerFunc(httpTraceAll(adminAPI.ServerInfoHandler)) // Harware Info operations - adminRouter.Methods(http.MethodGet).Path("/hardware").HandlerFunc(httpTraceAll(adminAPI.ServerHardwareInfoHandler)).Queries("hwType", "{hwType:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/hardware").HandlerFunc(httpTraceAll(adminAPI.ServerHardwareInfoHandler)).Queries("hwType", "{hwType:.*}") // StorageInfo operations - adminRouter.Methods(http.MethodGet).Path("/storageinfo").HandlerFunc(httpTraceAll(adminAPI.StorageInfoHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/storageinfo").HandlerFunc(httpTraceAll(adminAPI.StorageInfoHandler)) if globalIsDistXL || globalIsXL { /// Heal operations // Heal processing endpoint. - adminRouter.Methods(http.MethodPost).Path("/heal/").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) - adminRouter.Methods(http.MethodPost).Path("/heal/{bucket}").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) - adminRouter.Methods(http.MethodPost).Path("/heal/{bucket}/{prefix:.*}").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix + "/heal/").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix + "/heal/{bucket}").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix + "/heal/{bucket}/{prefix:.*}").HandlerFunc(httpTraceAll(adminAPI.HealHandler)) - adminRouter.Methods(http.MethodPost).Path("/background-heal/status").HandlerFunc(httpTraceAll(adminAPI.BackgroundHealStatusHandler)) + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix + "/background-heal/status").HandlerFunc(httpTraceAll(adminAPI.BackgroundHealStatusHandler)) /// Health operations } // Performance command - return performance details based on input type - adminRouter.Methods(http.MethodGet).Path("/performance").HandlerFunc(httpTraceAll(adminAPI.PerfInfoHandler)).Queries("perfType", "{perfType:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/performance").HandlerFunc(httpTraceAll(adminAPI.PerfInfoHandler)).Queries("perfType", "{perfType:.*}") // Profiling operations - adminRouter.Methods(http.MethodPost).Path("/profiling/start").HandlerFunc(httpTraceAll(adminAPI.StartProfilingHandler)). + adminRouter.Methods(http.MethodPost).Path(adminAPIVersionPrefix+"/profiling/start").HandlerFunc(httpTraceAll(adminAPI.StartProfilingHandler)). Queries("profilerType", "{profilerType:.*}") - adminRouter.Methods(http.MethodGet).Path("/profiling/download").HandlerFunc(httpTraceAll(adminAPI.DownloadProfilingHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/profiling/download").HandlerFunc(httpTraceAll(adminAPI.DownloadProfilingHandler)) // Config KV operations. if enableConfigOps { - adminRouter.Methods(http.MethodGet).Path("/get-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigKVHandler)).Queries("key", "{key:.*}") - adminRouter.Methods(http.MethodPut).Path("/set-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigKVHandler)) - adminRouter.Methods(http.MethodDelete).Path("/del-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.DelConfigKVHandler)) - adminRouter.Methods(http.MethodGet).Path("/help-config-kv").HandlerFunc(httpTraceAll(adminAPI.HelpConfigKVHandler)).Queries("subSys", "{subSys:.*}", "key", "{key:.*}") - adminRouter.Methods(http.MethodGet).Path("/list-config-history-kv").HandlerFunc(httpTraceAll(adminAPI.ListConfigHistoryKVHandler)) - adminRouter.Methods(http.MethodDelete).Path("/clear-config-history-kv").HandlerFunc(httpTraceHdrs(adminAPI.ClearConfigHistoryKVHandler)).Queries("restoreId", "{restoreId:.*}") - adminRouter.Methods(http.MethodPut).Path("/restore-config-history-kv").HandlerFunc(httpTraceHdrs(adminAPI.RestoreConfigHistoryKVHandler)).Queries("restoreId", "{restoreId:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/get-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigKVHandler)).Queries("key", "{key:.*}") + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix + "/set-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigKVHandler)) + adminRouter.Methods(http.MethodDelete).Path(adminAPIVersionPrefix + "/del-config-kv").HandlerFunc(httpTraceHdrs(adminAPI.DelConfigKVHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/help-config-kv").HandlerFunc(httpTraceAll(adminAPI.HelpConfigKVHandler)).Queries("subSys", "{subSys:.*}", "key", "{key:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/list-config-history-kv").HandlerFunc(httpTraceAll(adminAPI.ListConfigHistoryKVHandler)) + adminRouter.Methods(http.MethodDelete).Path(adminAPIVersionPrefix+"/clear-config-history-kv").HandlerFunc(httpTraceHdrs(adminAPI.ClearConfigHistoryKVHandler)).Queries("restoreId", "{restoreId:.*}") + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/restore-config-history-kv").HandlerFunc(httpTraceHdrs(adminAPI.RestoreConfigHistoryKVHandler)).Queries("restoreId", "{restoreId:.*}") } /// Config operations if enableConfigOps { // Get config - adminRouter.Methods(http.MethodGet).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/config").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigHandler)) // Set config - adminRouter.Methods(http.MethodPut).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigHandler)) + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix + "/config").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigHandler)) } if enableIAMOps { // -- IAM APIs -- // Add policy IAM - adminRouter.Methods(http.MethodPut).Path("/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name", + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/add-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.AddCannedPolicy)).Queries("name", "{name:.*}") // Add user IAM - adminRouter.Methods(http.MethodPut).Path("/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}") - adminRouter.Methods(http.MethodPut).Path("/set-user-status").HandlerFunc(httpTraceHdrs(adminAPI.SetUserStatus)). + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/add-user").HandlerFunc(httpTraceHdrs(adminAPI.AddUser)).Queries("accessKey", "{accessKey:.*}") + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/set-user-status").HandlerFunc(httpTraceHdrs(adminAPI.SetUserStatus)). Queries("accessKey", "{accessKey:.*}").Queries("status", "{status:.*}") // Info policy IAM - adminRouter.Methods(http.MethodGet).Path("/info-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.InfoCannedPolicy)).Queries("name", "{name:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/info-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.InfoCannedPolicy)).Queries("name", "{name:.*}") // Remove policy IAM - adminRouter.Methods(http.MethodDelete).Path("/remove-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.RemoveCannedPolicy)).Queries("name", "{name:.*}") + adminRouter.Methods(http.MethodDelete).Path(adminAPIVersionPrefix+"/remove-canned-policy").HandlerFunc(httpTraceHdrs(adminAPI.RemoveCannedPolicy)).Queries("name", "{name:.*}") // Set user or group policy - adminRouter.Methods(http.MethodPut).Path("/set-user-or-group-policy"). + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/set-user-or-group-policy"). HandlerFunc(httpTraceHdrs(adminAPI.SetPolicyForUserOrGroup)). Queries("policyName", "{policyName:.*}", "userOrGroup", "{userOrGroup:.*}", "isGroup", "{isGroup:true|false}") // Remove user IAM - adminRouter.Methods(http.MethodDelete).Path("/remove-user").HandlerFunc(httpTraceHdrs(adminAPI.RemoveUser)).Queries("accessKey", "{accessKey:.*}") + adminRouter.Methods(http.MethodDelete).Path(adminAPIVersionPrefix+"/remove-user").HandlerFunc(httpTraceHdrs(adminAPI.RemoveUser)).Queries("accessKey", "{accessKey:.*}") // List users - adminRouter.Methods(http.MethodGet).Path("/list-users").HandlerFunc(httpTraceHdrs(adminAPI.ListUsers)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/list-users").HandlerFunc(httpTraceHdrs(adminAPI.ListUsers)) // User info - adminRouter.Methods(http.MethodGet).Path("/user-info").HandlerFunc(httpTraceHdrs(adminAPI.GetUserInfo)).Queries("accessKey", "{accessKey:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/user-info").HandlerFunc(httpTraceHdrs(adminAPI.GetUserInfo)).Queries("accessKey", "{accessKey:.*}") // Add/Remove members from group - adminRouter.Methods(http.MethodPut).Path("/update-group-members").HandlerFunc(httpTraceHdrs(adminAPI.UpdateGroupMembers)) + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix + "/update-group-members").HandlerFunc(httpTraceHdrs(adminAPI.UpdateGroupMembers)) // Get Group - adminRouter.Methods(http.MethodGet).Path("/group").HandlerFunc(httpTraceHdrs(adminAPI.GetGroup)).Queries("group", "{group:.*}") + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix+"/group").HandlerFunc(httpTraceHdrs(adminAPI.GetGroup)).Queries("group", "{group:.*}") // List Groups - adminRouter.Methods(http.MethodGet).Path("/groups").HandlerFunc(httpTraceHdrs(adminAPI.ListGroups)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/groups").HandlerFunc(httpTraceHdrs(adminAPI.ListGroups)) // Set Group Status - adminRouter.Methods(http.MethodPut).Path("/set-group-status").HandlerFunc(httpTraceHdrs(adminAPI.SetGroupStatus)).Queries("group", "{group:.*}").Queries("status", "{status:.*}") + adminRouter.Methods(http.MethodPut).Path(adminAPIVersionPrefix+"/set-group-status").HandlerFunc(httpTraceHdrs(adminAPI.SetGroupStatus)).Queries("group", "{group:.*}").Queries("status", "{status:.*}") // List policies - adminRouter.Methods(http.MethodGet).Path("/list-canned-policies").HandlerFunc(httpTraceHdrs(adminAPI.ListCannedPolicies)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/list-canned-policies").HandlerFunc(httpTraceHdrs(adminAPI.ListCannedPolicies)) } // -- Top APIs -- // Top locks - adminRouter.Methods(http.MethodGet).Path("/top/locks").HandlerFunc(httpTraceHdrs(adminAPI.TopLocksHandler)) + if globalIsDistXL { + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/top/locks").HandlerFunc(httpTraceHdrs(adminAPI.TopLocksHandler)) + } // HTTP Trace - adminRouter.Methods(http.MethodGet).Path("/trace").HandlerFunc(adminAPI.TraceHandler) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/trace").HandlerFunc(adminAPI.TraceHandler) // Console Logs - adminRouter.Methods(http.MethodGet).Path("/log").HandlerFunc(httpTraceAll(adminAPI.ConsoleLogHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/log").HandlerFunc(httpTraceAll(adminAPI.ConsoleLogHandler)) // -- KMS APIs -- // - adminRouter.Methods(http.MethodGet).Path("/kms/key/status").HandlerFunc(httpTraceAll(adminAPI.KMSKeyStatusHandler)) + adminRouter.Methods(http.MethodGet).Path(adminAPIVersionPrefix + "/kms/key/status").HandlerFunc(httpTraceAll(adminAPI.KMSKeyStatusHandler)) - // If none of the routes match, return error. - adminRouter.NotFoundHandler = http.HandlerFunc(httpTraceHdrs(notFoundHandler)) - adminRouter.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler)) + // If none of the routes match add default error handler routes + adminRouter.NotFoundHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) + adminRouter.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) } diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 9d650a568..652ec359a 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -141,7 +141,6 @@ const ( ErrInvalidPrefixMarker ErrBadRequest ErrKeyTooLongError - ErrInvalidAPIVersion // Add new error codes here. // SSE-S3 related API errors @@ -1503,11 +1502,6 @@ var errorCodes = errorCodeMap{ Description: "Invalid according to Policy: Policy Condition failed", HTTPStatusCode: http.StatusForbidden, }, - ErrInvalidAPIVersion: { - Code: "ErrInvalidAPIVersion", - Description: "Invalid version found in the request", - HTTPStatusCode: http.StatusNotFound, - }, // Add your error structure here. } diff --git a/cmd/api-response.go b/cmd/api-response.go index d17ec0e62..7000c9bd9 100644 --- a/cmd/api-response.go +++ b/cmd/api-response.go @@ -694,6 +694,11 @@ func writeErrorResponseHeadersOnly(w http.ResponseWriter, err APIError) { writeResponse(w, err.HTTPStatusCode, nil, mimeNone) } +func writeErrorResponseString(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { + // Generate string error response. + writeResponse(w, err.HTTPStatusCode, []byte(err.Description), mimeNone) +} + // writeErrorResponseJSON - writes error response in JSON format; // useful for admin APIs. func writeErrorResponseJSON(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { diff --git a/cmd/api-router.go b/cmd/api-router.go index c1b0f38ce..541c242bc 100644 --- a/cmd/api-router.go +++ b/cmd/api-router.go @@ -171,6 +171,8 @@ func registerAPIRouter(router *mux.Router, encryptionEnabled, allowSSEKMS bool) // ListBuckets apiRouter.Methods(http.MethodGet).Path(SlashSeparator).HandlerFunc(collectAPIStats("listbuckets", httpTraceAll(api.ListBucketsHandler))) - // If none of the routes match. - apiRouter.NotFoundHandler = http.HandlerFunc(collectAPIStats("notfound", httpTraceAll(notFoundHandler))) + // If none of the routes match add default error handler routes + apiRouter.NotFoundHandler = http.HandlerFunc(collectAPIStats("notfound", httpTraceAll(errorResponseHandler))) + apiRouter.MethodNotAllowedHandler = http.HandlerFunc(collectAPIStats("methodnotallowed", httpTraceAll(errorResponseHandler))) + } diff --git a/cmd/config-encrypted.go b/cmd/config-encrypted.go index 98c4ec4df..f3a4a1e93 100644 --- a/cmd/config-encrypted.go +++ b/cmd/config-encrypted.go @@ -41,6 +41,20 @@ func handleEncryptedConfigBackend(objAPI ObjectLayer, server bool) error { var encrypted bool var err error + // Construct path to config/transaction.lock for locking + transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" + + // Make sure to hold lock for entire migration to avoid + // such that only one server should migrate the entire config + // at a given time, this big transaction lock ensures this + // appropriately. This is also true for rotation of encrypted + // content. + objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) + if err := objLock.GetLock(globalOperationTimeout); err != nil { + return err + } + defer objLock.Unlock() + // Migrating Config backend needs a retry mechanism for // the following reasons: // - Read quorum is lost just after the initialization @@ -48,8 +62,7 @@ func handleEncryptedConfigBackend(objAPI ObjectLayer, server bool) error { for range newRetryTimerSimple(doneCh) { if encrypted, err = checkBackendEncrypted(objAPI); err != nil { if err == errDiskNotFound || - strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) || - strings.Contains(err.Error(), InsufficientWriteQuorum{}.Error()) { + strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) { logger.Info("Waiting for config backend to be encrypted..") continue } @@ -247,18 +260,6 @@ func migrateConfigPrefixToEncrypted(objAPI ObjectLayer, activeCredOld auth.Crede logger.Info("Attempting a rotation of encrypted config, IAM users and policies on MinIO with newly supplied credentials") } - // Construct path to config/transaction.lock for locking - transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" - - // As object layer's GetObject() and PutObject() take respective lock on minioMetaBucket - // and configFile, take a transaction lock to avoid data race between readConfig() - // and saveConfig(). - objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) - if err := objLock.GetLock(globalOperationTimeout); err != nil { - return err - } - defer objLock.Unlock() - var marker string for { res, err := objAPI.ListObjects(context.Background(), minioMetaBucket, minioConfigPrefix, marker, "", maxObjectList) diff --git a/cmd/config-migrate.go b/cmd/config-migrate.go index 599be3657..173d354ff 100644 --- a/cmd/config-migrate.go +++ b/cmd/config-migrate.go @@ -2427,11 +2427,6 @@ func migrateConfigToMinioSys(objAPI ObjectLayer) (err error) { // Construct path to config.json for the given bucket. configFile := path.Join(minioConfigPrefix, minioConfigFile) - // Verify if config was already available in .minio.sys in which case, nothing more to be done. - if err = checkConfig(context.Background(), objAPI, configFile); err != errConfigNotFound { - return err - } - defer func() { if err == nil { if globalEtcdClient != nil { @@ -2444,18 +2439,6 @@ func migrateConfigToMinioSys(objAPI ObjectLayer) (err error) { } }() - // Construct path to config/transaction.lock for locking - transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" - - // As object layer's GetObject() and PutObject() take respective lock on minioMetaBucket - // and configFile, take a transaction lock to avoid data race between readConfig() - // and saveConfig(). - objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) - if err = objLock.GetLock(globalOperationTimeout); err != nil { - return err - } - defer objLock.Unlock() - // Verify if backend already has the file (after holding lock) if err = checkConfig(context.Background(), objAPI, configFile); err != errConfigNotFound { return err @@ -2488,6 +2471,7 @@ func migrateConfigToMinioSys(objAPI ObjectLayer) (err error) { // Migrates '.minio.sys/config.json' to v33. func migrateMinioSysConfig(objAPI ObjectLayer) error { + // Construct path to config.json for the given bucket. configFile := path.Join(minioConfigPrefix, minioConfigFile) // Check if the config version is latest, if not migrate. @@ -2499,18 +2483,6 @@ func migrateMinioSysConfig(objAPI ObjectLayer) error { return nil } - // Construct path to config/transaction.lock for locking - transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" - - // As object layer's GetObject() and PutObject() take respective lock on minioMetaBucket - // and configFile, take a transaction lock to avoid data race between readConfig() - // and saveConfig(). - objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) - if err := objLock.GetLock(globalOperationTimeout); err != nil { - return err - } - defer objLock.Unlock() - if err := migrateV27ToV28MinioSys(objAPI); err != nil { return err } @@ -2806,18 +2778,6 @@ func migrateMinioSysConfigToKV(objAPI ObjectLayer) error { notify.SetNotifyWebhook(newCfg, k, args) } - // Construct path to config/transaction.lock for locking - transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" - - // As object layer's GetObject() and PutObject() take respective lock on minioMetaBucket - // and configFile, take a transaction lock to avoid data race between readConfig() - // and saveConfig(). - objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) - if err = objLock.GetLock(globalOperationTimeout); err != nil { - return err - } - defer objLock.Unlock() - if err = saveServerConfig(context.Background(), objAPI, newCfg, cfg); err != nil { return err } diff --git a/cmd/config.go b/cmd/config.go index 1223fb115..2d1d93bad 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -233,7 +233,8 @@ func (sys *ConfigSys) Init(objAPI ObjectLayer) error { select { case <-retryTimerCh: if err := initConfig(objAPI); err != nil { - if strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) || + if err == errDiskNotFound || + strings.Contains(err.Error(), InsufficientReadQuorum{}.Error()) || strings.Contains(err.Error(), InsufficientWriteQuorum{}.Error()) { logger.Info("Waiting for configuration to be initialized..") continue @@ -264,6 +265,19 @@ func initConfig(objAPI ObjectLayer) error { } } + // Construct path to config/transaction.lock for locking + transactionConfigPrefix := minioConfigPrefix + "/transaction.lock" + + // Hold lock only by one server and let that server alone migrate + // all the config as necessary, this is to ensure that + // redundant locks are not held for each migration - this allows + // for a more predictable behavior while debugging. + objLock := globalNSMutex.NewNSLock(context.Background(), minioMetaBucket, transactionConfigPrefix) + if err := objLock.GetLock(globalOperationTimeout); err != nil { + return err + } + defer objLock.Unlock() + // Migrates ${HOME}/.minio/config.json or config.json.deprecated // to '/.minio.sys/config/config.json' // ignore if the file doesn't exist. diff --git a/cmd/format-disk-cache_test.go b/cmd/format-disk-cache_test.go index d818f0277..9e64674e4 100644 --- a/cmd/format-disk-cache_test.go +++ b/cmd/format-disk-cache_test.go @@ -36,7 +36,7 @@ func TestDiskCacheFormat(t *testing.T) { } // Do the basic sanity checks to check if initFormatCache() did its job. cacheFormatPath := pathJoin(fsDirs[0], minioMetaBucket, formatConfigFile) - f, err := os.OpenFile(cacheFormatPath, os.O_RDWR, 0) + f, err := os.OpenFile(cacheFormatPath, os.O_RDWR|os.O_SYNC, 0) if err != nil { t.Fatal(err) } diff --git a/cmd/format-fs_test.go b/cmd/format-fs_test.go index 9e657a92c..dc9f187d9 100644 --- a/cmd/format-fs_test.go +++ b/cmd/format-fs_test.go @@ -46,7 +46,7 @@ func TestFSFormatFS(t *testing.T) { rlk.Close() // Do the basic sanity checks to check if initFormatFS() did its job. - f, err := os.OpenFile(fsFormatPath, os.O_RDWR, 0) + f, err := os.OpenFile(fsFormatPath, os.O_RDWR|os.O_SYNC, 0) if err != nil { t.Fatal(err) } diff --git a/cmd/gateway-router.go b/cmd/gateway-interface.go similarity index 100% rename from cmd/gateway-router.go rename to cmd/gateway-interface.go diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index 9f2e7d9c9..1e0dd6141 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -276,7 +276,7 @@ func (h cacheControlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Check to allow access to the reserved "bucket" `/minio` for Admin // API requests. func isAdminReq(r *http.Request) bool { - return strings.HasPrefix(r.URL.Path, adminAPIPathPrefix+SlashSeparator) + return strings.HasPrefix(r.URL.Path, adminPathPrefix) } // Adds verification for incoming paths. @@ -293,11 +293,11 @@ func (h minioReservedBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Req case guessIsRPCReq(r), guessIsBrowserReq(r), guessIsHealthCheckReq(r), guessIsMetricsReq(r), isAdminReq(r): // Allow access to reserved buckets default: - // For all other requests reject access to reserved - // buckets + // For all other requests reject access to reserved buckets bucketName, _ := request2BucketObjectName(r) if isMinioReservedBucket(bucketName) || isMinioMetaBucket(bucketName) { - writeErrorResponse(context.Background(), w, errorCodes.ToAPIErr(ErrAllAccessDisabled), r.URL, guessIsBrowserReq(r)) + browser := guessIsBrowserReq(r) + writeErrorResponse(r.Context(), w, errorCodes.ToAPIErr(ErrAllAccessDisabled), r.URL, browser) return } } diff --git a/cmd/handler-utils.go b/cmd/handler-utils.go index a43cb2bd7..1a12dfbe5 100644 --- a/cmd/handler-utils.go +++ b/cmd/handler-utils.go @@ -19,18 +19,21 @@ package cmd import ( "bytes" "context" + "fmt" "io" "io/ioutil" "mime/multipart" "net" "net/http" "net/url" + "regexp" "strings" xhttp "github.com/minio/minio/cmd/http" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/handlers" + "github.com/minio/minio/pkg/madmin" ) // Parses location constraint from the incoming reader. @@ -408,23 +411,61 @@ func getResource(path string, host string, domains []string) (string, error) { return path, nil } -// If none of the http routes match respond with MethodNotAllowed -func notFoundHandler(w http.ResponseWriter, r *http.Request) { - writeErrorResponse(context.Background(), w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) +var regexVersion = regexp.MustCompile(`(\w\d+)`) + +func extractAPIVersion(r *http.Request) string { + return regexVersion.FindString(r.URL.Path) } -// If the API version does not match with current version. -func versionMismatchHandler(w http.ResponseWriter, r *http.Request) { - path := r.URL.Path +// If none of the http routes match respond with appropriate errors +func errorResponseHandler(w http.ResponseWriter, r *http.Request) { + version := extractAPIVersion(r) switch { - case strings.HasPrefix(path, minioReservedBucketPath+"/peer/"): - writeVersionMismatchResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidAPIVersion), r.URL, false) - case strings.HasPrefix(path, minioReservedBucketPath+"/storage/"): - writeVersionMismatchResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidAPIVersion), r.URL, false) - case strings.HasPrefix(path, minioReservedBucketPath+"/lock/"): - writeVersionMismatchResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidAPIVersion), r.URL, false) + case strings.HasPrefix(r.URL.Path, peerRESTPrefix): + desc := fmt.Sprintf("Expected 'peer' API version '%s', instead found '%s', please upgrade the servers", + peerRESTVersion, version) + writeErrorResponseString(r.Context(), w, APIError{ + Code: "XMinioPeerVersionMismatch", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL) + case strings.HasPrefix(r.URL.Path, storageRESTPrefix): + desc := fmt.Sprintf("Expected 'storage' API version '%s', instead found '%s', please upgrade the servers", + storageRESTVersion, version) + writeErrorResponseString(r.Context(), w, APIError{ + Code: "XMinioStorageVersionMismatch", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL) + case strings.HasPrefix(r.URL.Path, lockRESTPrefix): + desc := fmt.Sprintf("Expected 'lock' API version '%s', instead found '%s', please upgrade the servers", + lockRESTVersion, version) + writeErrorResponseString(r.Context(), w, APIError{ + Code: "XMinioLockVersionMismatch", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL) + case strings.HasPrefix(r.URL.Path, adminPathPrefix): + var desc string + if version == "v1" { + desc = fmt.Sprintf("Server expects client requests with 'admin' API version '%s', found '%s', please upgrade the client to latest releases", madmin.AdminAPIVersion, version) + } else if version == madmin.AdminAPIVersion { + desc = fmt.Sprintf("This 'admin' API is not supported by server in '%s'", getMinioMode()) + } else { + desc = fmt.Sprintf("Unexpected client 'admin' API version found '%s', expected '%s', please downgrade the client to older releases", version, madmin.AdminAPIVersion) + } + writeErrorResponseJSON(r.Context(), w, APIError{ + Code: "XMinioAdminVersionMismatch", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL) default: - writeVersionMismatchResponse(r.Context(), w, errorCodes.ToAPIErr(ErrInvalidAPIVersion), r.URL, true) + desc := fmt.Sprintf("Unknown API request at %s", r.URL.Path) + writeErrorResponse(r.Context(), w, APIError{ + Code: "XMinioUnknownAPIRequest", + Description: desc, + HTTPStatusCode: http.StatusBadRequest, + }, r.URL, guessIsBrowserReq(r)) } } diff --git a/cmd/lock-rest-server-common.go b/cmd/lock-rest-server-common.go index 7efeec7b2..74961cb9a 100644 --- a/cmd/lock-rest-server-common.go +++ b/cmd/lock-rest-server-common.go @@ -18,22 +18,23 @@ package cmd import ( "errors" - "path" "time" ) -const lockRESTVersion = "v2" -const lockRESTPath = minioReservedBucketPath + "/lock/" + lockRESTVersion - -var lockServicePath = path.Join(minioReservedBucketPath, lockServiceSubPath) +const ( + lockRESTVersion = "v2" + lockRESTVersionPrefix = SlashSeparator + "v2" + lockRESTPrefix = minioReservedBucketPath + "/lock" + lockRESTPath = lockRESTPrefix + lockRESTVersionPrefix +) const ( - lockRESTMethodLock = "lock" - lockRESTMethodRLock = "rlock" - lockRESTMethodUnlock = "unlock" - lockRESTMethodRUnlock = "runlock" - lockRESTMethodForceUnlock = "forceunlock" - lockRESTMethodExpired = "expired" + lockRESTMethodLock = "/lock" + lockRESTMethodRLock = "/rlock" + lockRESTMethodUnlock = "/unlock" + lockRESTMethodRUnlock = "/runlock" + lockRESTMethodForceUnlock = "/forceunlock" + lockRESTMethodExpired = "/expired" // Unique ID of lock/unlock request. lockRESTUID = "uid" diff --git a/cmd/lock-rest-server.go b/cmd/lock-rest-server.go index 53bd14805..ca1b1db52 100644 --- a/cmd/lock-rest-server.go +++ b/cmd/lock-rest-server.go @@ -30,9 +30,6 @@ import ( ) const ( - // Lock rpc server endpoint. - lockServiceSubPath = "/lock" - // Lock maintenance interval. lockMaintenanceInterval = 1 * time.Minute @@ -246,16 +243,18 @@ func startLockMaintenance(lkSrv *lockRESTServer) { // registerLockRESTHandlers - register lock rest router. func registerLockRESTHandlers(router *mux.Router) { - subrouter := router.PathPrefix(lockRESTPath).Subrouter() + subrouter := router.PathPrefix(lockRESTPrefix).Subrouter() queries := restQueries(lockRESTUID, lockRESTSource, lockRESTResource, lockRESTServerAddr, lockRESTServerEndpoint) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodLock).HandlerFunc(httpTraceHdrs(globalLockServer.LockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodRLock).HandlerFunc(httpTraceHdrs(globalLockServer.RLockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.UnlockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodRUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.RUnlockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodForceUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.ForceUnlockHandler)).Queries(queries...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + lockRESTMethodExpired).HandlerFunc(httpTraceAll(globalLockServer.ExpiredHandler)).Queries(queries...) - - router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler)) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodLock).HandlerFunc(httpTraceHdrs(globalLockServer.LockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodRLock).HandlerFunc(httpTraceHdrs(globalLockServer.RLockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.UnlockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodRUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.RUnlockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodForceUnlock).HandlerFunc(httpTraceHdrs(globalLockServer.ForceUnlockHandler)).Queries(queries...) + subrouter.Methods(http.MethodPost).Path(lockRESTVersionPrefix + lockRESTMethodExpired).HandlerFunc(httpTraceAll(globalLockServer.ExpiredHandler)).Queries(queries...) + + // If none of the routes match add default error handler routes + router.NotFoundHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) + router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) // Start lock maintenance from all lock servers. go startLockMaintenance(globalLockServer) diff --git a/cmd/namespace-lock.go b/cmd/namespace-lock.go index f848ff664..cd1ead334 100644 --- a/cmd/namespace-lock.go +++ b/cmd/namespace-lock.go @@ -70,7 +70,7 @@ func newDsyncNodes(endpoints EndpointList) (clnts []dsync.NetLocker, myNode int, globalLockServer = &lockRESTServer{ ll: &localLocker{ serverAddr: endpoint.Host, - serviceEndpoint: lockServicePath, + serviceEndpoint: lockRESTPrefix, lockMap: make(map[string][]lockRequesterInfo), }, } diff --git a/cmd/peer-rest-common.go b/cmd/peer-rest-common.go index 8aacae4fb..ac4a8fe87 100644 --- a/cmd/peer-rest-common.go +++ b/cmd/peer-rest-common.go @@ -16,44 +16,48 @@ package cmd -const peerRESTVersion = "v6" -const peerRESTPath = minioReservedBucketPath + "/peer/" + peerRESTVersion +const ( + peerRESTVersion = "v6" + peerRESTVersionPrefix = SlashSeparator + peerRESTVersion + peerRESTPrefix = minioReservedBucketPath + "/peer" + peerRESTPath = peerRESTPrefix + peerRESTVersionPrefix +) const ( - peerRESTMethodNetReadPerfInfo = "netreadperfinfo" - peerRESTMethodCollectNetPerfInfo = "collectnetperfinfo" - peerRESTMethodServerInfo = "serverinfo" - peerRESTMethodCPULoadInfo = "cpuloadinfo" - peerRESTMethodMemUsageInfo = "memusageinfo" - peerRESTMethodDrivePerfInfo = "driveperfinfo" - peerRESTMethodDeleteBucket = "deletebucket" - peerRESTMethodServerUpdate = "serverupdate" - peerRESTMethodSignalService = "signalservice" - peerRESTMethodBackgroundHealStatus = "backgroundhealstatus" - peerRESTMethodBackgroundOpsStatus = "backgroundopsstatus" - peerRESTMethodGetLocks = "getlocks" - peerRESTMethodBucketPolicyRemove = "removebucketpolicy" - peerRESTMethodLoadUser = "loaduser" - peerRESTMethodDeleteUser = "deleteuser" - peerRESTMethodLoadPolicy = "loadpolicy" - peerRESTMethodLoadPolicyMapping = "loadpolicymapping" - peerRESTMethodDeletePolicy = "deletepolicy" - peerRESTMethodLoadUsers = "loadusers" - peerRESTMethodLoadGroup = "loadgroup" - peerRESTMethodStartProfiling = "startprofiling" - peerRESTMethodDownloadProfilingData = "downloadprofilingdata" - peerRESTMethodBucketPolicySet = "setbucketpolicy" - peerRESTMethodBucketNotificationPut = "putbucketnotification" - peerRESTMethodBucketNotificationListen = "listenbucketnotification" - peerRESTMethodReloadFormat = "reloadformat" - peerRESTMethodTargetExists = "targetexists" - peerRESTMethodSendEvent = "sendevent" - peerRESTMethodTrace = "trace" - peerRESTMethodBucketLifecycleSet = "setbucketlifecycle" - peerRESTMethodBucketLifecycleRemove = "removebucketlifecycle" - peerRESTMethodLog = "log" - peerRESTMethodHardwareCPUInfo = "cpuhardwareinfo" - peerRESTMethodHardwareNetworkInfo = "networkhardwareinfo" + peerRESTMethodNetReadPerfInfo = "/netreadperfinfo" + peerRESTMethodCollectNetPerfInfo = "/collectnetperfinfo" + peerRESTMethodServerInfo = "/serverinfo" + peerRESTMethodCPULoadInfo = "/cpuloadinfo" + peerRESTMethodMemUsageInfo = "/memusageinfo" + peerRESTMethodDrivePerfInfo = "/driveperfinfo" + peerRESTMethodDeleteBucket = "/deletebucket" + peerRESTMethodServerUpdate = "/serverupdate" + peerRESTMethodSignalService = "/signalservice" + peerRESTMethodBackgroundHealStatus = "/backgroundhealstatus" + peerRESTMethodBackgroundOpsStatus = "/backgroundopsstatus" + peerRESTMethodGetLocks = "/getlocks" + peerRESTMethodBucketPolicyRemove = "/removebucketpolicy" + peerRESTMethodLoadUser = "/loaduser" + peerRESTMethodDeleteUser = "/deleteuser" + peerRESTMethodLoadPolicy = "/loadpolicy" + peerRESTMethodLoadPolicyMapping = "/loadpolicymapping" + peerRESTMethodDeletePolicy = "/deletepolicy" + peerRESTMethodLoadUsers = "/loadusers" + peerRESTMethodLoadGroup = "/loadgroup" + peerRESTMethodStartProfiling = "/startprofiling" + peerRESTMethodDownloadProfilingData = "/downloadprofilingdata" + peerRESTMethodBucketPolicySet = "/setbucketpolicy" + peerRESTMethodBucketNotificationPut = "/putbucketnotification" + peerRESTMethodBucketNotificationListen = "/listenbucketnotification" + peerRESTMethodReloadFormat = "/reloadformat" + peerRESTMethodTargetExists = "/targetexists" + peerRESTMethodSendEvent = "/sendevent" + peerRESTMethodTrace = "/trace" + peerRESTMethodBucketLifecycleSet = "/setbucketlifecycle" + peerRESTMethodBucketLifecycleRemove = "/removebucketlifecycle" + peerRESTMethodLog = "/log" + peerRESTMethodHardwareCPUInfo = "/cpuhardwareinfo" + peerRESTMethodHardwareNetworkInfo = "/networkhardwareinfo" ) const ( diff --git a/cmd/peer-rest-server.go b/cmd/peer-rest-server.go index 285330154..5d0981951 100644 --- a/cmd/peer-rest-server.go +++ b/cmd/peer-rest-server.go @@ -995,47 +995,49 @@ func (s *peerRESTServer) IsValid(w http.ResponseWriter, r *http.Request) bool { // registerPeerRESTHandlers - register peer rest router. func registerPeerRESTHandlers(router *mux.Router) { server := &peerRESTServer{} - subrouter := router.PathPrefix(peerRESTPath).Subrouter() - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodNetReadPerfInfo).HandlerFunc(httpTraceHdrs(server.NetReadPerfInfoHandler)).Queries(restQueries(peerRESTNetPerfSize)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodCollectNetPerfInfo).HandlerFunc(httpTraceHdrs(server.CollectNetPerfInfoHandler)).Queries(restQueries(peerRESTNetPerfSize)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodGetLocks).HandlerFunc(httpTraceHdrs(server.GetLocksHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodServerInfo).HandlerFunc(httpTraceHdrs(server.ServerInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodCPULoadInfo).HandlerFunc(httpTraceHdrs(server.CPULoadInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodMemUsageInfo).HandlerFunc(httpTraceHdrs(server.MemUsageInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDrivePerfInfo).HandlerFunc(httpTraceHdrs(server.DrivePerfInfoHandler)).Queries(restQueries(peerRESTDrivePerfSize)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodHardwareCPUInfo).HandlerFunc(httpTraceHdrs(server.CPUInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodHardwareNetworkInfo).HandlerFunc(httpTraceHdrs(server.NetworkInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDeleteBucket).HandlerFunc(httpTraceHdrs(server.DeleteBucketHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodSignalService).HandlerFunc(httpTraceHdrs(server.SignalServiceHandler)).Queries(restQueries(peerRESTSignal)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodServerUpdate).HandlerFunc(httpTraceHdrs(server.ServerUpdateHandler)).Queries(restQueries(peerRESTUpdateURL, peerRESTSha256Hex, peerRESTLatestRelease)...) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketPolicyRemove).HandlerFunc(httpTraceAll(server.RemoveBucketPolicyHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketPolicySet).HandlerFunc(httpTraceHdrs(server.SetBucketPolicyHandler)).Queries(restQueries(peerRESTBucket)...) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDeletePolicy).HandlerFunc(httpTraceAll(server.DeletePolicyHandler)).Queries(restQueries(peerRESTPolicy)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadPolicy).HandlerFunc(httpTraceAll(server.LoadPolicyHandler)).Queries(restQueries(peerRESTPolicy)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadPolicyMapping).HandlerFunc(httpTraceAll(server.LoadPolicyMappingHandler)).Queries(restQueries(peerRESTUserOrGroup)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDeleteUser).HandlerFunc(httpTraceAll(server.LoadUserHandler)).Queries(restQueries(peerRESTUser)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadUser).HandlerFunc(httpTraceAll(server.LoadUserHandler)).Queries(restQueries(peerRESTUser, peerRESTUserTemp)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadUsers).HandlerFunc(httpTraceAll(server.LoadUsersHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLoadGroup).HandlerFunc(httpTraceAll(server.LoadGroupHandler)).Queries(restQueries(peerRESTGroup)...) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodStartProfiling).HandlerFunc(httpTraceAll(server.StartProfilingHandler)).Queries(restQueries(peerRESTProfiler)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodDownloadProfilingData).HandlerFunc(httpTraceHdrs(server.DownloadProflingDataHandler)) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodTargetExists).HandlerFunc(httpTraceHdrs(server.TargetExistsHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodSendEvent).HandlerFunc(httpTraceHdrs(server.SendEventHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketNotificationPut).HandlerFunc(httpTraceHdrs(server.PutBucketNotificationHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketNotificationListen).HandlerFunc(httpTraceHdrs(server.ListenBucketNotificationHandler)).Queries(restQueries(peerRESTBucket)...) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodReloadFormat).HandlerFunc(httpTraceHdrs(server.ReloadFormatHandler)).Queries(restQueries(peerRESTDryRun)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketLifecycleSet).HandlerFunc(httpTraceHdrs(server.SetBucketLifecycleHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBucketLifecycleRemove).HandlerFunc(httpTraceHdrs(server.RemoveBucketLifecycleHandler)).Queries(restQueries(peerRESTBucket)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBackgroundOpsStatus).HandlerFunc(server.BackgroundOpsStatusHandler) - - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodTrace).HandlerFunc(server.TraceHandler) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodBackgroundHealStatus).HandlerFunc(server.BackgroundHealStatusHandler) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + peerRESTMethodLog).HandlerFunc(server.ConsoleLogHandler) - - router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler)) + subrouter := router.PathPrefix(peerRESTPrefix).Subrouter() + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodNetReadPerfInfo).HandlerFunc(httpTraceHdrs(server.NetReadPerfInfoHandler)).Queries(restQueries(peerRESTNetPerfSize)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodCollectNetPerfInfo).HandlerFunc(httpTraceHdrs(server.CollectNetPerfInfoHandler)).Queries(restQueries(peerRESTNetPerfSize)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodGetLocks).HandlerFunc(httpTraceHdrs(server.GetLocksHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodServerInfo).HandlerFunc(httpTraceHdrs(server.ServerInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodCPULoadInfo).HandlerFunc(httpTraceHdrs(server.CPULoadInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodMemUsageInfo).HandlerFunc(httpTraceHdrs(server.MemUsageInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDrivePerfInfo).HandlerFunc(httpTraceHdrs(server.DrivePerfInfoHandler)).Queries(restQueries(peerRESTDrivePerfSize)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodHardwareCPUInfo).HandlerFunc(httpTraceHdrs(server.CPUInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodHardwareNetworkInfo).HandlerFunc(httpTraceHdrs(server.NetworkInfoHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDeleteBucket).HandlerFunc(httpTraceHdrs(server.DeleteBucketHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodSignalService).HandlerFunc(httpTraceHdrs(server.SignalServiceHandler)).Queries(restQueries(peerRESTSignal)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodServerUpdate).HandlerFunc(httpTraceHdrs(server.ServerUpdateHandler)).Queries(restQueries(peerRESTUpdateURL, peerRESTSha256Hex, peerRESTLatestRelease)...) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketPolicyRemove).HandlerFunc(httpTraceAll(server.RemoveBucketPolicyHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketPolicySet).HandlerFunc(httpTraceHdrs(server.SetBucketPolicyHandler)).Queries(restQueries(peerRESTBucket)...) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDeletePolicy).HandlerFunc(httpTraceAll(server.DeletePolicyHandler)).Queries(restQueries(peerRESTPolicy)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadPolicy).HandlerFunc(httpTraceAll(server.LoadPolicyHandler)).Queries(restQueries(peerRESTPolicy)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadPolicyMapping).HandlerFunc(httpTraceAll(server.LoadPolicyMappingHandler)).Queries(restQueries(peerRESTUserOrGroup)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDeleteUser).HandlerFunc(httpTraceAll(server.LoadUserHandler)).Queries(restQueries(peerRESTUser)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadUser).HandlerFunc(httpTraceAll(server.LoadUserHandler)).Queries(restQueries(peerRESTUser, peerRESTUserTemp)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadUsers).HandlerFunc(httpTraceAll(server.LoadUsersHandler)) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLoadGroup).HandlerFunc(httpTraceAll(server.LoadGroupHandler)).Queries(restQueries(peerRESTGroup)...) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodStartProfiling).HandlerFunc(httpTraceAll(server.StartProfilingHandler)).Queries(restQueries(peerRESTProfiler)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDownloadProfilingData).HandlerFunc(httpTraceHdrs(server.DownloadProflingDataHandler)) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodTargetExists).HandlerFunc(httpTraceHdrs(server.TargetExistsHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodSendEvent).HandlerFunc(httpTraceHdrs(server.SendEventHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketNotificationPut).HandlerFunc(httpTraceHdrs(server.PutBucketNotificationHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketNotificationListen).HandlerFunc(httpTraceHdrs(server.ListenBucketNotificationHandler)).Queries(restQueries(peerRESTBucket)...) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodReloadFormat).HandlerFunc(httpTraceHdrs(server.ReloadFormatHandler)).Queries(restQueries(peerRESTDryRun)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketLifecycleSet).HandlerFunc(httpTraceHdrs(server.SetBucketLifecycleHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBucketLifecycleRemove).HandlerFunc(httpTraceHdrs(server.RemoveBucketLifecycleHandler)).Queries(restQueries(peerRESTBucket)...) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBackgroundOpsStatus).HandlerFunc(server.BackgroundOpsStatusHandler) + + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodTrace).HandlerFunc(server.TraceHandler) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodBackgroundHealStatus).HandlerFunc(server.BackgroundHealStatusHandler) + subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodLog).HandlerFunc(server.ConsoleLogHandler) + + // If none of the routes match add default error handler routes + router.NotFoundHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) + router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) } diff --git a/cmd/posix_test.go b/cmd/posix_test.go index 745ac89f6..b54077d6e 100644 --- a/cmd/posix_test.go +++ b/cmd/posix_test.go @@ -1887,7 +1887,7 @@ func TestPosixVerifyFile(t *testing.T) { // 4) Streaming bitrot check on corrupted file filePath := pathJoin(posixStorage.String(), volName, fileName) - f, err := os.OpenFile(filePath, os.O_WRONLY, 0644) + f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_SYNC, 0644) if err != nil { t.Fatal(err) } diff --git a/cmd/rest/client.go b/cmd/rest/client.go index e6cbccbe2..c58ef9185 100644 --- a/cmd/rest/client.go +++ b/cmd/rest/client.go @@ -54,13 +54,12 @@ type Client struct { // URL query separator constants const ( - resourceSep = "/" - querySep = "?" + querySep = "?" ) // CallWithContext - make a REST call with context. func (c *Client) CallWithContext(ctx context.Context, method string, values url.Values, body io.Reader, length int64) (reply io.ReadCloser, err error) { - req, err := http.NewRequest(http.MethodPost, c.url.String()+resourceSep+method+querySep+values.Encode(), body) + req, err := http.NewRequest(http.MethodPost, c.url.String()+method+querySep+values.Encode(), body) if err != nil { return nil, &NetworkError{err} } diff --git a/cmd/server-main.go b/cmd/server-main.go index 7567470f2..5d9309033 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -244,6 +244,9 @@ func serverMain(ctx *cli.Context) { // Handle all server command args. serverHandleCmdArgs(ctx) + // Handle all server environment vars. + serverHandleEnvVars() + // Check and load TLS certificates. var err error globalPublicCerts, globalTLSCerts, globalIsSSL, err = getTLSConfig() @@ -253,9 +256,6 @@ func serverMain(ctx *cli.Context) { globalRootCAs, err = config.GetRootCAs(globalCertsCADir.Get()) logger.FatalIf(err, "Failed to read root CAs (%v)", err) - // Handle all server environment vars. - serverHandleEnvVars() - // Is distributed setup, error out if no certificates are found for HTTPS endpoints. if globalIsDistXL { if globalEndpoints.IsHTTPS() && !globalIsSSL { diff --git a/cmd/storage-rest-client.go b/cmd/storage-rest-client.go index b93621a11..86b5ebcce 100644 --- a/cmd/storage-rest-client.go +++ b/cmd/storage-rest-client.go @@ -460,7 +460,7 @@ func newStorageRESTClient(endpoint Endpoint) (*storageRESTClient, error) { serverURL := &url.URL{ Scheme: scheme, Host: endpoint.Host, - Path: path.Join(storageRESTPath, endpoint.Path), + Path: path.Join(storageRESTPrefix, endpoint.Path, storageRESTVersion), } var tlsConfig *tls.Config diff --git a/cmd/storage-rest-common.go b/cmd/storage-rest-common.go index 81a6da7a6..9df169570 100644 --- a/cmd/storage-rest-common.go +++ b/cmd/storage-rest-common.go @@ -17,30 +17,31 @@ package cmd const ( - storageRESTVersion = "v10" - storageRESTPath = minioReservedBucketPath + "/storage/" + storageRESTVersion + SlashSeparator + storageRESTVersion = "v10" + storageRESTVersionPrefix = SlashSeparator + "v10" + storageRESTPrefix = minioReservedBucketPath + "/storage" ) const ( - storageRESTMethodDiskInfo = "diskinfo" - storageRESTMethodMakeVol = "makevol" - storageRESTMethodStatVol = "statvol" - storageRESTMethodDeleteVol = "deletevol" - storageRESTMethodListVols = "listvols" + storageRESTMethodDiskInfo = "/diskinfo" + storageRESTMethodMakeVol = "/makevol" + storageRESTMethodStatVol = "/statvol" + storageRESTMethodDeleteVol = "/deletevol" + storageRESTMethodListVols = "/listvols" - storageRESTMethodAppendFile = "appendfile" - storageRESTMethodCreateFile = "createfile" - storageRESTMethodWriteAll = "writeall" - storageRESTMethodStatFile = "statfile" - storageRESTMethodReadAll = "readall" - storageRESTMethodReadFile = "readfile" - storageRESTMethodReadFileStream = "readfilestream" - storageRESTMethodListDir = "listdir" - storageRESTMethodWalk = "walk" - storageRESTMethodDeleteFile = "deletefile" - storageRESTMethodDeleteFileBulk = "deletefilebulk" - storageRESTMethodRenameFile = "renamefile" - storageRESTMethodVerifyFile = "verifyfile" + storageRESTMethodAppendFile = "/appendfile" + storageRESTMethodCreateFile = "/createfile" + storageRESTMethodWriteAll = "/writeall" + storageRESTMethodStatFile = "/statfile" + storageRESTMethodReadAll = "/readall" + storageRESTMethodReadFile = "/readfile" + storageRESTMethodReadFileStream = "/readfilestream" + storageRESTMethodListDir = "/listdir" + storageRESTMethodWalk = "/walk" + storageRESTMethodDeleteFile = "/deletefile" + storageRESTMethodDeleteFileBulk = "/deletefilebulk" + storageRESTMethodRenameFile = "/renamefile" + storageRESTMethodVerifyFile = "/verifyfile" ) const ( diff --git a/cmd/storage-rest-server.go b/cmd/storage-rest-server.go index f9cc6151d..2b63acc19 100644 --- a/cmd/storage-rest-server.go +++ b/cmd/storage-rest-server.go @@ -573,43 +573,45 @@ func registerStorageRESTHandlers(router *mux.Router, endpoints EndpointList) { server := &storageRESTServer{storage: storage} - subrouter := router.PathPrefix(path.Join(storageRESTPath, endpoint.Path)).Subrouter() + subrouter := router.PathPrefix(path.Join(storageRESTPrefix, endpoint.Path)).Subrouter() - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodDiskInfo).HandlerFunc(httpTraceHdrs(server.DiskInfoHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodMakeVol).HandlerFunc(httpTraceHdrs(server.MakeVolHandler)).Queries(restQueries(storageRESTVolume)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodStatVol).HandlerFunc(httpTraceHdrs(server.StatVolHandler)).Queries(restQueries(storageRESTVolume)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodDeleteVol).HandlerFunc(httpTraceHdrs(server.DeleteVolHandler)).Queries(restQueries(storageRESTVolume)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodListVols).HandlerFunc(httpTraceHdrs(server.ListVolsHandler)) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDiskInfo).HandlerFunc(httpTraceHdrs(server.DiskInfoHandler)) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodMakeVol).HandlerFunc(httpTraceHdrs(server.MakeVolHandler)).Queries(restQueries(storageRESTVolume)...) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodStatVol).HandlerFunc(httpTraceHdrs(server.StatVolHandler)).Queries(restQueries(storageRESTVolume)...) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteVol).HandlerFunc(httpTraceHdrs(server.DeleteVolHandler)).Queries(restQueries(storageRESTVolume)...) + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodListVols).HandlerFunc(httpTraceHdrs(server.ListVolsHandler)) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodAppendFile).HandlerFunc(httpTraceHdrs(server.AppendFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodAppendFile).HandlerFunc(httpTraceHdrs(server.AppendFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodWriteAll).HandlerFunc(httpTraceHdrs(server.WriteAllHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodWriteAll).HandlerFunc(httpTraceHdrs(server.WriteAllHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodCreateFile).HandlerFunc(httpTraceHdrs(server.CreateFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodCreateFile).HandlerFunc(httpTraceHdrs(server.CreateFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath, storageRESTLength)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodStatFile).HandlerFunc(httpTraceHdrs(server.StatFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodStatFile).HandlerFunc(httpTraceHdrs(server.StatFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodReadAll).HandlerFunc(httpTraceHdrs(server.ReadAllHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadAll).HandlerFunc(httpTraceHdrs(server.ReadAllHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodReadFile).HandlerFunc(httpTraceHdrs(server.ReadFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFile).HandlerFunc(httpTraceHdrs(server.ReadFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath, storageRESTOffset, storageRESTLength, storageRESTBitrotAlgo, storageRESTBitrotHash)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodReadFileStream).HandlerFunc(httpTraceHdrs(server.ReadFileStreamHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFileStream).HandlerFunc(httpTraceHdrs(server.ReadFileStreamHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath, storageRESTOffset, storageRESTLength)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodListDir).HandlerFunc(httpTraceHdrs(server.ListDirHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodListDir).HandlerFunc(httpTraceHdrs(server.ListDirHandler)). Queries(restQueries(storageRESTVolume, storageRESTDirPath, storageRESTCount, storageRESTLeafFile)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodWalk).HandlerFunc(httpTraceHdrs(server.WalkHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodWalk).HandlerFunc(httpTraceHdrs(server.WalkHandler)). Queries(restQueries(storageRESTVolume, storageRESTDirPath, storageRESTMarkerPath, storageRESTRecursive, storageRESTLeafFile)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodDeleteFile).HandlerFunc(httpTraceHdrs(server.DeleteFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteFile).HandlerFunc(httpTraceHdrs(server.DeleteFileHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodDeleteFileBulk).HandlerFunc(httpTraceHdrs(server.DeleteFileBulkHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteFileBulk).HandlerFunc(httpTraceHdrs(server.DeleteFileBulkHandler)). Queries(restQueries(storageRESTVolume, storageRESTFilePath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodRenameFile).HandlerFunc(httpTraceHdrs(server.RenameFileHandler)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodRenameFile).HandlerFunc(httpTraceHdrs(server.RenameFileHandler)). Queries(restQueries(storageRESTSrcVolume, storageRESTSrcPath, storageRESTDstVolume, storageRESTDstPath)...) - subrouter.Methods(http.MethodPost).Path(SlashSeparator + storageRESTMethodVerifyFile).HandlerFunc(httpTraceHdrs(server.VerifyFile)). + subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodVerifyFile).HandlerFunc(httpTraceHdrs(server.VerifyFile)). Queries(restQueries(storageRESTVolume, storageRESTFilePath, storageRESTBitrotAlgo, storageRESTBitrotHash, storageRESTLength, storageRESTShardSize)...) } - router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(versionMismatchHandler)) + // If none of the routes match add default error handler routes + router.NotFoundHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) + router.MethodNotAllowedHandler = http.HandlerFunc(httpTraceAll(errorResponseHandler)) } diff --git a/cmd/xl-v1-healing-common_test.go b/cmd/xl-v1-healing-common_test.go index fa3e51c07..b55f6a7a8 100644 --- a/cmd/xl-v1-healing-common_test.go +++ b/cmd/xl-v1-healing-common_test.go @@ -216,7 +216,7 @@ func TestListOnlineDisks(t *testing.T) { // appears in outDatedDisks. tamperedIndex = index filePath := pathJoin(xlDisks[index].String(), bucket, object, "part.1") - f, err := os.OpenFile(filePath, os.O_WRONLY, 0) + f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_SYNC, 0) if err != nil { t.Fatalf("Failed to open %s: %s\n", filePath, err) } @@ -319,7 +319,7 @@ func TestDisksWithAllParts(t *testing.T) { for _, info := range partsMetadata[diskIndex].Erasure.Checksums { if info.Name == partName { filePath := pathJoin(xlDisks[diskIndex].String(), bucket, object, partName) - f, err := os.OpenFile(filePath, os.O_WRONLY, 0) + f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_SYNC, 0) if err != nil { t.Fatalf("Failed to open %s: %s\n", filePath, err) }