IAM: Block while loading users (#11671)

While starting up a request that needs all IAM data will start another load operation if the first on startup hasn't finished. This slows down both operations.

Block these requests until initial load has completed.

Blocking calls will be ListPolicies, ListUsers, ListServiceAccounts, ListGroups - and the calls that eventually trigger these. These will wait for the initial load to complete.

Fixes issue seen in #11305
This commit is contained in:
Klaus Post 2021-03-02 17:08:25 -08:00 committed by GitHub
parent f96d4cf7d3
commit cd9e30c0f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -221,7 +221,9 @@ type IAMSys struct {
// Persistence layer for IAM subsystem // Persistence layer for IAM subsystem
store IAMStorageAPI store IAMStorageAPI
storeFallback bool
// configLoaded will be closed and remain so after first load.
configLoaded chan struct{}
} }
// IAMUserType represents a user type inside MinIO server // IAMUserType represents a user type inside MinIO server
@ -554,7 +556,11 @@ func (sys *IAMSys) Load(ctx context.Context, store IAMStorageAPI) error {
} }
sys.buildUserGroupMemberships() sys.buildUserGroupMemberships()
sys.storeFallback = false select {
case <-sys.configLoaded:
default:
close(sys.configLoaded)
}
return nil return nil
} }
@ -732,15 +738,7 @@ func (sys *IAMSys) ListPolicies() (map[string]iampolicy.Policy, error) {
return nil, errServerNotInitialized return nil, errServerNotInitialized
} }
sys.store.rlock() <-sys.configLoaded
fallback := sys.storeFallback
sys.store.runlock()
if fallback {
if err := sys.store.loadAll(context.Background(), sys); err != nil {
return nil, err
}
}
sys.store.rlock() sys.store.rlock()
defer sys.store.runlock() defer sys.store.runlock()
@ -915,15 +913,7 @@ func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) {
return nil, errIAMActionNotAllowed return nil, errIAMActionNotAllowed
} }
sys.store.rlock() <-sys.configLoaded
fallback := sys.storeFallback
sys.store.runlock()
if fallback {
if err := sys.store.loadAll(context.Background(), sys); err != nil {
return nil, err
}
}
sys.store.rlock() sys.store.rlock()
defer sys.store.runlock() defer sys.store.runlock()
@ -995,10 +985,9 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
return u, errServerNotInitialized return u, errServerNotInitialized
} }
sys.store.rlock() select {
fallback := sys.storeFallback case <-sys.configLoaded:
sys.store.runlock() default:
if fallback {
sys.loadUserFromStore(name) sys.loadUserFromStore(name)
} }
@ -1178,15 +1167,7 @@ func (sys *IAMSys) ListServiceAccounts(ctx context.Context, accessKey string) ([
return nil, errServerNotInitialized return nil, errServerNotInitialized
} }
sys.store.rlock() <-sys.configLoaded
fallback := sys.storeFallback
sys.store.runlock()
if fallback {
if err := sys.store.loadAll(context.Background(), sys); err != nil {
return nil, err
}
}
sys.store.rlock() sys.store.rlock()
defer sys.store.runlock() defer sys.store.runlock()
@ -1355,11 +1336,12 @@ func (sys *IAMSys) GetUser(accessKey string) (cred auth.Credentials, ok bool) {
return cred, false return cred, false
} }
sys.store.rlock() fallback := false
fallback := sys.storeFallback select {
sys.store.runlock() case <-sys.configLoaded:
if fallback { default:
sys.loadUserFromStore(accessKey) sys.loadUserFromStore(accessKey)
fallback = true
} }
sys.store.rlock() sys.store.rlock()
@ -1619,15 +1601,7 @@ func (sys *IAMSys) ListGroups() (r []string, err error) {
return nil, errIAMActionNotAllowed return nil, errIAMActionNotAllowed
} }
sys.store.rlock() <-sys.configLoaded
fallback := sys.storeFallback
sys.store.runlock()
if fallback {
if err := sys.store.loadAll(context.Background(), sys); err != nil {
return nil, err
}
}
sys.store.rlock() sys.store.rlock()
defer sys.store.runlock() defer sys.store.runlock()
@ -2182,6 +2156,6 @@ func NewIAMSys() *IAMSys {
iamGroupPolicyMap: make(map[string]MappedPolicy), iamGroupPolicyMap: make(map[string]MappedPolicy),
iamGroupsMap: make(map[string]GroupInfo), iamGroupsMap: make(map[string]GroupInfo),
iamUserGroupMemberships: make(map[string]set.StringSet), iamUserGroupMemberships: make(map[string]set.StringSet),
storeFallback: true, configLoaded: make(chan struct{}),
} }
} }