github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/config-migrate.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"context"
    22  	"encoding/json"
    23  	"errors"
    24  	"path"
    25  	"strings"
    26  
    27  	"github.com/minio/minio/internal/config"
    28  	"github.com/minio/minio/internal/config/compress"
    29  	xldap "github.com/minio/minio/internal/config/identity/ldap"
    30  	"github.com/minio/minio/internal/config/identity/openid"
    31  	"github.com/minio/minio/internal/config/notify"
    32  	"github.com/minio/minio/internal/config/policy/opa"
    33  	"github.com/minio/minio/internal/config/storageclass"
    34  	"github.com/minio/minio/internal/event/target"
    35  	"github.com/minio/minio/internal/logger"
    36  	xnet "github.com/minio/pkg/v2/net"
    37  	"github.com/minio/pkg/v2/quick"
    38  )
    39  
    40  // Save config file to corresponding backend
    41  func Save(configFile string, data interface{}) error {
    42  	return quick.SaveConfig(data, configFile, globalEtcdClient)
    43  }
    44  
    45  // Load config from backend
    46  func Load(configFile string, data interface{}) (quick.Config, error) {
    47  	return quick.LoadConfig(configFile, globalEtcdClient, data)
    48  }
    49  
    50  func readConfigWithoutMigrate(ctx context.Context, objAPI ObjectLayer) (config.Config, error) {
    51  	// Construct path to config.json for the given bucket.
    52  	configFile := path.Join(minioConfigPrefix, minioConfigFile)
    53  
    54  	configFiles := []string{
    55  		getConfigFile(),
    56  		getConfigFile() + ".deprecated",
    57  		configFile,
    58  	}
    59  
    60  	newServerCfg := func() (config.Config, error) {
    61  		// Initialize server config.
    62  		srvCfg := newServerConfig()
    63  
    64  		return srvCfg, saveServerConfig(ctx, objAPI, srvCfg)
    65  	}
    66  
    67  	var data []byte
    68  	var err error
    69  
    70  	cfg := &serverConfigV33{}
    71  	for _, cfgFile := range configFiles {
    72  		if _, err = Load(cfgFile, cfg); err != nil {
    73  			if !osIsNotExist(err) && !osIsPermission(err) {
    74  				return nil, err
    75  			}
    76  			continue
    77  		}
    78  		data, _ = json.Marshal(cfg)
    79  		break
    80  	}
    81  	if osIsPermission(err) {
    82  		logger.Info("Older config found but is not readable %s, proceeding to read config from other places", err)
    83  	}
    84  	if osIsNotExist(err) || osIsPermission(err) || len(data) == 0 {
    85  		data, err = readConfig(GlobalContext, objAPI, configFile)
    86  		if err != nil {
    87  			// when config.json is not found, then we freshly initialize.
    88  			if errors.Is(err, errConfigNotFound) {
    89  				return newServerCfg()
    90  			}
    91  			return nil, err
    92  		}
    93  
    94  		data, err = decryptData(data, configFile)
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  
    99  		newCfg, err := readServerConfig(GlobalContext, objAPI, data)
   100  		if err == nil {
   101  			return newCfg, nil
   102  		}
   103  
   104  		// Read older `.minio.sys/config/config.json`, if not
   105  		// possible just fail.
   106  		if err = json.Unmarshal(data, cfg); err != nil {
   107  			// Unable to parse old JSON simply re-initialize a new one.
   108  			return newServerCfg()
   109  		}
   110  	}
   111  
   112  	if !globalCredViaEnv && cfg.Credential.IsValid() {
   113  		// Preserve older credential if we do not have
   114  		// root credentials set via environment variable.
   115  		globalActiveCred = cfg.Credential
   116  	}
   117  
   118  	// Init compression config. For future migration, Compression config needs to be copied over from previous version.
   119  	switch cfg.Version {
   120  	case "29":
   121  		// V29 -> V30
   122  		cfg.Compression.Enabled = false
   123  		cfg.Compression.Extensions = strings.Split(compress.DefaultExtensions, config.ValueSeparator)
   124  		cfg.Compression.MimeTypes = strings.Split(compress.DefaultMimeTypes, config.ValueSeparator)
   125  	case "30":
   126  		// V30 -> V31
   127  		cfg.OpenID = openid.Config{}
   128  		cfg.Policy.OPA = opa.Args{
   129  			URL:       &xnet.URL{},
   130  			AuthToken: "",
   131  		}
   132  	case "31":
   133  		// V31 -> V32
   134  		cfg.Notify.NSQ = make(map[string]target.NSQArgs)
   135  		cfg.Notify.NSQ["1"] = target.NSQArgs{}
   136  	}
   137  
   138  	// Move to latest.
   139  	cfg.Version = "33"
   140  
   141  	newCfg := newServerConfig()
   142  
   143  	config.SetRegion(newCfg, cfg.Region)
   144  	storageclass.SetStorageClass(newCfg, cfg.StorageClass)
   145  
   146  	for k, loggerArgs := range cfg.Logger.HTTP {
   147  		logger.SetLoggerHTTP(newCfg, k, loggerArgs)
   148  	}
   149  	for k, auditArgs := range cfg.Logger.AuditWebhook {
   150  		logger.SetLoggerHTTPAudit(newCfg, k, auditArgs)
   151  	}
   152  
   153  	xldap.SetIdentityLDAP(newCfg, cfg.LDAPServerConfig)
   154  	opa.SetPolicyOPAConfig(newCfg, cfg.Policy.OPA)
   155  	compress.SetCompressionConfig(newCfg, cfg.Compression)
   156  
   157  	for k, args := range cfg.Notify.AMQP {
   158  		notify.SetNotifyAMQP(newCfg, k, args)
   159  	}
   160  	for k, args := range cfg.Notify.Elasticsearch {
   161  		notify.SetNotifyES(newCfg, k, args)
   162  	}
   163  	for k, args := range cfg.Notify.Kafka {
   164  		notify.SetNotifyKafka(newCfg, k, args)
   165  	}
   166  	for k, args := range cfg.Notify.MQTT {
   167  		notify.SetNotifyMQTT(newCfg, k, args)
   168  	}
   169  	for k, args := range cfg.Notify.MySQL {
   170  		notify.SetNotifyMySQL(newCfg, k, args)
   171  	}
   172  	for k, args := range cfg.Notify.NATS {
   173  		notify.SetNotifyNATS(newCfg, k, args)
   174  	}
   175  	for k, args := range cfg.Notify.NSQ {
   176  		notify.SetNotifyNSQ(newCfg, k, args)
   177  	}
   178  	for k, args := range cfg.Notify.PostgreSQL {
   179  		notify.SetNotifyPostgres(newCfg, k, args)
   180  	}
   181  	for k, args := range cfg.Notify.Redis {
   182  		notify.SetNotifyRedis(newCfg, k, args)
   183  	}
   184  	for k, args := range cfg.Notify.Webhook {
   185  		notify.SetNotifyWebhook(newCfg, k, args)
   186  	}
   187  
   188  	return newCfg, nil
   189  }