mirror of https://github.com/minio/minio.git
Persist MINIO_WORM as part of config.json (#6022)
This commit is contained in:
parent
113570b514
commit
6138cae8e7
|
@ -42,7 +42,7 @@ export class ChangePasswordModal extends React.Component {
|
|||
const { serverInfo } = this.props
|
||||
|
||||
// Check environment variables first.
|
||||
if (serverInfo.info.isEnvCreds) {
|
||||
if (serverInfo.info.isEnvCreds || serverInfo.info.isWorm) {
|
||||
this.setState({
|
||||
accessKey: "xxxxxxxxx",
|
||||
secretKey: "xxxxxxxxx",
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -68,7 +68,7 @@ var (
|
|||
func (a adminAPIHandlers) VersionHandler(w http.ResponseWriter, r *http.Request) {
|
||||
adminAPIErr := checkAdminRequestAuthType(r, globalServerConfig.GetRegion())
|
||||
if adminAPIErr != ErrNone {
|
||||
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||
writeErrorResponseJSON(w, adminAPIErr, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -669,6 +669,12 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques
|
|||
return
|
||||
}
|
||||
|
||||
// Deny if WORM is enabled
|
||||
if globalWORMEnabled {
|
||||
writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate request signature.
|
||||
adminAPIErr := checkAdminRequestAuthType(r, globalServerConfig.GetRegion())
|
||||
if adminAPIErr != ErrNone {
|
||||
|
@ -681,12 +687,12 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques
|
|||
n, err := io.ReadFull(r.Body, configBuf)
|
||||
if err == nil {
|
||||
// More than maxConfigSize bytes were available
|
||||
writeErrorResponse(w, ErrAdminConfigTooLarge, r.URL)
|
||||
writeErrorResponseJSON(w, ErrAdminConfigTooLarge, r.URL)
|
||||
return
|
||||
}
|
||||
if err != io.ErrUnexpectedEOF {
|
||||
logger.LogIf(ctx, err)
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
writeErrorResponseJSON(w, toAPIErrorCode(err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -696,7 +702,7 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques
|
|||
// client has not sent JSON objects with duplicate keys.
|
||||
if err = quick.CheckDuplicateKeys(string(configBytes)); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
writeErrorResponse(w, ErrAdminConfigBadJSON, r.URL)
|
||||
writeErrorResponseJSON(w, ErrAdminConfigBadJSON, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -704,7 +710,7 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques
|
|||
err = json.Unmarshal(configBytes, &config)
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
writeErrorResponseJSON(w, toAPIErrorCode(err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -769,14 +775,14 @@ func (a adminAPIHandlers) UpdateCredentialsHandler(w http.ResponseWriter,
|
|||
// Authenticate request
|
||||
adminAPIErr := checkAdminRequestAuthType(r, globalServerConfig.GetRegion())
|
||||
if adminAPIErr != ErrNone {
|
||||
writeErrorResponse(w, adminAPIErr, r.URL)
|
||||
writeErrorResponseJSON(w, adminAPIErr, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
// Avoid setting new credentials when they are already passed
|
||||
// by the environment.
|
||||
if globalIsEnvCreds {
|
||||
writeErrorResponse(w, ErrMethodNotAllowed, r.URL)
|
||||
// by the environment. Deny if WORM is enabled.
|
||||
if globalIsEnvCreds || globalWORMEnabled {
|
||||
writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -791,7 +797,7 @@ func (a adminAPIHandlers) UpdateCredentialsHandler(w http.ResponseWriter,
|
|||
|
||||
creds, err := auth.CreateCredentials(req.AccessKey, req.SecretKey)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||
writeErrorResponseJSON(w, toAPIErrorCode(err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -811,7 +817,7 @@ func (a adminAPIHandlers) UpdateCredentialsHandler(w http.ResponseWriter,
|
|||
// Update local credentials in memory.
|
||||
globalServerConfig.SetCredential(creds)
|
||||
if err = globalServerConfig.Save(); err != nil {
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponseJSON(w, ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Minio Cloud Storage, (C) 2017 Minio, Inc.
|
||||
* Minio Cloud Storage, (C) 2017, 2018 Minio, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -21,11 +21,11 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
// BrowserFlag - wrapper bool type.
|
||||
type BrowserFlag bool
|
||||
// BoolFlag - wrapper bool type.
|
||||
type BoolFlag bool
|
||||
|
||||
// String - returns string of BrowserFlag.
|
||||
func (bf BrowserFlag) String() string {
|
||||
// String - returns string of BoolFlag.
|
||||
func (bf BoolFlag) String() string {
|
||||
if bf {
|
||||
return "on"
|
||||
}
|
||||
|
@ -33,20 +33,20 @@ func (bf BrowserFlag) String() string {
|
|||
return "off"
|
||||
}
|
||||
|
||||
// MarshalJSON - converts BrowserFlag into JSON data.
|
||||
func (bf BrowserFlag) MarshalJSON() ([]byte, error) {
|
||||
// MarshalJSON - converts BoolFlag into JSON data.
|
||||
func (bf BoolFlag) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(bf.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON - parses given data into BrowserFlag.
|
||||
func (bf *BrowserFlag) UnmarshalJSON(data []byte) (err error) {
|
||||
// UnmarshalJSON - parses given data into BoolFlag.
|
||||
func (bf *BoolFlag) UnmarshalJSON(data []byte) (err error) {
|
||||
var s string
|
||||
if err = json.Unmarshal(data, &s); err == nil {
|
||||
b := BrowserFlag(true)
|
||||
b := BoolFlag(true)
|
||||
if s == "" {
|
||||
// Empty string is treated as valid.
|
||||
*bf = b
|
||||
} else if b, err = ParseBrowserFlag(s); err == nil {
|
||||
} else if b, err = ParseBoolFlag(s); err == nil {
|
||||
*bf = b
|
||||
}
|
||||
}
|
||||
|
@ -54,14 +54,14 @@ func (bf *BrowserFlag) UnmarshalJSON(data []byte) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// ParseBrowserFlag - parses string into BrowserFlag.
|
||||
func ParseBrowserFlag(s string) (bf BrowserFlag, err error) {
|
||||
// ParseBoolFlag - parses string into BoolFlag.
|
||||
func ParseBoolFlag(s string) (bf BoolFlag, err error) {
|
||||
if s == "on" {
|
||||
bf = true
|
||||
} else if s == "off" {
|
||||
bf = false
|
||||
} else {
|
||||
err = fmt.Errorf("invalid value ‘%s’ for BrowserFlag", s)
|
||||
err = fmt.Errorf("invalid value ‘%s’ for BoolFlag", s)
|
||||
}
|
||||
|
||||
return bf, err
|
|
@ -21,17 +21,17 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
// Test BrowserFlag.String()
|
||||
func TestBrowserFlagString(t *testing.T) {
|
||||
var bf BrowserFlag
|
||||
// Test BoolFlag.String()
|
||||
func TestBoolFlagString(t *testing.T) {
|
||||
var bf BoolFlag
|
||||
|
||||
testCases := []struct {
|
||||
flag BrowserFlag
|
||||
flag BoolFlag
|
||||
expectedResult string
|
||||
}{
|
||||
{bf, "off"},
|
||||
{BrowserFlag(true), "on"},
|
||||
{BrowserFlag(false), "off"},
|
||||
{BoolFlag(true), "on"},
|
||||
{BoolFlag(false), "off"},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
|
@ -42,17 +42,17 @@ func TestBrowserFlagString(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test BrowserFlag.MarshalJSON()
|
||||
func TestBrowserFlagMarshalJSON(t *testing.T) {
|
||||
var bf BrowserFlag
|
||||
// Test BoolFlag.MarshalJSON()
|
||||
func TestBoolFlagMarshalJSON(t *testing.T) {
|
||||
var bf BoolFlag
|
||||
|
||||
testCases := []struct {
|
||||
flag BrowserFlag
|
||||
flag BoolFlag
|
||||
expectedResult string
|
||||
}{
|
||||
{bf, `"off"`},
|
||||
{BrowserFlag(true), `"on"`},
|
||||
{BrowserFlag(false), `"off"`},
|
||||
{BoolFlag(true), `"on"`},
|
||||
{BoolFlag(false), `"off"`},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
|
@ -63,27 +63,27 @@ func TestBrowserFlagMarshalJSON(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test BrowserFlag.UnmarshalJSON()
|
||||
func TestBrowserFlagUnmarshalJSON(t *testing.T) {
|
||||
// Test BoolFlag.UnmarshalJSON()
|
||||
func TestBoolFlagUnmarshalJSON(t *testing.T) {
|
||||
testCases := []struct {
|
||||
data []byte
|
||||
expectedResult BrowserFlag
|
||||
expectedResult BoolFlag
|
||||
expectedErr error
|
||||
}{
|
||||
{[]byte(`{}`), BrowserFlag(false), errors.New("json: cannot unmarshal object into Go value of type string")},
|
||||
{[]byte(`["on"]`), BrowserFlag(false), errors.New("json: cannot unmarshal array into Go value of type string")},
|
||||
{[]byte(`"junk"`), BrowserFlag(false), errors.New("invalid value ‘junk’ for BrowserFlag")},
|
||||
{[]byte(`"true"`), BrowserFlag(false), errors.New("invalid value ‘true’ for BrowserFlag")},
|
||||
{[]byte(`"false"`), BrowserFlag(false), errors.New("invalid value ‘false’ for BrowserFlag")},
|
||||
{[]byte(`"ON"`), BrowserFlag(false), errors.New("invalid value ‘ON’ for BrowserFlag")},
|
||||
{[]byte(`"OFF"`), BrowserFlag(false), errors.New("invalid value ‘OFF’ for BrowserFlag")},
|
||||
{[]byte(`""`), BrowserFlag(true), nil},
|
||||
{[]byte(`"on"`), BrowserFlag(true), nil},
|
||||
{[]byte(`"off"`), BrowserFlag(false), nil},
|
||||
{[]byte(`{}`), BoolFlag(false), errors.New("json: cannot unmarshal object into Go value of type string")},
|
||||
{[]byte(`["on"]`), BoolFlag(false), errors.New("json: cannot unmarshal array into Go value of type string")},
|
||||
{[]byte(`"junk"`), BoolFlag(false), errors.New("invalid value ‘junk’ for BoolFlag")},
|
||||
{[]byte(`"true"`), BoolFlag(false), errors.New("invalid value ‘true’ for BoolFlag")},
|
||||
{[]byte(`"false"`), BoolFlag(false), errors.New("invalid value ‘false’ for BoolFlag")},
|
||||
{[]byte(`"ON"`), BoolFlag(false), errors.New("invalid value ‘ON’ for BoolFlag")},
|
||||
{[]byte(`"OFF"`), BoolFlag(false), errors.New("invalid value ‘OFF’ for BoolFlag")},
|
||||
{[]byte(`""`), BoolFlag(true), nil},
|
||||
{[]byte(`"on"`), BoolFlag(true), nil},
|
||||
{[]byte(`"off"`), BoolFlag(false), nil},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
var flag BrowserFlag
|
||||
var flag BoolFlag
|
||||
err := (&flag).UnmarshalJSON(testCase.data)
|
||||
if testCase.expectedErr == nil {
|
||||
if err != nil {
|
||||
|
@ -101,25 +101,25 @@ func TestBrowserFlagUnmarshalJSON(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test ParseBrowserFlag()
|
||||
func TestParseBrowserFlag(t *testing.T) {
|
||||
// Test ParseBoolFlag()
|
||||
func TestParseBoolFlag(t *testing.T) {
|
||||
testCases := []struct {
|
||||
flagStr string
|
||||
expectedResult BrowserFlag
|
||||
expectedResult BoolFlag
|
||||
expectedErr error
|
||||
}{
|
||||
{"", BrowserFlag(false), errors.New("invalid value ‘’ for BrowserFlag")},
|
||||
{"junk", BrowserFlag(false), errors.New("invalid value ‘junk’ for BrowserFlag")},
|
||||
{"true", BrowserFlag(false), errors.New("invalid value ‘true’ for BrowserFlag")},
|
||||
{"false", BrowserFlag(false), errors.New("invalid value ‘false’ for BrowserFlag")},
|
||||
{"ON", BrowserFlag(false), errors.New("invalid value ‘ON’ for BrowserFlag")},
|
||||
{"OFF", BrowserFlag(false), errors.New("invalid value ‘OFF’ for BrowserFlag")},
|
||||
{"on", BrowserFlag(true), nil},
|
||||
{"off", BrowserFlag(false), nil},
|
||||
{"", BoolFlag(false), errors.New("invalid value ‘’ for BoolFlag")},
|
||||
{"junk", BoolFlag(false), errors.New("invalid value ‘junk’ for BoolFlag")},
|
||||
{"true", BoolFlag(false), errors.New("invalid value ‘true’ for BoolFlag")},
|
||||
{"false", BoolFlag(false), errors.New("invalid value ‘false’ for BoolFlag")},
|
||||
{"ON", BoolFlag(false), errors.New("invalid value ‘ON’ for BoolFlag")},
|
||||
{"OFF", BoolFlag(false), errors.New("invalid value ‘OFF’ for BoolFlag")},
|
||||
{"on", BoolFlag(true), nil},
|
||||
{"off", BoolFlag(false), nil},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
bf, err := ParseBrowserFlag(testCase.flagStr)
|
||||
bf, err := ParseBoolFlag(testCase.flagStr)
|
||||
if testCase.expectedErr == nil {
|
||||
if err != nil {
|
||||
t.Fatalf("error: expected = <nil>, got = %v", err)
|
|
@ -105,7 +105,7 @@ func handleCommonEnvVars() {
|
|||
}
|
||||
|
||||
if browser := os.Getenv("MINIO_BROWSER"); browser != "" {
|
||||
browserFlag, err := ParseBrowserFlag(browser)
|
||||
browserFlag, err := ParseBoolFlag(browser)
|
||||
if err != nil {
|
||||
logger.Fatal(uiErrInvalidBrowserValue(nil).Msg("Unknown value `%s`", browser), "Unable to validate MINIO_BROWSER environment variable")
|
||||
}
|
||||
|
@ -123,10 +123,7 @@ func handleCommonEnvVars() {
|
|||
logger.FatalIf(err, "error opening file %s", traceFile)
|
||||
}
|
||||
|
||||
globalDomainName = os.Getenv("MINIO_DOMAIN")
|
||||
if globalDomainName != "" {
|
||||
globalIsEnvDomainName = true
|
||||
}
|
||||
globalDomainName, globalIsEnvDomainName = os.LookupEnv("MINIO_DOMAIN")
|
||||
|
||||
if drives := os.Getenv("MINIO_CACHE_DRIVES"); drives != "" {
|
||||
driveList, err := parseCacheDrives(strings.Split(drives, cacheEnvDelimiter))
|
||||
|
@ -189,5 +186,15 @@ func handleCommonEnvVars() {
|
|||
}
|
||||
|
||||
// Get WORM environment variable.
|
||||
globalWORMEnabled = strings.EqualFold(os.Getenv("MINIO_WORM"), "on")
|
||||
if worm := os.Getenv("MINIO_WORM"); worm != "" {
|
||||
wormFlag, err := ParseBoolFlag(worm)
|
||||
if err != nil {
|
||||
logger.Fatal(uiErrInvalidWormValue(nil).Msg("Unknown value `%s`", worm), "Unable to validate MINIO_WORM environment variable")
|
||||
}
|
||||
|
||||
// worm Envs are set globally, this does not represent
|
||||
// if worm is turned off or on.
|
||||
globalIsEnvWORM = true
|
||||
globalWORMEnabled = bool(wormFlag)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@ import (
|
|||
// 6. Make changes in config-current_test.go for any test change
|
||||
|
||||
// Config version
|
||||
const serverConfigVersion = "24"
|
||||
const serverConfigVersion = "25"
|
||||
|
||||
type serverConfig = serverConfigV24
|
||||
type serverConfig = serverConfigV25
|
||||
|
||||
var (
|
||||
// globalServerConfig server config.
|
||||
|
@ -85,7 +85,13 @@ func (s *serverConfig) GetCredential() auth.Credentials {
|
|||
// SetBrowser set if browser is enabled.
|
||||
func (s *serverConfig) SetBrowser(b bool) {
|
||||
// Set the new value.
|
||||
s.Browser = BrowserFlag(b)
|
||||
s.Browser = BoolFlag(b)
|
||||
}
|
||||
|
||||
// SetWorm set if worm is enabled.
|
||||
func (s *serverConfig) SetWorm(b bool) {
|
||||
// Set the new value.
|
||||
s.Worm = BoolFlag(b)
|
||||
}
|
||||
|
||||
func (s *serverConfig) SetStorageClass(standardClass, rrsClass storageClass) {
|
||||
|
@ -99,11 +105,16 @@ func (s *serverConfig) GetStorageClass() (storageClass, storageClass) {
|
|||
return s.StorageClass.Standard, s.StorageClass.RRS
|
||||
}
|
||||
|
||||
// GetCredentials get current credentials.
|
||||
// GetBrowser get current credentials.
|
||||
func (s *serverConfig) GetBrowser() bool {
|
||||
return bool(s.Browser)
|
||||
}
|
||||
|
||||
// GetWorm get current credentials.
|
||||
func (s *serverConfig) GetWorm() bool {
|
||||
return bool(s.Worm)
|
||||
}
|
||||
|
||||
// SetCacheConfig sets the current cache config
|
||||
func (s *serverConfig) SetCacheConfig(drives, exclude []string, expiry int) {
|
||||
s.Cache.Drives = drives
|
||||
|
@ -230,6 +241,10 @@ func newConfig() error {
|
|||
srvCfg.SetBrowser(globalIsBrowserEnabled)
|
||||
}
|
||||
|
||||
if globalIsEnvWORM {
|
||||
srvCfg.SetWorm(globalWORMEnabled)
|
||||
}
|
||||
|
||||
if globalIsEnvRegion {
|
||||
srvCfg.SetRegion(globalServerRegion)
|
||||
}
|
||||
|
@ -324,6 +339,9 @@ func loadConfig() error {
|
|||
if !globalIsEnvBrowser {
|
||||
globalIsBrowserEnabled = globalServerConfig.GetBrowser()
|
||||
}
|
||||
if !globalIsEnvWORM {
|
||||
globalWORMEnabled = globalServerConfig.GetWorm()
|
||||
}
|
||||
if !globalIsEnvRegion {
|
||||
globalServerRegion = globalServerConfig.GetRegion()
|
||||
}
|
||||
|
|
|
@ -177,6 +177,11 @@ func migrateConfig() error {
|
|||
return err
|
||||
}
|
||||
fallthrough
|
||||
case "24":
|
||||
if err = migrateV24ToV25(); err != nil {
|
||||
return err
|
||||
}
|
||||
fallthrough
|
||||
case serverConfigVersion:
|
||||
// No migration needed. this always points to current version.
|
||||
err = nil
|
||||
|
@ -2069,3 +2074,121 @@ func migrateV23ToV24() error {
|
|||
logger.Info(configMigrateMSGTemplate, configFile, cv23.Version, srvConfig.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
func migrateV24ToV25() error {
|
||||
configFile := getConfigFile()
|
||||
|
||||
cv24 := &serverConfigV24{}
|
||||
_, err := quick.Load(configFile, cv24)
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("Unable to load config version ‘24’. %v", err)
|
||||
}
|
||||
if cv24.Version != "24" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Copy over fields from V24 into V25 config struct
|
||||
srvConfig := &serverConfigV25{
|
||||
Notify: notifier{},
|
||||
}
|
||||
srvConfig.Version = "25"
|
||||
srvConfig.Credential = cv24.Credential
|
||||
srvConfig.Region = cv24.Region
|
||||
if srvConfig.Region == "" {
|
||||
// Region needs to be set for AWS Signature Version 4.
|
||||
srvConfig.Region = globalMinioDefaultRegion
|
||||
}
|
||||
|
||||
if len(cv24.Notify.AMQP) == 0 {
|
||||
srvConfig.Notify.AMQP = make(map[string]target.AMQPArgs)
|
||||
srvConfig.Notify.AMQP["1"] = target.AMQPArgs{}
|
||||
} else {
|
||||
srvConfig.Notify.AMQP = cv24.Notify.AMQP
|
||||
}
|
||||
if len(cv24.Notify.Elasticsearch) == 0 {
|
||||
srvConfig.Notify.Elasticsearch = make(map[string]target.ElasticsearchArgs)
|
||||
srvConfig.Notify.Elasticsearch["1"] = target.ElasticsearchArgs{
|
||||
Format: event.NamespaceFormat,
|
||||
}
|
||||
} else {
|
||||
srvConfig.Notify.Elasticsearch = cv24.Notify.Elasticsearch
|
||||
}
|
||||
if len(cv24.Notify.Redis) == 0 {
|
||||
srvConfig.Notify.Redis = make(map[string]target.RedisArgs)
|
||||
srvConfig.Notify.Redis["1"] = target.RedisArgs{
|
||||
Format: event.NamespaceFormat,
|
||||
}
|
||||
} else {
|
||||
srvConfig.Notify.Redis = cv24.Notify.Redis
|
||||
}
|
||||
if len(cv24.Notify.PostgreSQL) == 0 {
|
||||
srvConfig.Notify.PostgreSQL = make(map[string]target.PostgreSQLArgs)
|
||||
srvConfig.Notify.PostgreSQL["1"] = target.PostgreSQLArgs{
|
||||
Format: event.NamespaceFormat,
|
||||
}
|
||||
} else {
|
||||
srvConfig.Notify.PostgreSQL = cv24.Notify.PostgreSQL
|
||||
}
|
||||
if len(cv24.Notify.Kafka) == 0 {
|
||||
srvConfig.Notify.Kafka = make(map[string]target.KafkaArgs)
|
||||
srvConfig.Notify.Kafka["1"] = target.KafkaArgs{}
|
||||
} else {
|
||||
srvConfig.Notify.Kafka = cv24.Notify.Kafka
|
||||
}
|
||||
if len(cv24.Notify.NATS) == 0 {
|
||||
srvConfig.Notify.NATS = make(map[string]target.NATSArgs)
|
||||
srvConfig.Notify.NATS["1"] = target.NATSArgs{}
|
||||
} else {
|
||||
srvConfig.Notify.NATS = cv24.Notify.NATS
|
||||
}
|
||||
if len(cv24.Notify.Webhook) == 0 {
|
||||
srvConfig.Notify.Webhook = make(map[string]target.WebhookArgs)
|
||||
srvConfig.Notify.Webhook["1"] = target.WebhookArgs{}
|
||||
} else {
|
||||
srvConfig.Notify.Webhook = cv24.Notify.Webhook
|
||||
}
|
||||
if len(cv24.Notify.MySQL) == 0 {
|
||||
srvConfig.Notify.MySQL = make(map[string]target.MySQLArgs)
|
||||
srvConfig.Notify.MySQL["1"] = target.MySQLArgs{
|
||||
Format: event.NamespaceFormat,
|
||||
}
|
||||
} else {
|
||||
srvConfig.Notify.MySQL = cv24.Notify.MySQL
|
||||
}
|
||||
|
||||
if len(cv24.Notify.MQTT) == 0 {
|
||||
srvConfig.Notify.MQTT = make(map[string]target.MQTTArgs)
|
||||
srvConfig.Notify.MQTT["1"] = target.MQTTArgs{}
|
||||
} else {
|
||||
srvConfig.Notify.MQTT = cv24.Notify.MQTT
|
||||
}
|
||||
|
||||
// Load browser config from existing config in the file.
|
||||
srvConfig.Browser = cv24.Browser
|
||||
|
||||
// New field should be turned-off by default.
|
||||
srvConfig.Worm = false // cv25.Worm should be used here
|
||||
// for the next migration from v25 to v26 to persist
|
||||
// local config value.
|
||||
|
||||
// Load domain config from existing config in the file.
|
||||
srvConfig.Domain = cv24.Domain
|
||||
|
||||
// Load storage class config from existing storage class config in the file.
|
||||
srvConfig.StorageClass.RRS = cv24.StorageClass.RRS
|
||||
srvConfig.StorageClass.Standard = cv24.StorageClass.Standard
|
||||
|
||||
// Load cache config from existing cache config in the file.
|
||||
srvConfig.Cache.Drives = cv24.Cache.Drives
|
||||
srvConfig.Cache.Exclude = cv24.Cache.Exclude
|
||||
srvConfig.Cache.Expiry = cv24.Cache.Expiry
|
||||
|
||||
if err = quick.Save(configFile, srvConfig); err != nil {
|
||||
return fmt.Errorf("Failed to migrate config from ‘%s’ to ‘%s’. %v", cv24.Version, srvConfig.Version, err)
|
||||
}
|
||||
|
||||
logger.Info(configMigrateMSGTemplate, configFile, cv24.Version, srvConfig.Version)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -405,7 +405,7 @@ type serverConfigV14 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
|
||||
// Additional error logging configuration.
|
||||
Logger *loggerV7 `json:"logger"`
|
||||
|
@ -422,7 +422,7 @@ type serverConfigV15 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
|
||||
// Additional error logging configuration.
|
||||
Logger *loggerV7 `json:"logger"`
|
||||
|
@ -460,7 +460,7 @@ type serverConfigV16 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
|
||||
// Additional error logging configuration.
|
||||
Logger *loggers `json:"logger"`
|
||||
|
@ -479,7 +479,7 @@ type serverConfigV17 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
|
||||
// Additional error logging configuration.
|
||||
Logger *loggers `json:"logger"`
|
||||
|
@ -498,7 +498,7 @@ type serverConfigV18 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
|
||||
// Additional error logging configuration.
|
||||
Logger *loggers `json:"logger"`
|
||||
|
@ -516,7 +516,7 @@ type serverConfigV19 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
|
||||
// Additional error logging configuration.
|
||||
Logger *loggers `json:"logger"`
|
||||
|
@ -534,7 +534,7 @@ type serverConfigV20 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Additional error logging configuration.
|
||||
|
@ -552,7 +552,7 @@ type serverConfigV21 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Notification queue configuration.
|
||||
|
@ -570,7 +570,7 @@ type serverConfigV22 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Storage class configuration
|
||||
|
@ -590,7 +590,7 @@ type serverConfigV23 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Storage class configuration
|
||||
|
@ -614,7 +614,32 @@ type serverConfigV24 struct {
|
|||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BrowserFlag `json:"browser"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Storage class configuration
|
||||
StorageClass storageClassConfig `json:"storageclass"`
|
||||
|
||||
// Cache configuration
|
||||
Cache CacheConfig `json:"cache"`
|
||||
|
||||
// Notification queue configuration.
|
||||
Notify notifier `json:"notify"`
|
||||
}
|
||||
|
||||
// serverConfigV25 is just like version '24', stores additionally
|
||||
// worm variable.
|
||||
//
|
||||
// IMPORTANT NOTE: When updating this struct make sure that
|
||||
// serverConfig.ConfigDiff() is updated as necessary.
|
||||
type serverConfigV25 struct {
|
||||
Version string `json:"version"`
|
||||
|
||||
// S3 API configuration.
|
||||
Credential auth.Credentials `json:"credential"`
|
||||
Region string `json:"region"`
|
||||
Browser BoolFlag `json:"browser"`
|
||||
Worm BoolFlag `json:"worm"`
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// Storage class configuration
|
||||
|
|
|
@ -174,6 +174,7 @@ var (
|
|||
// Set to store standard storage class
|
||||
globalStandardStorageClass storageClass
|
||||
|
||||
globalIsEnvWORM bool
|
||||
globalWORMEnabled bool
|
||||
|
||||
// Is Disk Caching set up
|
||||
|
@ -217,6 +218,7 @@ func getGlobalInfo() (globalInfo map[string]interface{}) {
|
|||
"isDistXL": globalIsDistXL,
|
||||
"isXL": globalIsXL,
|
||||
"isBrowserEnabled": globalIsBrowserEnabled,
|
||||
"isWorm": globalWORMEnabled,
|
||||
"isEnvBrowser": globalIsEnvBrowser,
|
||||
"isEnvCreds": globalIsEnvCreds,
|
||||
"isEnvRegion": globalIsEnvRegion,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"path"
|
||||
|
||||
|
@ -223,7 +222,9 @@ func registerStorageRPCRouters(router *mux.Router, endpoints EndpointList) {
|
|||
for _, endpoint := range endpoints {
|
||||
if endpoint.IsLocal {
|
||||
rpcServer, err := NewStorageRPCServer(endpoint.Path)
|
||||
logger.CriticalIf(context.Background(), err)
|
||||
if err != nil {
|
||||
logger.Fatal(uiErrUnableToWriteInBackend(err), "Unable to configure one of server's RPC services")
|
||||
}
|
||||
subrouter := router.PathPrefix(minioReservedBucketPath).Subrouter()
|
||||
subrouter.Path(path.Join(storageServiceSubPath, endpoint.Path)).Handler(rpcServer)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ import (
|
|||
// errInvalidArgument means that input argument is invalid.
|
||||
var errInvalidArgument = errors.New("Invalid arguments specified")
|
||||
|
||||
// errMethodNotAllowed means that method is not allowed.
|
||||
var errMethodNotAllowed = errors.New("Method not allowed")
|
||||
|
||||
// errSignatureMismatch means signature did not match.
|
||||
var errSignatureMismatch = errors.New("Signature does not match")
|
||||
|
||||
|
|
|
@ -29,6 +29,12 @@ var (
|
|||
"Browser can only accept `on` and `off` values. To disable web browser access, set this value to `off`",
|
||||
)
|
||||
|
||||
uiErrInvalidWormValue = newUIErrFn(
|
||||
"Invalid WORM value",
|
||||
"Please check the passed value",
|
||||
"WORM can only accept `on` and `off` values. To enable WORM, set this value to `on`",
|
||||
)
|
||||
|
||||
uiErrInvalidCacheDrivesValue = newUIErrFn(
|
||||
"Invalid cache drive value",
|
||||
"Please check the value in this ENV variable",
|
||||
|
|
|
@ -353,6 +353,13 @@ next:
|
|||
for _, objectName := range args.Objects {
|
||||
// If not a directory, remove the object.
|
||||
if !hasSuffix(objectName, slashSeparator) && objectName != "" {
|
||||
// Deny if WORM is enabled
|
||||
if globalWORMEnabled {
|
||||
if _, err = objectAPI.GetObjectInfo(context.Background(), args.BucketName, objectName); err == nil {
|
||||
return toJSONError(errMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
if err = deleteObject(nil, objectAPI, web.CacheAPI(), args.BucketName, objectName, r); err != nil {
|
||||
break next
|
||||
}
|
||||
|
@ -457,7 +464,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se
|
|||
}
|
||||
|
||||
// If creds are set through ENV disallow changing credentials.
|
||||
if globalIsEnvCreds {
|
||||
if globalIsEnvCreds || globalWORMEnabled {
|
||||
return toJSONError(errChangeCredNotAllowed)
|
||||
}
|
||||
|
||||
|
@ -594,6 +601,14 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Deny if WORM is enabled
|
||||
if globalWORMEnabled {
|
||||
if _, err = objectAPI.GetObjectInfo(context.Background(), bucket, object); err == nil {
|
||||
writeWebErrorResponse(w, errMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
objInfo, err := putObject(context.Background(), bucket, object, hashReader, metadata)
|
||||
if err != nil {
|
||||
writeWebErrorResponse(w, err)
|
||||
|
@ -1103,7 +1118,10 @@ func toWebAPIError(err error) APIError {
|
|||
HTTPStatusCode: http.StatusBadRequest,
|
||||
Description: err.Error(),
|
||||
}
|
||||
} else if err == errMethodNotAllowed {
|
||||
return getAPIError(ErrMethodNotAllowed)
|
||||
}
|
||||
|
||||
// Convert error type to api error code.
|
||||
switch err.(type) {
|
||||
case StorageFull:
|
||||
|
|
|
@ -69,6 +69,18 @@ export MINIO_BROWSER=off
|
|||
minio server /data
|
||||
```
|
||||
|
||||
#### Worm
|
||||
|Field|Type|Description|
|
||||
|:---|:---|:---|
|
||||
|``worm``| _string_ | Enable this to turn on Write-Once-Read-Many. By default it is set to `off`. You may override this field with ``MINIO_WORM`` environment variable.|
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
export MINIO_WORM=on
|
||||
minio server /data
|
||||
```
|
||||
|
||||
### Domain
|
||||
|Field|Type|Description|
|
||||
|:---|:---|:---|
|
||||
|
|
Loading…
Reference in New Issue