remove safeMode behavior in startup (#10645)

In almost all scenarios MinIO now is
mostly ready for all sub-systems
independently, safe-mode is not useful
anymore and do not serve its original
intended purpose.

allow server to be fully functional
even with config partially configured,
this is to cater for availability of actual
I/O v/s manually fixing the server.

In k8s like environments it will never make
sense to take pod into safe-mode state,
because there is no real access to perform
any remote operation on them.
This commit is contained in:
Harshavardhana 2020-10-09 09:59:52 -07:00 committed by GitHub
parent 1738eb24b1
commit a0d0645128
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 139 additions and 268 deletions

View file

@ -42,7 +42,7 @@ import (
func validateAdminReqConfigKV(ctx context.Context, w http.ResponseWriter, r *http.Request) (auth.Credentials, ObjectLayer) {
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
return auth.Credentials{}, nil

View file

@ -35,7 +35,7 @@ func validateAdminUsersReq(ctx context.Context, w http.ResponseWriter, r *http.R
var adminAPIErr APIErrorCode
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || globalNotificationSys == nil || globalIAMSys == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
return nil, cred
@ -386,7 +386,7 @@ func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Reque
defer logger.AuditLog(w, r, "AddServiceAccount", mustGetClaimsFromToken(r))
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || globalNotificationSys == nil || globalIAMSys == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
return
@ -465,7 +465,7 @@ func (a adminAPIHandlers) ListServiceAccounts(w http.ResponseWriter, r *http.Req
defer logger.AuditLog(w, r, "ListServiceAccounts", mustGetClaimsFromToken(r))
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || globalNotificationSys == nil || globalIAMSys == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
return
@ -520,7 +520,7 @@ func (a adminAPIHandlers) DeleteServiceAccount(w http.ResponseWriter, r *http.Re
defer logger.AuditLog(w, r, "DeleteServiceAccount", mustGetClaimsFromToken(r))
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || globalNotificationSys == nil || globalIAMSys == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
return
@ -579,7 +579,7 @@ func (a adminAPIHandlers) AccountUsageInfoHandler(w http.ResponseWriter, r *http
defer logger.AuditLog(w, r, "AccountUsageInfo", mustGetClaimsFromToken(r))
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || globalNotificationSys == nil || globalIAMSys == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
return

View file

@ -899,7 +899,7 @@ func validateAdminReq(ctx context.Context, w http.ResponseWriter, r *http.Reques
var cred auth.Credentials
var adminAPIErr APIErrorCode
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || globalNotificationSys == nil {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
return nil, cred
@ -1490,11 +1490,7 @@ func (a adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Reque
}
}
mode := "safemode"
if newObjectLayerFn() != nil {
mode = "online"
}
mode := "online"
server := getLocalServerProperty(globalEndpoints, r)
servers := globalNotificationSys.ServerInfo()
servers = append(servers, server)

View file

@ -808,7 +808,7 @@ func (h *healSequence) traverseAndHeal() {
func (h *healSequence) healMinioSysMeta(metaPrefix string) func() error {
return func() error {
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil {
return errServerNotInitialized
}
@ -844,7 +844,7 @@ func (h *healSequence) healDiskFormat() error {
}
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil {
return errServerNotInitialized
}
@ -864,7 +864,7 @@ func (h *healSequence) healBuckets(bucketsOnly bool) error {
}
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil {
return errServerNotInitialized
}
@ -886,7 +886,7 @@ func (h *healSequence) healBuckets(bucketsOnly bool) error {
// healBucket - traverses and heals given bucket
func (h *healSequence) healBucket(bucket string, bucketsOnly bool) error {
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil {
return errServerNotInitialized
}
@ -932,7 +932,7 @@ func (h *healSequence) healBucket(bucket string, bucketsOnly bool) error {
// healObject - heal the given object and record result
func (h *healSequence) healObject(bucket, object, versionID string) error {
// Get current object layer instance.
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil {
return errServerNotInitialized
}

View file

@ -703,10 +703,6 @@ func generateMultiDeleteResponse(quiet bool, deletedObjects []DeletedObject, err
}
func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
if newObjectLayerFn() == nil {
// Server still in safe mode.
w.Header().Set(xhttp.MinIOServerStatus, "safemode")
}
setCommonHeaders(w)
if mType != mimeNone {
w.Header().Set(xhttp.ContentType, string(mType))
@ -773,10 +769,6 @@ func writeErrorResponse(ctx context.Context, w http.ResponseWriter, err APIError
// The request is from browser and also if browser
// is enabled we need to redirect.
if browser && globalBrowserEnabled {
if newObjectLayerFn() == nil {
// server still in safe mode.
w.Header().Set(xhttp.MinIOServerStatus, "safemode")
}
w.Header().Set(xhttp.Location, minioReservedBucketPath+reqURL.Path)
w.WriteHeader(http.StatusTemporaryRedirect)
return

View file

@ -32,28 +32,15 @@ func newHTTPServerFn() *xhttp.Server {
return globalHTTPServer
}
func newObjectLayerWithoutSafeModeFn() ObjectLayer {
globalObjLayerMutex.Lock()
defer globalObjLayerMutex.Unlock()
return globalObjectAPI
}
func newObjectLayerFn() ObjectLayer {
globalObjLayerMutex.Lock()
defer globalObjLayerMutex.Unlock()
if globalSafeMode {
return nil
}
return globalObjectAPI
}
func newCachedObjectLayerFn() CacheObjectLayer {
globalObjLayerMutex.Lock()
defer globalObjLayerMutex.Unlock()
if globalSafeMode {
return nil
}
return globalCacheObjectAPI
}

View file

@ -34,7 +34,7 @@ func NewBucketSSEConfigSys() *BucketSSEConfigSys {
// Get - gets bucket encryption config for the given bucket.
func (sys *BucketSSEConfigSys) Get(bucket string) (*bucketsse.BucketSSEConfig, error) {
if globalIsGateway {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return nil, errServerNotInitialized
}

View file

@ -31,7 +31,7 @@ type LifecycleSys struct{}
// Get - gets lifecycle config associated to a given bucket name.
func (sys *LifecycleSys) Get(bucketName string) (lc *lifecycle.Lifecycle, err error) {
if globalIsGateway {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return nil, errServerNotInitialized
}

View file

@ -72,7 +72,7 @@ func (sys *BucketMetadataSys) Set(bucket string, meta BucketMetadata) {
// Update update bucket metadata for the specified config file.
// The configData data should not be modified after being sent here.
func (sys *BucketMetadataSys) Update(bucket string, configFile string, configData []byte) error {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return errServerNotInitialized
}
@ -275,7 +275,7 @@ func (sys *BucketMetadataSys) GetLifecycleConfig(bucket string) (*lifecycle.Life
func (sys *BucketMetadataSys) GetNotificationConfig(bucket string) (*event.Config, error) {
if globalIsGateway && globalGatewayName == NASBackendGateway {
// Only needed in case of NAS gateway.
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return nil, errServerNotInitialized
}
@ -313,7 +313,7 @@ func (sys *BucketMetadataSys) GetSSEConfig(bucket string) (*bucketsse.BucketSSEC
// The returned object may not be modified.
func (sys *BucketMetadataSys) GetPolicyConfig(bucket string) (*policy.Policy, error) {
if globalIsGateway {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return nil, errServerNotInitialized
}
@ -376,7 +376,7 @@ func (sys *BucketMetadataSys) GetBucketTargetsConfig(bucket string) (*madmin.Buc
// GetConfig returns a specific configuration from the bucket metadata.
// The returned object may not be modified.
func (sys *BucketMetadataSys) GetConfig(bucket string) (BucketMetadata, error) {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return newBucketMetadata(bucket), errServerNotInitialized
}

View file

@ -33,7 +33,7 @@ type BucketObjectLockSys struct{}
// Get - Get retention configuration.
func (sys *BucketObjectLockSys) Get(bucketName string) (r objectlock.Retention, err error) {
if globalIsGateway {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return r, errServerNotInitialized
}

View file

@ -63,7 +63,7 @@ func parseBucketQuota(bucket string, data []byte) (quotaCfg *madmin.BucketQuota,
}
func (sys *BucketQuotaSys) check(ctx context.Context, bucket string, size int64) error {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return errServerNotInitialized
}

View file

@ -38,7 +38,7 @@ import (
// gets replication config associated to a given bucket name.
func getReplicationConfig(ctx context.Context, bucketName string) (rc *replication.Config, err error) {
if globalIsGateway {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return nil, errServerNotInitialized
}

View file

@ -462,7 +462,7 @@ func (f *folderScanner) scanQueuedLevels(ctx context.Context, folders []cachedFo
continue
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
continue
}

View file

@ -300,7 +300,6 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
// Once endpoints are finalized, initialize the new object api in safe mode.
globalObjLayerMutex.Lock()
globalSafeMode = true
globalObjectAPI = newObject
globalObjLayerMutex.Unlock()
@ -325,7 +324,7 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
if enableIAMOps {
// Initialize IAM sys.
startBackgroundIAMLoad(GlobalContext)
startBackgroundIAMLoad(GlobalContext, newObject)
}
if globalCacheConfig.Enabled {
@ -353,11 +352,6 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
// - compression
verifyObjectLayerFeatures("gateway "+gatewayName, newObject)
// Disable safe mode operation, after all initialization is over.
globalObjLayerMutex.Lock()
globalSafeMode = false
globalObjLayerMutex.Unlock()
// Prints the formatted startup message once object layer is initialized.
if !globalCLIContext.Quiet {
mode := globalMinioModeGatewayPrefix + gatewayName

View file

@ -268,11 +268,6 @@ var (
globalBackgroundHealRoutine *healRoutine
globalBackgroundHealState *allHealState
// Only enabled when one of the sub-systems fail
// to initialize, this allows for administrators to
// fix the system.
globalSafeMode bool
// If writes to FS backend should be O_SYNC.
globalFSOSync bool

View file

@ -411,8 +411,8 @@ func (sys *IAMSys) doIAMConfigMigration(ctx context.Context) error {
// Loads IAM users and policies in background, any un-handled
// error means this code can potentially crash the server
// in such a situation manual intervention is necessary.
func startBackgroundIAMLoad(ctx context.Context) {
go globalIAMSys.Init(ctx, newObjectLayerWithoutSafeModeFn())
func startBackgroundIAMLoad(ctx context.Context, objAPI ObjectLayer) {
go globalIAMSys.Init(ctx, objAPI)
}
// Init - initializes config system by reading entries from config/iam
@ -514,7 +514,7 @@ func (sys *IAMSys) Init(ctx context.Context, objAPI ObjectLayer) {
// DeletePolicy - deletes a canned policy from backend or etcd.
func (sys *IAMSys) DeletePolicy(policyName string) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -567,7 +567,7 @@ func (sys *IAMSys) DeletePolicy(policyName string) error {
// InfoPolicy - expands the canned policy into its JSON structure.
func (sys *IAMSys) InfoPolicy(policyName string) (iampolicy.Policy, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return iampolicy.Policy{}, errServerNotInitialized
}
@ -585,7 +585,7 @@ func (sys *IAMSys) InfoPolicy(policyName string) (iampolicy.Policy, error) {
// ListPolicies - lists all canned policies.
func (sys *IAMSys) ListPolicies() (map[string]iampolicy.Policy, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return nil, errServerNotInitialized
}
@ -607,7 +607,7 @@ func (sys *IAMSys) ListPolicies() (map[string]iampolicy.Policy, error) {
// SetPolicy - sets a new name policy.
func (sys *IAMSys) SetPolicy(policyName string, p iampolicy.Policy) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -629,7 +629,7 @@ func (sys *IAMSys) SetPolicy(policyName string, p iampolicy.Policy) error {
// DeleteUser - delete user (only for long-term users not STS users).
func (sys *IAMSys) DeleteUser(accessKey string) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -699,7 +699,7 @@ func (sys *IAMSys) currentPolicies(policyName string) string {
// SetTempUser - set temporary user credentials, these credentials have an expiry.
func (sys *IAMSys) SetTempUser(accessKey string, cred auth.Credentials, policyName string) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -749,7 +749,7 @@ func (sys *IAMSys) SetTempUser(accessKey string, cred auth.Credentials, policyNa
// ListUsers - list all users.
func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return nil, errServerNotInitialized
}
@ -786,7 +786,7 @@ func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) {
// IsTempUser - returns if given key is a temporary user.
func (sys *IAMSys) IsTempUser(name string) (bool, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return false, errServerNotInitialized
}
@ -804,7 +804,7 @@ func (sys *IAMSys) IsTempUser(name string) (bool, error) {
// IsServiceAccount - returns if given key is a service account
func (sys *IAMSys) IsServiceAccount(name string) (bool, string, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return false, "", errServerNotInitialized
}
@ -826,7 +826,7 @@ func (sys *IAMSys) IsServiceAccount(name string) (bool, string, error) {
// GetUserInfo - get info on a user.
func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return u, errServerNotInitialized
}
@ -872,7 +872,7 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
// SetUserStatus - sets current user status, supports disabled or enabled.
func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -918,7 +918,7 @@ func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus)
// NewServiceAccount - create a new service account
func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, sessionPolicy *iampolicy.Policy) (auth.Credentials, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return auth.Credentials{}, errServerNotInitialized
}
@ -985,7 +985,7 @@ func (sys *IAMSys) NewServiceAccount(ctx context.Context, parentUser string, ses
// ListServiceAccounts - lists all services accounts associated to a specific user
func (sys *IAMSys) ListServiceAccounts(ctx context.Context, accessKey string) ([]string, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return nil, errServerNotInitialized
}
@ -1010,7 +1010,7 @@ func (sys *IAMSys) ListServiceAccounts(ctx context.Context, accessKey string) ([
// GetServiceAccountParent - gets information about a service account
func (sys *IAMSys) GetServiceAccountParent(ctx context.Context, accessKey string) (string, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return "", errServerNotInitialized
}
@ -1027,7 +1027,7 @@ func (sys *IAMSys) GetServiceAccountParent(ctx context.Context, accessKey string
// DeleteServiceAccount - delete a service account
func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -1056,7 +1056,7 @@ func (sys *IAMSys) DeleteServiceAccount(ctx context.Context, accessKey string) e
// SetUser - set user credentials and policy.
func (sys *IAMSys) SetUser(accessKey string, uinfo madmin.UserInfo) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -1094,7 +1094,7 @@ func (sys *IAMSys) SetUser(accessKey string, uinfo madmin.UserInfo) error {
// SetUserSecretKey - sets user secret key
func (sys *IAMSys) SetUserSecretKey(accessKey string, secretKey string) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -1123,7 +1123,7 @@ func (sys *IAMSys) SetUserSecretKey(accessKey string, secretKey string) error {
// GetUser - get user credentials
func (sys *IAMSys) GetUser(accessKey string) (cred auth.Credentials, ok bool) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return cred, false
}
@ -1187,7 +1187,7 @@ func (sys *IAMSys) GetUser(accessKey string) (cred auth.Credentials, ok bool) {
// AddUsersToGroup - adds users to a group, creating the group if
// needed. No error if user(s) already are in the group.
func (sys *IAMSys) AddUsersToGroup(group string, members []string) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -1248,7 +1248,7 @@ func (sys *IAMSys) AddUsersToGroup(group string, members []string) error {
// RemoveUsersFromGroup - remove users from group. If no users are
// given, and the group is empty, deletes the group as well.
func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -1329,7 +1329,7 @@ func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error {
// SetGroupStatus - enable/disabled a group
func (sys *IAMSys) SetGroupStatus(group string, enabled bool) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -1365,7 +1365,7 @@ func (sys *IAMSys) SetGroupStatus(group string, enabled bool) error {
// GetGroupDescription - builds up group description
func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return gd, errServerNotInitialized
}
@ -1406,7 +1406,7 @@ func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err e
// ListGroups - lists groups.
func (sys *IAMSys) ListGroups() (r []string, err error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return r, errServerNotInitialized
}
@ -1430,7 +1430,7 @@ func (sys *IAMSys) ListGroups() (r []string, err error) {
// PolicyDBSet - sets a policy for a user or group in the PolicyDB.
func (sys *IAMSys) PolicyDBSet(name, policy string, isGroup bool) error {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return errServerNotInitialized
}
@ -1497,7 +1497,7 @@ func (sys *IAMSys) policyDBSet(name, policyName string, userType IAMUserType, is
// be a member of multiple groups, this function returns an array of
// applicable policies (each group is mapped to at most one policy).
func (sys *IAMSys) PolicyDBGet(name string, isGroup bool) ([]string, error) {
objectAPI := newObjectLayerWithoutSafeModeFn()
objectAPI := newObjectLayerFn()
if objectAPI == nil || sys == nil || sys.store == nil {
return nil, errServerNotInitialized
}

View file

@ -35,7 +35,7 @@ const (
lockMaintenanceInterval = 30 * time.Second
// Lock validity check interval.
lockValidityCheckInterval = 2 * time.Minute
lockValidityCheckInterval = 30 * time.Second
)
// To abstract a node over network.
@ -242,7 +242,7 @@ func getLongLivedLocks(interval time.Duration) map[Endpoint][]nameLockRequesterI
//
// We will ignore the error, and we will retry later to get a resolve on this lock
func lockMaintenance(ctx context.Context, interval time.Duration) error {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return nil
}
@ -332,7 +332,7 @@ func startLockMaintenance(ctx context.Context) {
// no need to start the lock maintenance
// if ObjectAPI is not initialized.
for {
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
time.Sleep(time.Second)
continue

View file

@ -161,7 +161,7 @@ func gatewayMetricsPrometheus(ch chan<- prometheus.Metric) {
return
}
objLayer := newObjectLayerWithoutSafeModeFn()
objLayer := newObjectLayerFn()
// Service not initialized yet
if objLayer == nil {
return
@ -372,7 +372,7 @@ func networkMetricsPrometheus(ch chan<- prometheus.Metric) {
// Populates prometheus with bucket usage metrics, this metrics
// is only enabled if crawler is enabled.
func bucketUsageMetricsPrometheus(ch chan<- prometheus.Metric) {
objLayer := newObjectLayerWithoutSafeModeFn()
objLayer := newObjectLayerFn()
// Service not initialized yet
if objLayer == nil {
return
@ -435,7 +435,7 @@ func bucketUsageMetricsPrometheus(ch chan<- prometheus.Metric) {
// collects storage metrics for MinIO server in Prometheus specific format
// and sends to given channel
func storageMetricsPrometheus(ch chan<- prometheus.Metric) {
objLayer := newObjectLayerWithoutSafeModeFn()
objLayer := newObjectLayerFn()
// Service not initialized yet
if objLayer == nil {
return

View file

@ -613,18 +613,12 @@ func (sys *NotificationSys) Init(ctx context.Context, buckets []BucketInfo, objA
return errServerNotInitialized
}
// In gateway mode, notifications are not supported.
// In gateway mode, notifications are not supported - except NAS gateway.
if globalIsGateway && !objAPI.IsNotificationSupported() {
return nil
}
if globalConfigTargetList != nil {
for _, target := range globalConfigTargetList.Targets() {
if err := sys.targetList.Add(target); err != nil {
return err
}
}
}
logger.LogIf(ctx, sys.targetList.Add(globalConfigTargetList.Targets()...))
go func() {
for res := range sys.targetResCh {

View file

@ -64,7 +64,7 @@ func (s *peerRESTServer) DeletePolicyHandler(w http.ResponseWriter, r *http.Requ
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -97,7 +97,7 @@ func (s *peerRESTServer) LoadPolicyHandler(w http.ResponseWriter, r *http.Reques
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -130,7 +130,7 @@ func (s *peerRESTServer) LoadPolicyMappingHandler(w http.ResponseWriter, r *http
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -164,7 +164,7 @@ func (s *peerRESTServer) DeleteServiceAccountHandler(w http.ResponseWriter, r *h
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -197,7 +197,7 @@ func (s *peerRESTServer) LoadServiceAccountHandler(w http.ResponseWriter, r *htt
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -230,7 +230,7 @@ func (s *peerRESTServer) DeleteUserHandler(w http.ResponseWriter, r *http.Reques
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -263,7 +263,7 @@ func (s *peerRESTServer) LoadUserHandler(w http.ResponseWriter, r *http.Request)
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -307,7 +307,7 @@ func (s *peerRESTServer) LoadGroupHandler(w http.ResponseWriter, r *http.Request
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -609,7 +609,7 @@ func (s *peerRESTServer) LoadBucketMetadataHandler(w http.ResponseWriter, r *htt
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -657,7 +657,7 @@ func (s *peerRESTServer) ReloadFormatHandler(w http.ResponseWriter, r *http.Requ
return
}
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
s.writeErrorResponse(w, errServerNotInitialized)
return
@ -767,7 +767,7 @@ func (s *peerRESTServer) GetLocalDiskIDs(w http.ResponseWriter, r *http.Request)
ctx := newContext(r, w, "GetLocalDiskIDs")
objLayer := newObjectLayerWithoutSafeModeFn()
objLayer := newObjectLayerFn()
// Service not initialized yet
if objLayer == nil {

View file

@ -186,7 +186,7 @@ func newAllSubsystems() {
globalBucketTargetSys = NewBucketTargetSys()
}
func initSafeMode(ctx context.Context, newObject ObjectLayer) (err error) {
func initServer(ctx context.Context, newObject ObjectLayer) (err error) {
// Create cancel context to control 'newRetryTimer' go routine.
retryCtx, cancel := context.WithCancel(ctx)
@ -199,33 +199,33 @@ func initSafeMode(ctx context.Context, newObject ObjectLayer) (err error) {
// appropriately. This is also true for rotation of encrypted
// content.
txnLk := newObject.NewNSLock(retryCtx, minioMetaBucket, minioConfigPrefix+"/transaction.lock")
var locked bool
defer func(txnLk RWLocker) {
if locked {
txnLk.Unlock()
}
defer func() {
if err != nil {
var cerr config.Err
// For any config error, we don't need to drop into safe-mode
// instead its a user error and should be fixed by user.
if errors.As(err, &cerr) {
logger.FatalIf(err, "Unable to initialize the server")
return
}
// If context was canceled
if errors.Is(err, context.Canceled) {
logger.FatalIf(err, "Server startup canceled upon user request")
return
}
// Prints the formatted startup message in safe mode operation.
// Drops-into safe mode where users need to now manually recover
// the server.
printStartupSafeModeMessage(getAPIEndpoints(), err)
<-globalOSSignalCh
}
}(txnLk)
// Prints the formatted startup message, if err is not nil then it prints additional information as well.
printStartupMessage(getAPIEndpoints(), err)
if globalActiveCred.Equal(auth.DefaultCredentials) {
msg := fmt.Sprintf("Detected default credentials '%s', please change the credentials immediately using 'MINIO_ACCESS_KEY' and 'MINIO_SECRET_KEY'", globalActiveCred)
logger.StartupMessage(color.RedBold(msg))
}
<-globalOSSignalCh
}()
// Enable background operations for erasure coding
if globalIsErasure {
@ -256,9 +256,6 @@ func initSafeMode(ctx context.Context, newObject ObjectLayer) (err error) {
continue
}
// locked successful
locked = true
// These messages only meant primarily for distributed setup, so only log during distributed setup.
if globalIsDistErasure {
logger.Info("Waiting for all MinIO sub-systems to be initialized.. lock acquired")
@ -270,7 +267,8 @@ func initSafeMode(ctx context.Context, newObject ObjectLayer) (err error) {
if err = handleEncryptedConfigBackend(newObject); err == nil {
// Upon success migrating the config, initialize all sub-systems
// if all sub-systems initialized successfully return right away
if err = initAllSubsystems(retryCtx, newObject); err == nil {
if err = initAllSubsystems(ctx, newObject); err == nil {
txnLk.Unlock()
// All successful return.
if globalIsDistErasure {
// These messages only meant primarily for distributed setup, so only log during distributed setup.
@ -280,6 +278,8 @@ func initSafeMode(ctx context.Context, newObject ObjectLayer) (err error) {
}
}
txnLk.Unlock() // Unlock the transaction lock and allow other nodes to acquire the lock if possible.
// One of these retriable errors shall be retried.
if errors.Is(err, errDiskNotFound) ||
errors.Is(err, errConfigNotFound) ||
@ -288,8 +288,6 @@ func initSafeMode(ctx context.Context, newObject ObjectLayer) (err error) {
errors.As(err, &wquorum) ||
isErrBucketNotFound(err) {
logger.Info("Waiting for all MinIO sub-systems to be initialized.. possible cause (%v)", err)
txnLk.Unlock() // Unlock the transaction lock and allow other nodes to acquire the lock if possible.
locked = false
continue
}
@ -299,7 +297,7 @@ func initSafeMode(ctx context.Context, newObject ObjectLayer) (err error) {
// Return an error when retry is canceled or deadlined
if err = retryCtx.Err(); err != nil {
return fmt.Errorf("Unable to initialize sub-systems: %w", err)
return err
}
// Retry was canceled successfully.
@ -314,13 +312,13 @@ func initAllSubsystems(ctx context.Context, newObject ObjectLayer) (err error) {
// ensures top level retry works accordingly.
// List buckets to heal, and be re-used for loading configs.
var buckets []BucketInfo
rquorum := InsufficientReadQuorum{}
wquorum := InsufficientWriteQuorum{}
if globalIsErasure {
buckets, err = newObject.ListBucketsHeal(ctx)
if err != nil {
return fmt.Errorf("Unable to list buckets to heal: %w", err)
}
rquorum := InsufficientReadQuorum{}
wquorum := InsufficientWriteQuorum{}
for _, bucket := range buckets {
if err = newObject.MakeBucketWithLocation(ctx, bucket.Name, BucketOptions{}); err != nil {
if errors.As(err, &wquorum) || errors.As(err, &rquorum) {
@ -344,7 +342,16 @@ func initAllSubsystems(ctx context.Context, newObject ObjectLayer) (err error) {
// Initialize config system.
if err = globalConfigSys.Init(newObject); err != nil {
return fmt.Errorf("Unable to initialize config system: %w", err)
if errors.Is(err, errDiskNotFound) ||
errors.Is(err, errConfigNotFound) ||
errors.Is(err, context.DeadlineExceeded) ||
errors.As(err, &rquorum) ||
errors.As(err, &wquorum) ||
isErrBucketNotFound(err) {
return fmt.Errorf("Unable to initialize config system: %w", err)
}
// Any other config errors we simply print a message and proceed forward.
logger.LogIf(ctx, err)
}
// Populate existing buckets to the etcd backend
@ -353,20 +360,25 @@ func initAllSubsystems(ctx context.Context, newObject ObjectLayer) (err error) {
go initFederatorBackend(buckets, newObject)
}
// Initialize bucket metadata sub-system.
if err = globalBucketMetadataSys.Init(ctx, buckets, newObject); err != nil {
return fmt.Errorf("Unable to initialize bucket metadata sub-system: %w", err)
if globalCacheConfig.Enabled {
// initialize the new disk cache objects.
var cacheAPI CacheObjectLayer
cacheAPI, err = newServerCacheObjects(ctx, globalCacheConfig)
logger.FatalIf(err, "Unable to initialize disk caching")
globalObjLayerMutex.Lock()
globalCacheObjectAPI = cacheAPI
globalObjLayerMutex.Unlock()
}
// Initialize bucket metadata sub-system.
globalBucketMetadataSys.Init(ctx, buckets, newObject)
// Initialize notification system.
if err = globalNotificationSys.Init(ctx, buckets, newObject); err != nil {
return fmt.Errorf("Unable to initialize notification system: %w", err)
}
globalNotificationSys.Init(ctx, buckets, newObject)
// Initialize bucket targets sub-system.
if err = globalBucketTargetSys.Init(ctx, buckets, newObject); err != nil {
return fmt.Errorf("Unable to initialize bucket target sub-system: %w", err)
}
globalBucketTargetSys.Init(ctx, buckets, newObject)
return nil
}
@ -488,42 +500,15 @@ func serverMain(ctx *cli.Context) {
// Once endpoints are finalized, initialize the new object api in safe mode.
globalObjLayerMutex.Lock()
globalSafeMode = true
globalObjectAPI = newObject
globalObjLayerMutex.Unlock()
go initDataCrawler(GlobalContext, newObject)
logger.FatalIf(initSafeMode(GlobalContext, newObject), "Unable to initialize server switching into safe-mode")
// Initialize users credentials and policies in background.
go startBackgroundIAMLoad(GlobalContext)
go startBackgroundIAMLoad(GlobalContext, newObject)
if globalCacheConfig.Enabled {
// initialize the new disk cache objects.
var cacheAPI CacheObjectLayer
cacheAPI, err = newServerCacheObjects(GlobalContext, globalCacheConfig)
logger.FatalIf(err, "Unable to initialize disk caching")
globalObjLayerMutex.Lock()
globalCacheObjectAPI = cacheAPI
globalObjLayerMutex.Unlock()
}
// Disable safe mode operation, after all initialization is over.
globalObjLayerMutex.Lock()
globalSafeMode = false
globalObjLayerMutex.Unlock()
// Prints the formatted startup message once object layer is initialized.
printStartupMessage(getAPIEndpoints())
if globalActiveCred.Equal(auth.DefaultCredentials) {
msg := fmt.Sprintf("Detected default credentials '%s', please change the credentials immediately using 'MINIO_ACCESS_KEY' and 'MINIO_SECRET_KEY'", globalActiveCred)
logger.StartupMessage(color.RedBold(msg))
}
<-globalOSSignalCh
initServer(GlobalContext, newObject)
}
// Initialize object layer with the supplied disks, objectLayer is nil upon any error.

View file

@ -32,13 +32,12 @@ import (
// Documentation links, these are part of message printing code.
const (
mcQuickStartGuide = "https://docs.min.io/docs/minio-client-quickstart-guide"
mcAdminQuickStartGuide = "https://docs.min.io/docs/minio-admin-complete-guide.html"
goQuickStartGuide = "https://docs.min.io/docs/golang-client-quickstart-guide"
jsQuickStartGuide = "https://docs.min.io/docs/javascript-client-quickstart-guide"
javaQuickStartGuide = "https://docs.min.io/docs/java-client-quickstart-guide"
pyQuickStartGuide = "https://docs.min.io/docs/python-client-quickstart-guide"
dotnetQuickStartGuide = "https://docs.min.io/docs/dotnet-client-quickstart-guide"
mcQuickStartGuide = "https://docs.min.io/docs/minio-client-quickstart-guide"
goQuickStartGuide = "https://docs.min.io/docs/golang-client-quickstart-guide"
jsQuickStartGuide = "https://docs.min.io/docs/javascript-client-quickstart-guide"
javaQuickStartGuide = "https://docs.min.io/docs/java-client-quickstart-guide"
pyQuickStartGuide = "https://docs.min.io/docs/python-client-quickstart-guide"
dotnetQuickStartGuide = "https://docs.min.io/docs/dotnet-client-quickstart-guide"
)
// generates format string depending on the string length and padding.
@ -52,65 +51,13 @@ func mustGetStorageInfo(objAPI ObjectLayer) StorageInfo {
return storageInfo
}
func printStartupSafeModeMessage(apiEndpoints []string, err error) {
logStartupMessage(color.RedBold("Server startup failed with '%v'", err))
logStartupMessage(color.RedBold("Server switching to safe mode"))
logStartupMessage(color.RedBold("Please use 'mc admin config' commands fix this issue"))
// Object layer is initialized then print StorageInfo in safe mode.
objAPI := newObjectLayerWithoutSafeModeFn()
if objAPI != nil {
if msg := getStorageInfoMsgSafeMode(mustGetStorageInfo(objAPI)); msg != "" {
logStartupMessage(msg)
}
}
// Get saved credentials.
cred := globalActiveCred
// Get saved region.
region := globalServerRegion
strippedAPIEndpoints := stripStandardPorts(apiEndpoints)
apiEndpointStr := strings.Join(strippedAPIEndpoints, " ")
// Colorize the message and print.
logStartupMessage(color.Red("Endpoint: ") + color.Bold(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 1), apiEndpointStr)))
if color.IsTerminal() && !globalCLIContext.Anonymous {
logStartupMessage(color.Red("AccessKey: ") + color.Bold(fmt.Sprintf("%s ", cred.AccessKey)))
logStartupMessage(color.Red("SecretKey: ") + color.Bold(fmt.Sprintf("%s ", cred.SecretKey)))
if region != "" {
logStartupMessage(color.Red("Region: ") + color.Bold(fmt.Sprintf(getFormatStr(len(region), 3), region)))
}
}
// Prints `mc` cli configuration message chooses
// first endpoint as default.
alias := "myminio"
endPoint := strippedAPIEndpoints[0]
// Configure 'mc', following block prints platform specific information for minio client admin commands.
if color.IsTerminal() && !globalCLIContext.Anonymous {
logStartupMessage(color.RedBold("\nCommand-line Access: ") + mcAdminQuickStartGuide)
if runtime.GOOS == globalWindowsOSName {
mcMessage := fmt.Sprintf("> mc.exe alias set %s %s %s %s --api s3v4", alias,
endPoint, cred.AccessKey, cred.SecretKey)
logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
mcMessage = "> mc.exe admin config --help"
logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
} else {
mcMessage := fmt.Sprintf("$ mc alias set %s %s %s %s --api s3v4", alias,
endPoint, cred.AccessKey, cred.SecretKey)
logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
mcMessage = "$ mc admin config --help"
logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
}
}
}
// Prints the formatted startup message.
func printStartupMessage(apiEndpoints []string) {
func printStartupMessage(apiEndpoints []string, err error) {
if err != nil {
logStartupMessage(color.RedBold("Server startup failed with '%v'", err))
logStartupMessage(color.RedBold("Not all features may be available on this server"))
logStartupMessage(color.RedBold("Please use 'mc admin' commands to further investigate this issue"))
}
strippedAPIEndpoints := stripStandardPorts(apiEndpoints)
// If cache layer is enabled, print cache capacity.
@ -254,23 +201,6 @@ func printObjectAPIMsg() {
logStartupMessage(color.Blue(" .NET: ") + fmt.Sprintf(getFormatStr(len(dotnetQuickStartGuide), 6), dotnetQuickStartGuide))
}
// Get formatted disk/storage info message.
func getStorageInfoMsgSafeMode(storageInfo StorageInfo) string {
var msg string
var mcMessage string
if storageInfo.Backend.Type == BackendErasure {
if storageInfo.Backend.OfflineDisks.Sum() > 0 {
mcMessage = "Use `mc admin info` to look for latest server/disk info\n"
}
diskInfo := fmt.Sprintf(" %d Online, %d Offline. ", storageInfo.Backend.OnlineDisks.Sum(), storageInfo.Backend.OfflineDisks.Sum())
msg += color.Red("Status:") + fmt.Sprintf(getFormatStr(len(diskInfo), 8), diskInfo)
}
if len(mcMessage) > 0 {
msg = fmt.Sprintf("%s %s", mcMessage, msg)
}
return msg
}
// Get formatted disk/storage info message.
func getStorageInfoMsg(storageInfo StorageInfo) string {
var msg string

View file

@ -102,5 +102,5 @@ func TestPrintStartupMessage(t *testing.T) {
}
apiEndpoints := []string{"http://127.0.0.1:9000"}
printStartupMessage(apiEndpoints)
printStartupMessage(apiEndpoints, nil)
}

View file

@ -60,7 +60,7 @@ func handleSignals() {
}
}
if objAPI := newObjectLayerWithoutSafeModeFn(); objAPI != nil {
if objAPI := newObjectLayerFn(); objAPI != nil {
oerr = objAPI.Shutdown(context.Background())
logger.LogIf(context.Background(), oerr)
}

View file

@ -2077,16 +2077,10 @@ func registerAPIFunctions(muxRouter *mux.Router, objLayer ObjectLayer, apiFuncti
// operation
api := objectAPIHandlers{
ObjectAPI: func() ObjectLayer {
if !globalSafeMode {
return globalObjectAPI
}
return nil
return globalObjectAPI
},
CacheAPI: func() CacheObjectLayer {
if !globalSafeMode {
return globalCacheObjectAPI
}
return nil
return globalCacheObjectAPI
},
}

View file

@ -366,7 +366,7 @@ func (s *xlStorage) CrawlAndGetDataUsage(ctx context.Context, cache dataUsageCac
}
// Get object api
objAPI := newObjectLayerWithoutSafeModeFn()
objAPI := newObjectLayerFn()
if objAPI == nil {
return cache, errServerNotInitialized
}

View file

@ -86,6 +86,10 @@ func (list *TargetList) Remove(targetIDSet TargetIDSet) {
// Targets - list all targets
func (list *TargetList) Targets() []Target {
if list == nil {
return []Target{}
}
list.RLock()
defer list.RUnlock()