mirror of
https://github.com/minio/minio.git
synced 2025-05-21 09:33:50 -04:00
fix: use its own lock in serverConfigV17 (#4014)
Previously serverConfigV17 used a global lock that made any instance of serverConfigV17 depended on single global serverConfigMu. This patch fixes by having individual lock per instances.
This commit is contained in:
parent
2df8160f6a
commit
6e9c91f43a
@ -26,17 +26,21 @@ import (
|
|||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Read Write mutex for safe access to ServerConfig.
|
|
||||||
var serverConfigMu sync.RWMutex
|
|
||||||
|
|
||||||
// Config version
|
// Config version
|
||||||
const v17 = "17"
|
const v17 = "17"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// serverConfig server config.
|
||||||
|
serverConfig *serverConfigV17
|
||||||
|
serverConfigMu sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
// serverConfigV17 server configuration version '17' which is like
|
// serverConfigV17 server configuration version '17' which is like
|
||||||
// version '16' except it adds support for "format" parameter in
|
// version '16' except it adds support for "format" parameter in
|
||||||
// database event notification targets: PostgreSQL, MySQL, Redis and
|
// database event notification targets: PostgreSQL, MySQL, Redis and
|
||||||
// Elasticsearch.
|
// Elasticsearch.
|
||||||
type serverConfigV17 struct {
|
type serverConfigV17 struct {
|
||||||
|
sync.RWMutex
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
|
|
||||||
// S3 API configuration.
|
// S3 API configuration.
|
||||||
@ -51,6 +55,73 @@ type serverConfigV17 struct {
|
|||||||
Notify *notifier `json:"notify"`
|
Notify *notifier `json:"notify"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetVersion get current config version.
|
||||||
|
func (s *serverConfigV17) GetVersion() string {
|
||||||
|
s.RLock()
|
||||||
|
defer s.RUnlock()
|
||||||
|
|
||||||
|
return s.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRegion set new region.
|
||||||
|
func (s *serverConfigV17) SetRegion(region string) {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
s.Region = region
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRegion get current region.
|
||||||
|
func (s *serverConfigV17) GetRegion() string {
|
||||||
|
s.RLock()
|
||||||
|
defer s.RUnlock()
|
||||||
|
|
||||||
|
return s.Region
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCredentials set new credentials.
|
||||||
|
func (s *serverConfigV17) SetCredential(creds credential) {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
// Set updated credential.
|
||||||
|
s.Credential = creds
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCredentials get current credentials.
|
||||||
|
func (s *serverConfigV17) GetCredential() credential {
|
||||||
|
s.RLock()
|
||||||
|
defer s.RUnlock()
|
||||||
|
|
||||||
|
return s.Credential
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBrowser set if browser is enabled.
|
||||||
|
func (s *serverConfigV17) SetBrowser(b bool) {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
// Set the new value.
|
||||||
|
s.Browser = BrowserFlag(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCredentials get current credentials.
|
||||||
|
func (s *serverConfigV17) GetBrowser() bool {
|
||||||
|
s.RLock()
|
||||||
|
defer s.RUnlock()
|
||||||
|
|
||||||
|
return bool(s.Browser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save config.
|
||||||
|
func (s *serverConfigV17) Save() error {
|
||||||
|
s.RLock()
|
||||||
|
defer s.RUnlock()
|
||||||
|
|
||||||
|
// Save config file.
|
||||||
|
return quick.Save(getConfigFile(), s)
|
||||||
|
}
|
||||||
|
|
||||||
func newServerConfigV17() *serverConfigV17 {
|
func newServerConfigV17() *serverConfigV17 {
|
||||||
srvCfg := &serverConfigV17{
|
srvCfg := &serverConfigV17{
|
||||||
Version: v17,
|
Version: v17,
|
||||||
@ -91,20 +162,14 @@ func newConfig() error {
|
|||||||
// Initialize server config.
|
// Initialize server config.
|
||||||
srvCfg := newServerConfigV17()
|
srvCfg := newServerConfigV17()
|
||||||
|
|
||||||
// If env is set for a fresh start, save them to config file.
|
// If env is set override the credentials from config file.
|
||||||
if globalIsEnvCreds {
|
if globalIsEnvCreds {
|
||||||
srvCfg.SetCredential(globalActiveCred)
|
srvCfg.SetCredential(globalActiveCred)
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalIsEnvBrowser {
|
if globalIsEnvBrowser {
|
||||||
srvCfg.SetBrowser(globalIsBrowserEnabled)
|
srvCfg.SetBrowser(globalIsBrowserEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create config path.
|
|
||||||
if err := createConfigDir(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// hold the mutex lock before a new config is assigned.
|
// hold the mutex lock before a new config is assigned.
|
||||||
// Save the new config globally.
|
// Save the new config globally.
|
||||||
// unlock the mutex.
|
// unlock the mutex.
|
||||||
@ -116,42 +181,6 @@ func newConfig() error {
|
|||||||
return serverConfig.Save()
|
return serverConfig.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadConfig - loads a new config from disk, overrides params from env
|
|
||||||
// if found and valid
|
|
||||||
func loadConfig() error {
|
|
||||||
srvCfg := &serverConfigV17{
|
|
||||||
Region: globalMinioDefaultRegion,
|
|
||||||
Browser: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := quick.Load(getConfigFile(), srvCfg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if srvCfg.Version != v17 {
|
|
||||||
return fmt.Errorf("configuration version mismatch. Expected: ‘%s’, Got: ‘%s’", srvCfg.Version, v17)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If env is set override the credentials from config file.
|
|
||||||
if globalIsEnvCreds {
|
|
||||||
srvCfg.SetCredential(globalActiveCred)
|
|
||||||
} else {
|
|
||||||
globalActiveCred = srvCfg.GetCredential()
|
|
||||||
}
|
|
||||||
|
|
||||||
if globalIsEnvBrowser {
|
|
||||||
srvCfg.SetBrowser(globalIsBrowserEnabled)
|
|
||||||
} else {
|
|
||||||
globalIsBrowserEnabled = srvCfg.GetBrowser()
|
|
||||||
}
|
|
||||||
|
|
||||||
// hold the mutex lock before a new config is assigned.
|
|
||||||
serverConfigMu.Lock()
|
|
||||||
// Save the loaded config globally.
|
|
||||||
serverConfig = srvCfg
|
|
||||||
serverConfigMu.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// doCheckDupJSONKeys recursively detects duplicate json keys
|
// doCheckDupJSONKeys recursively detects duplicate json keys
|
||||||
func doCheckDupJSONKeys(key, value gjson.Result) error {
|
func doCheckDupJSONKeys(key, value gjson.Result) error {
|
||||||
// Key occurrences map of the current scope to count
|
// Key occurrences map of the current scope to count
|
||||||
@ -203,8 +232,8 @@ func checkDupJSONKeys(json string) error {
|
|||||||
return doCheckDupJSONKeys(rootKey, config)
|
return doCheckDupJSONKeys(rootKey, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateConfig checks for
|
// getValidConfig - returns valid server configuration
|
||||||
func validateConfig() error {
|
func getValidConfig() (*serverConfigV17, error) {
|
||||||
srvCfg := &serverConfigV17{
|
srvCfg := &serverConfigV17{
|
||||||
Region: globalMinioDefaultRegion,
|
Region: globalMinioDefaultRegion,
|
||||||
Browser: true,
|
Browser: true,
|
||||||
@ -212,128 +241,74 @@ func validateConfig() error {
|
|||||||
|
|
||||||
configFile := getConfigFile()
|
configFile := getConfigFile()
|
||||||
if _, err := quick.Load(configFile, srvCfg); err != nil {
|
if _, err := quick.Load(configFile, srvCfg); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if srvCfg.Version != v17 {
|
if srvCfg.Version != v17 {
|
||||||
// Older binary but newer config version.
|
return nil, fmt.Errorf("configuration version mismatch. Expected: ‘%s’, Got: ‘%s’", v17, srvCfg.Version)
|
||||||
// Config version can never be older as it would have migrated.
|
|
||||||
return fmt.Errorf("Expected config version: %s, newer config version found: %s", v17, srvCfg.Version)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load config file json and check for duplication json keys
|
// Load config file json and check for duplication json keys
|
||||||
jsonBytes, err := ioutil.ReadFile(configFile)
|
jsonBytes, err := ioutil.ReadFile(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := checkDupJSONKeys(string(jsonBytes)); err != nil {
|
if err = checkDupJSONKeys(string(jsonBytes)); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate region field
|
// Validate region field
|
||||||
if srvCfg.GetRegion() == "" {
|
if srvCfg.Region == "" {
|
||||||
return errors.New("Region config value cannot be empty")
|
return nil, errors.New("Region config value cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate credential fields only when
|
// Validate credential fields only when
|
||||||
// they are not set via the environment
|
// they are not set via the environment
|
||||||
if !globalIsEnvCreds {
|
|
||||||
if !srvCfg.Credential.IsValid() {
|
// Error out if global is env credential is not set and config has invalid credential
|
||||||
return errors.New("invalid credential")
|
if !globalIsEnvCreds && !srvCfg.Credential.IsValid() {
|
||||||
}
|
return nil, errors.New("invalid credential in config file " + configFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate logger field
|
// Validate logger field
|
||||||
if err := srvCfg.Logger.Validate(); err != nil {
|
if err = srvCfg.Logger.Validate(); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate notify field
|
// Validate notify field
|
||||||
if err := srvCfg.Notify.Validate(); err != nil {
|
if err = srvCfg.Notify.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return srvCfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadConfig - loads a new config from disk, overrides params from env
|
||||||
|
// if found and valid
|
||||||
|
func loadConfig() error {
|
||||||
|
srvCfg, err := getValidConfig()
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If env is set override the credentials from config file.
|
||||||
|
if globalIsEnvCreds {
|
||||||
|
srvCfg.SetCredential(globalActiveCred)
|
||||||
|
}
|
||||||
|
if globalIsEnvBrowser {
|
||||||
|
srvCfg.SetBrowser(globalIsBrowserEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hold the mutex lock before a new config is assigned.
|
||||||
|
serverConfigMu.Lock()
|
||||||
|
serverConfig = srvCfg
|
||||||
|
if !globalIsEnvCreds {
|
||||||
|
globalActiveCred = serverConfig.GetCredential()
|
||||||
|
}
|
||||||
|
if !globalIsEnvBrowser {
|
||||||
|
globalIsBrowserEnabled = serverConfig.GetBrowser()
|
||||||
|
}
|
||||||
|
serverConfigMu.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverConfig server config.
|
|
||||||
var serverConfig *serverConfigV17
|
|
||||||
|
|
||||||
// GetVersion get current config version.
|
|
||||||
func (s serverConfigV17) GetVersion() string {
|
|
||||||
serverConfigMu.RLock()
|
|
||||||
defer serverConfigMu.RUnlock()
|
|
||||||
|
|
||||||
return s.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRegion set new region.
|
|
||||||
func (s *serverConfigV17) SetRegion(region string) {
|
|
||||||
serverConfigMu.Lock()
|
|
||||||
defer serverConfigMu.Unlock()
|
|
||||||
|
|
||||||
// Empty region means "us-east-1" by default from S3 spec.
|
|
||||||
if region == "" {
|
|
||||||
region = "us-east-1"
|
|
||||||
}
|
|
||||||
s.Region = region
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRegion get current region.
|
|
||||||
func (s serverConfigV17) GetRegion() string {
|
|
||||||
serverConfigMu.RLock()
|
|
||||||
defer serverConfigMu.RUnlock()
|
|
||||||
|
|
||||||
if s.Region != "" {
|
|
||||||
return s.Region
|
|
||||||
} // region empty
|
|
||||||
|
|
||||||
// Empty region means "us-east-1" by default from S3 spec.
|
|
||||||
return "us-east-1"
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCredentials set new credentials.
|
|
||||||
func (s *serverConfigV17) SetCredential(creds credential) {
|
|
||||||
serverConfigMu.Lock()
|
|
||||||
defer serverConfigMu.Unlock()
|
|
||||||
|
|
||||||
// Set updated credential.
|
|
||||||
s.Credential = creds
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCredentials get current credentials.
|
|
||||||
func (s serverConfigV17) GetCredential() credential {
|
|
||||||
serverConfigMu.RLock()
|
|
||||||
defer serverConfigMu.RUnlock()
|
|
||||||
|
|
||||||
return s.Credential
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBrowser set if browser is enabled.
|
|
||||||
func (s *serverConfigV17) SetBrowser(b bool) {
|
|
||||||
serverConfigMu.Lock()
|
|
||||||
defer serverConfigMu.Unlock()
|
|
||||||
|
|
||||||
// Set the new value.
|
|
||||||
s.Browser = BrowserFlag(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCredentials get current credentials.
|
|
||||||
func (s serverConfigV17) GetBrowser() bool {
|
|
||||||
serverConfigMu.RLock()
|
|
||||||
defer serverConfigMu.RUnlock()
|
|
||||||
|
|
||||||
return bool(s.Browser)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save config.
|
|
||||||
func (s serverConfigV17) Save() error {
|
|
||||||
serverConfigMu.RLock()
|
|
||||||
defer serverConfigMu.RUnlock()
|
|
||||||
|
|
||||||
// get config file.
|
|
||||||
configFile := getConfigFile()
|
|
||||||
|
|
||||||
// Save config file.
|
|
||||||
return quick.Save(configFile, &s)
|
|
||||||
}
|
|
||||||
|
@ -309,7 +309,7 @@ func TestValidateConfig(t *testing.T) {
|
|||||||
if werr := ioutil.WriteFile(configPath, []byte(testCase.configData), 0700); werr != nil {
|
if werr := ioutil.WriteFile(configPath, []byte(testCase.configData), 0700); werr != nil {
|
||||||
t.Fatal(werr)
|
t.Fatal(werr)
|
||||||
}
|
}
|
||||||
verr := validateConfig()
|
_, verr := getValidConfig()
|
||||||
if testCase.shouldPass && verr != nil {
|
if testCase.shouldPass && verr != nil {
|
||||||
t.Errorf("Test %d, should pass but it failed with err = %v", i+1, verr)
|
t.Errorf("Test %d, should pass but it failed with err = %v", i+1, verr)
|
||||||
}
|
}
|
||||||
|
@ -104,17 +104,9 @@ func newGatewayConfig(accessKey, secretKey, region string) error {
|
|||||||
SecretKey: secretKey,
|
SecretKey: secretKey,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set default printing to console.
|
|
||||||
srvCfg.Logger.SetConsole(NewConsoleLogger())
|
|
||||||
|
|
||||||
// Set custom region.
|
// Set custom region.
|
||||||
srvCfg.SetRegion(region)
|
srvCfg.SetRegion(region)
|
||||||
|
|
||||||
// Create certs path for SSL configuration.
|
|
||||||
if err := createConfigDir(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// hold the mutex lock before a new config is assigned.
|
// hold the mutex lock before a new config is assigned.
|
||||||
// Save the new config globally.
|
// Save the new config globally.
|
||||||
// unlock the mutex.
|
// unlock the mutex.
|
||||||
@ -139,8 +131,7 @@ func gatewayMain(ctx *cli.Context) {
|
|||||||
// TODO: add support for custom region when we add
|
// TODO: add support for custom region when we add
|
||||||
// support for S3 backend storage, currently this can
|
// support for S3 backend storage, currently this can
|
||||||
// default to "us-east-1"
|
// default to "us-east-1"
|
||||||
err := newGatewayConfig(accessKey, secretKey, "us-east-1")
|
newGatewayConfig(accessKey, secretKey, globalMinioDefaultRegion)
|
||||||
fatalIf(err, "Unable to initialize gateway config")
|
|
||||||
|
|
||||||
// Get quiet flag from command line argument.
|
// Get quiet flag from command line argument.
|
||||||
quietFlag := ctx.Bool("quiet") || ctx.GlobalBool("quiet")
|
quietFlag := ctx.Bool("quiet") || ctx.GlobalBool("quiet")
|
||||||
@ -151,6 +142,9 @@ func gatewayMain(ctx *cli.Context) {
|
|||||||
// First argument is selected backend type.
|
// First argument is selected backend type.
|
||||||
backendType := ctx.Args().First()
|
backendType := ctx.Args().First()
|
||||||
|
|
||||||
|
// Create certs path for SSL configuration.
|
||||||
|
fatalIf(createConfigDir(), "Unable to create configuration directory")
|
||||||
|
|
||||||
newObject, err := newGatewayLayer(backendType, accessKey, secretKey)
|
newObject, err := newGatewayLayer(backendType, accessKey, secretKey)
|
||||||
fatalIf(err, "Unable to initialize gateway layer")
|
fatalIf(err, "Unable to initialize gateway layer")
|
||||||
|
|
||||||
|
@ -357,8 +357,7 @@ func initConfig() {
|
|||||||
// Config file does not exist, we create it fresh and return upon success.
|
// Config file does not exist, we create it fresh and return upon success.
|
||||||
if isFile(getConfigFile()) {
|
if isFile(getConfigFile()) {
|
||||||
fatalIf(migrateConfig(), "Config migration failed.")
|
fatalIf(migrateConfig(), "Config migration failed.")
|
||||||
fatalIf(validateConfig(), "Unable to validate configuration file")
|
fatalIf(loadConfig(), "Unable to load minio config file")
|
||||||
fatalIf(loadConfig(), "Unable to initialize minio config")
|
|
||||||
} else {
|
} else {
|
||||||
fatalIf(newConfig(), "Unable to initialize minio config for the first time.")
|
fatalIf(newConfig(), "Unable to initialize minio config for the first time.")
|
||||||
log.Println("Created minio configuration file successfully at " + getConfigDir())
|
log.Println("Created minio configuration file successfully at " + getConfigDir())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user