diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index 9a25d8115..58b3393b0 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -1466,7 +1466,7 @@ func getServerInfo(ctx context.Context, r *http.Request) madmin.InfoMessage { return madmin.InfoMessage{ Mode: string(mode), Domain: domain, - Region: globalServerRegion, + Region: globalSite.Region, SQSARN: globalNotificationSys.GetARNList(false), DeploymentID: globalDeploymentID, Buckets: buckets, diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 1fd6b6290..4abc6556c 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -396,10 +396,10 @@ func (e errorCodeMap) ToAPIErrWithErr(errCode APIErrorCode, err error) APIError if err != nil { apiErr.Description = fmt.Sprintf("%s (%s)", apiErr.Description, err) } - if globalServerRegion != "" { + if globalSite.Region != "" { switch errCode { case ErrAuthorizationHeaderMalformed: - apiErr.Description = fmt.Sprintf("The authorization header is malformed; the region is wrong; expecting '%s'.", globalServerRegion) + apiErr.Description = fmt.Sprintf("The authorization header is malformed; the region is wrong; expecting '%s'.", globalSite.Region) return apiErr } } @@ -2286,7 +2286,7 @@ func getAPIErrorResponse(ctx context.Context, err APIError, resource, requestID, BucketName: reqInfo.BucketName, Key: reqInfo.ObjectName, Resource: resource, - Region: globalServerRegion, + Region: globalSite.Region, RequestID: requestID, HostID: hostID, } diff --git a/cmd/api-headers.go b/cmd/api-headers.go index 210c29f7e..a847fac63 100644 --- a/cmd/api-headers.go +++ b/cmd/api-headers.go @@ -52,7 +52,7 @@ func setCommonHeaders(w http.ResponseWriter) { // Set `x-amz-bucket-region` only if region is set on the server // by default minio uses an empty region. - if region := globalServerRegion; region != "" { + if region := globalSite.Region; region != "" { w.Header().Set(xhttp.AmzBucketRegion, region) } w.Header().Set(xhttp.AcceptRanges, "bytes") diff --git a/cmd/api-response.go b/cmd/api-response.go index 5dd10e8a0..f4fa79c42 100644 --- a/cmd/api-response.go +++ b/cmd/api-response.go @@ -787,9 +787,9 @@ func writeErrorResponse(ctx context.Context, w http.ResponseWriter, err APIError // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After w.Header().Set(xhttp.RetryAfter, "120") case "InvalidRegion": - err.Description = fmt.Sprintf("Region does not match; expecting '%s'.", globalServerRegion) + err.Description = fmt.Sprintf("Region does not match; expecting '%s'.", globalSite.Region) case "AuthorizationHeaderMalformed": - err.Description = fmt.Sprintf("The authorization header is malformed; the region is wrong; expecting '%s'.", globalServerRegion) + err.Description = fmt.Sprintf("The authorization header is malformed; the region is wrong; expecting '%s'.", globalSite.Region) } // Generate error response. diff --git a/cmd/auth-handler.go b/cmd/auth-handler.go index 9022bb645..4b971975c 100644 --- a/cmd/auth-handler.go +++ b/cmd/auth-handler.go @@ -299,7 +299,7 @@ func checkRequestAuthTypeCredential(ctx context.Context, r *http.Request, action } cred, owner, s3Err = getReqAccessKeyV2(r) case authTypeSigned, authTypePresigned: - region := globalServerRegion + region := globalSite.Region switch action { case policy.GetBucketLocationAction, policy.ListAllMyBucketsAction: region = "" @@ -529,7 +529,7 @@ func validateSignature(atype authType, r *http.Request) (auth.Credentials, bool, } cred, owner, s3Err = getReqAccessKeyV2(r) case authTypePresigned, authTypeSigned: - region := globalServerRegion + region := globalSite.Region if s3Err = isReqAuthenticated(GlobalContext, r, region, serviceS3); s3Err != ErrNone { return cred, owner, s3Err } @@ -596,7 +596,7 @@ func isPutActionAllowed(ctx context.Context, atype authType, bucketName, objectN case authTypeSignedV2, authTypePresignedV2: cred, owner, s3Err = getReqAccessKeyV2(r) case authTypeStreamingSigned, authTypePresigned, authTypeSigned: - region := globalServerRegion + region := globalSite.Region cred, owner, s3Err = getReqAccessKeyV4(r, region, serviceS3) } if s3Err != ErrNone { diff --git a/cmd/auth-handler_test.go b/cmd/auth-handler_test.go index a25bde1e9..247898551 100644 --- a/cmd/auth-handler_test.go +++ b/cmd/auth-handler_test.go @@ -397,7 +397,7 @@ func TestIsReqAuthenticated(t *testing.T) { // Validates all testcases. for i, testCase := range testCases { - s3Error := isReqAuthenticated(ctx, testCase.req, globalServerRegion, serviceS3) + s3Error := isReqAuthenticated(ctx, testCase.req, globalSite.Region, serviceS3) if s3Error != testCase.s3Error { if _, err := ioutil.ReadAll(testCase.req.Body); toAPIErrorCode(ctx, err) != testCase.s3Error { t.Fatalf("Test %d: Unexpected S3 error: want %d - got %d (got after reading request %s)", i, testCase.s3Error, s3Error, toAPIError(ctx, err).Code) @@ -435,7 +435,7 @@ func TestCheckAdminRequestAuthType(t *testing.T) { } ctx := context.Background() for i, testCase := range testCases { - if _, s3Error := checkAdminRequestAuth(ctx, testCase.Request, iampolicy.AllAdminActions, globalServerRegion); s3Error != testCase.ErrCode { + if _, s3Error := checkAdminRequestAuth(ctx, testCase.Request, iampolicy.AllAdminActions, globalSite.Region); s3Error != testCase.ErrCode { t.Errorf("Test %d: Unexpected s3error returned wanted %d, got %d", i, testCase.ErrCode, s3Error) } } diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 54c036eed..cc0910eab 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -211,7 +211,7 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r * // Generate response. encodedSuccessResponse := encodeResponse(LocationResponse{}) // Get current region. - region := globalServerRegion + region := globalSite.Region if region != globalMinioDefaultRegion { encodedSuccessResponse = encodeResponse(LocationResponse{ Location: region, diff --git a/cmd/bucket-notification-handlers.go b/cmd/bucket-notification-handlers.go index c64e09db7..af2b3fe9e 100644 --- a/cmd/bucket-notification-handlers.go +++ b/cmd/bucket-notification-handlers.go @@ -72,8 +72,8 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) return } - config.SetRegion(globalServerRegion) - if err = config.Validate(globalServerRegion, globalNotificationSys.targetList); err != nil { + config.SetRegion(globalSite.Region) + if err = config.Validate(globalSite.Region, globalNotificationSys.targetList); err != nil { arnErr, ok := err.(*event.ErrARNNotFound) if ok { for i, queue := range config.QueueList { @@ -145,7 +145,7 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, return } - config, err := event.ParseConfig(io.LimitReader(r.Body, r.ContentLength), globalServerRegion, globalNotificationSys.targetList) + config, err := event.ParseConfig(io.LimitReader(r.Body, r.ContentLength), globalSite.Region, globalNotificationSys.targetList) if err != nil { apiErr := errorCodes.ToAPIErr(ErrMalformedXML) if event.IsEventError(err) { diff --git a/cmd/common-main.go b/cmd/common-main.go index fb22f7701..3a573770d 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -187,7 +187,7 @@ func minioConfigToConsoleFeatures() { os.Setenv("CONSOLE_IDP_CALLBACK", getConsoleEndpoints()[0]+"/oauth_callback") } } - os.Setenv("CONSOLE_MINIO_REGION", globalServerRegion) + os.Setenv("CONSOLE_MINIO_REGION", globalSite.Region) os.Setenv("CONSOLE_CERT_PASSWD", env.Get("MINIO_CERT_PASSWD", "")) if globalSubnetConfig.License != "" { os.Setenv("CONSOLE_SUBNET_LICENSE", globalSubnetConfig.License) diff --git a/cmd/config-common.go b/cmd/config-common.go index 1afff3baf..250da471b 100644 --- a/cmd/config-common.go +++ b/cmd/config-common.go @@ -30,7 +30,6 @@ import ( var errConfigNotFound = errors.New("config file not found") func readConfig(ctx context.Context, objAPI ObjectLayer, configFile string) ([]byte, error) { - // Read entire content by setting size to -1 r, err := objAPI.GetObjectNInfo(ctx, minioMetaBucket, configFile, nil, http.Header{}, readLock, ObjectOptions{}) if err != nil { // Treat object not found as config not found. diff --git a/cmd/config-current.go b/cmd/config-current.go index 283d2c92f..00cc18b0d 100644 --- a/cmd/config-current.go +++ b/cmd/config-current.go @@ -58,6 +58,7 @@ func initHelp() { config.IdentityOpenIDSubSys: openid.DefaultKVS, config.IdentityTLSSubSys: xtls.DefaultKVS, config.PolicyOPASubSys: opa.DefaultKVS, + config.SiteSubSys: config.DefaultSiteKVS, config.RegionSubSys: config.DefaultRegionKVS, config.APISubSys: api.DefaultKVS, config.CredentialsSubSys: config.DefaultCredentialKVS, @@ -79,8 +80,8 @@ func initHelp() { // Captures help for each sub-system var helpSubSys = config.HelpKVS{ config.HelpKV{ - Key: config.RegionSubSys, - Description: "label the location of the server", + Key: config.SiteSubSys, + Description: "label the server and its location", }, config.HelpKV{ Key: config.CacheSubSys, @@ -206,6 +207,7 @@ func initHelp() { var helpMap = map[string]config.HelpKVS{ "": helpSubSys, // Help for all sub-systems. + config.SiteSubSys: config.SiteHelp, config.RegionSubSys: config.RegionHelp, config.APISubSys: api.Help, config.StorageClassSubSys: storageclass.Help, @@ -235,6 +237,16 @@ func initHelp() { } config.RegisterHelpSubSys(helpMap) + + // save top-level help for deprecated sub-systems in a separate map. + deprecatedHelpKVMap := map[string]config.HelpKV{ + config.RegionSubSys: { + Key: config.RegionSubSys, + Description: "[DEPRECATED - use `site` instead] label the location of the server", + }, + } + + config.RegisterHelpDeprecatedSubSys(deprecatedHelpKVMap) } var ( @@ -259,7 +271,7 @@ func validateConfig(s config.Config) error { return err } - if _, err := config.LookupRegion(s[config.RegionSubSys][config.Default]); err != nil { + if _, err := config.LookupSite(s[config.SiteSubSys][config.Default], s[config.RegionSubSys][config.Default]); err != nil { return err } @@ -437,9 +449,9 @@ func lookupConfigs(s config.Config, objAPI ObjectLayer) { // but not federation. globalBucketFederation = etcdCfg.PathPrefix == "" && etcdCfg.Enabled - globalServerRegion, err = config.LookupRegion(s[config.RegionSubSys][config.Default]) + globalSite, err = config.LookupSite(s[config.SiteSubSys][config.Default], s[config.RegionSubSys][config.Default]) if err != nil { - logger.LogIf(ctx, fmt.Errorf("Invalid region configuration: %w", err)) + logger.LogIf(ctx, fmt.Errorf("Invalid site configuration: %w", err)) } apiConfig, err := api.LookupConfig(s[config.APISubSys][config.Default]) @@ -674,7 +686,10 @@ func GetHelp(subSys, key string, envOnly bool) (Help, error) { subSysHelp, ok := config.HelpSubSysMap[""].Lookup(subSys) if !ok { - return Help{}, config.Errorf("unknown sub-system %s", subSys) + subSysHelp, ok = config.HelpDeprecatedSubSysMap[subSys] + if !ok { + return Help{}, config.Errorf("unknown sub-system %s", subSys) + } } h, ok := config.HelpSubSysMap[subSys] diff --git a/cmd/config-current_test.go b/cmd/config-current_test.go index ea3cda245..6c2fa2526 100644 --- a/cmd/config-current_test.go +++ b/cmd/config-current_test.go @@ -36,18 +36,21 @@ func TestServerConfig(t *testing.T) { t.Fatalf("Init Test config failed") } - if globalServerRegion != globalMinioDefaultRegion { - t.Errorf("Expecting region `us-east-1` found %s", globalServerRegion) + if globalSite.Region != globalMinioDefaultRegion { + t.Errorf("Expecting region `us-east-1` found %s", globalSite.Region) } // Set new region and verify. config.SetRegion(globalServerConfig, "us-west-1") - region, err := config.LookupRegion(globalServerConfig[config.RegionSubSys][config.Default]) + site, err := config.LookupSite( + globalServerConfig[config.SiteSubSys][config.Default], + globalServerConfig[config.RegionSubSys][config.Default], + ) if err != nil { t.Fatal(err) } - if region != "us-west-1" { - t.Errorf("Expecting region `us-west-1` found %s", globalServerRegion) + if site.Region != "us-west-1" { + t.Errorf("Expecting region `us-west-1` found %s", globalSite.Region) } if err := saveServerConfig(context.Background(), objLayer, globalServerConfig); err != nil { diff --git a/cmd/config.go b/cmd/config.go index e55a48cfe..b1f76d642 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -186,11 +186,6 @@ func readServerConfig(ctx context.Context, objAPI ObjectLayer) (config.Config, e // ConfigSys - config system. type ConfigSys struct{} -// Load - load config.json. -func (sys *ConfigSys) Load(objAPI ObjectLayer) error { - return sys.Init(objAPI) -} - // Init - initializes config system from config.json. func (sys *ConfigSys) Init(objAPI ObjectLayer) error { if objAPI == nil { diff --git a/cmd/globals.go b/cmd/globals.go index d42e94496..7dd5f5c02 100644 --- a/cmd/globals.go +++ b/cmd/globals.go @@ -29,6 +29,7 @@ import ( "github.com/minio/console/restapi" "github.com/minio/minio-go/v7/pkg/set" "github.com/minio/minio/internal/bucket/bandwidth" + "github.com/minio/minio/internal/config" "github.com/minio/minio/internal/handlers" "github.com/minio/minio/internal/kms" "github.com/rs/dnscache" @@ -148,8 +149,9 @@ var ( // This flag is set to 'true' when MINIO_UPDATE env is set to 'off'. Default is false. globalInplaceUpdateDisabled = false - // This flag is set to 'us-east-1' by default - globalServerRegion = globalMinioDefaultRegion + globalSite = config.Site{ + Region: globalMinioDefaultRegion, + } // MinIO local server address (in `host:port` format) globalMinioAddr = "" diff --git a/cmd/handler-utils.go b/cmd/handler-utils.go index 592d92662..ceb8208ea 100644 --- a/cmd/handler-utils.go +++ b/cmd/handler-utils.go @@ -58,7 +58,7 @@ func parseLocationConstraint(r *http.Request) (location string, s3Error APIError } // else for both err as nil or io.EOF location = locationConstraint.Location if location == "" { - location = globalServerRegion + location = globalSite.Region } return location, ErrNone } @@ -66,7 +66,7 @@ func parseLocationConstraint(r *http.Request) (location string, s3Error APIError // Validates input location is same as configured region // of MinIO server. func isValidLocation(location string) bool { - return globalServerRegion == "" || globalServerRegion == location + return globalSite.Region == "" || globalSite.Region == location } // Supported headers that needs to be extracted. @@ -222,7 +222,7 @@ func extractReqParams(r *http.Request) map[string]string { return nil } - region := globalServerRegion + region := globalSite.Region cred := getReqAccessCred(r, region) principalID := cred.AccessKey diff --git a/cmd/notification.go b/cmd/notification.go index 96bb142f2..432750d0d 100644 --- a/cmd/notification.go +++ b/cmd/notification.go @@ -63,7 +63,7 @@ func (sys *NotificationSys) GetARNList(onlyActive bool) []string { if sys == nil { return arns } - region := globalServerRegion + region := globalSite.Region for targetID, target := range sys.targetList.TargetMap() { // httpclient target is part of ListenNotification // which doesn't need to be listed as part of the ARN list @@ -643,8 +643,8 @@ func (sys *NotificationSys) set(bucket BucketInfo, meta BucketMetadata) { if config == nil { return } - config.SetRegion(globalServerRegion) - if err := config.Validate(globalServerRegion, globalNotificationSys.targetList); err != nil { + config.SetRegion(globalSite.Region) + if err := config.Validate(globalSite.Region, globalNotificationSys.targetList); err != nil { if _, ok := err.(*event.ErrARNNotFound); !ok { logger.LogIf(GlobalContext, err) } diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 08a29a35e..ff394d5d8 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -862,7 +862,7 @@ var ( // Returns a minio-go Client configured to access remote host described by destDNSRecord // Applicable only in a federated deployment var getRemoteInstanceClient = func(r *http.Request, host string) (*miniogo.Core, error) { - cred := getReqAccessCred(r, globalServerRegion) + cred := getReqAccessCred(r, globalSite.Region) // In a federated deployment, all the instances share config files // and hence expected to have same credentials. return miniogo.NewCore(host, &miniogo.Options{ @@ -1651,7 +1651,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req } case authTypePresigned, authTypeSigned: - if s3Err = reqSignatureV4Verify(r, globalServerRegion, serviceS3); s3Err != ErrNone { + if s3Err = reqSignatureV4Verify(r, globalSite.Region, serviceS3); s3Err != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) return } @@ -1982,7 +1982,7 @@ func (api objectAPIHandlers) PutObjectExtractHandler(w http.ResponseWriter, r *h } case authTypePresigned, authTypeSigned: - if s3Err = reqSignatureV4Verify(r, globalServerRegion, serviceS3); s3Err != ErrNone { + if s3Err = reqSignatureV4Verify(r, globalSite.Region, serviceS3); s3Err != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL) return } @@ -2739,7 +2739,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http return } case authTypePresigned, authTypeSigned: - if s3Error = reqSignatureV4Verify(r, globalServerRegion, serviceS3); s3Error != ErrNone { + if s3Error = reqSignatureV4Verify(r, globalSite.Region, serviceS3); s3Error != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL) return } diff --git a/cmd/server-startup-msg.go b/cmd/server-startup-msg.go index 986c5008f..1dabc5fde 100644 --- a/cmd/server-startup-msg.go +++ b/cmd/server-startup-msg.go @@ -126,7 +126,7 @@ func printServerCommonMsg(apiEndpoints []string) { cred := globalActiveCred // Get saved region. - region := globalServerRegion + region := globalSite.Region apiEndpointStr := strings.Join(apiEndpoints, " ") diff --git a/cmd/signature-v4.go b/cmd/signature-v4.go index bda7535a6..c4032cb7b 100644 --- a/cmd/signature-v4.go +++ b/cmd/signature-v4.go @@ -173,7 +173,7 @@ func compareSignatureV4(sig1, sig2 string) bool { // returns ErrNone if the signature matches. func doesPolicySignatureV4Match(formValues http.Header) (auth.Credentials, APIErrorCode) { // Server region. - region := globalServerRegion + region := globalSite.Region // Parse credential tag. credHeader, s3Err := parseCredentialHeader("Credential="+formValues.Get(xhttp.AmzCredential), region, serviceS3) diff --git a/cmd/signature-v4_test.go b/cmd/signature-v4_test.go index 0652e7bde..26e3aa67d 100644 --- a/cmd/signature-v4_test.go +++ b/cmd/signature-v4_test.go @@ -107,7 +107,7 @@ func TestDoesPresignedSignatureMatch(t *testing.T) { now := UTCNow() credentialTemplate := "%s/%s/%s/s3/aws4_request" - region := globalServerRegion + region := globalSite.Region accessKeyID := globalActiveCred.AccessKey testCases := []struct { queryParams map[string]string diff --git a/cmd/streaming-signature-v4.go b/cmd/streaming-signature-v4.go index 06680ac25..35d91d521 100644 --- a/cmd/streaming-signature-v4.go +++ b/cmd/streaming-signature-v4.go @@ -74,7 +74,7 @@ func calculateSeedSignature(r *http.Request) (cred auth.Credentials, signature s v4Auth := req.Header.Get(xhttp.Authorization) // Parse signature version '4' header. - signV4Values, errCode := parseSignV4(v4Auth, globalServerRegion, serviceS3) + signV4Values, errCode := parseSignV4(v4Auth, globalSite.Region, serviceS3) if errCode != ErrNone { return cred, "", "", time.Time{}, errCode } diff --git a/cmd/sts-handlers.go b/cmd/sts-handlers.go index 1f42a3900..468778f05 100644 --- a/cmd/sts-handlers.go +++ b/cmd/sts-handlers.go @@ -142,12 +142,12 @@ func checkAssumeRoleAuth(ctx context.Context, r *http.Request) (user auth.Creden default: return user, true, ErrSTSAccessDenied case authTypeSigned: - s3Err := isReqAuthenticated(ctx, r, globalServerRegion, serviceSTS) + s3Err := isReqAuthenticated(ctx, r, globalSite.Region, serviceSTS) if s3Err != ErrNone { return user, false, STSErrorCode(s3Err) } - user, _, s3Err = getReqAccessKeyV4(r, globalServerRegion, serviceSTS) + user, _, s3Err = getReqAccessKeyV4(r, globalSite.Region, serviceSTS) if s3Err != ErrNone { return user, false, STSErrorCode(s3Err) } diff --git a/cmd/test-utils_test.go b/cmd/test-utils_test.go index 0f846594e..1875a0aa8 100644 --- a/cmd/test-utils_test.go +++ b/cmd/test-utils_test.go @@ -725,7 +725,7 @@ func newTestStreamingRequest(method, urlStr string, dataLength, chunkSize int64, func assembleStreamingChunks(req *http.Request, body io.ReadSeeker, chunkSize int64, secretKey, signature string, currTime time.Time) (*http.Request, error) { - regionStr := globalServerRegion + regionStr := globalSite.Region var stream []byte var buffer []byte body.Seek(0, 0) @@ -833,7 +833,7 @@ func preSignV4(req *http.Request, accessKeyID, secretAccessKey string, expires i return errors.New("Presign cannot be generated without access and secret keys") } - region := globalServerRegion + region := globalSite.Region date := UTCNow() scope := getScope(date, region) credential := fmt.Sprintf("%s/%s", accessKeyID, scope) @@ -961,7 +961,7 @@ func signRequestV4(req *http.Request, accessKey, secretKey string) error { } sort.Strings(headers) - region := globalServerRegion + region := globalSite.Region // Get canonical headers. var buf bytes.Buffer diff --git a/docs/config/README.md b/docs/config/README.md index 64e5d3819..ef5f56e50 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -40,30 +40,33 @@ export MINIO_ROOT_PASSWORD=minio13 minio server /data ``` -#### Region +#### Site ``` KEY: -region label the location of the server +site label the server and its location ARGS: -name (string) name of the location of the server e.g. "us-west-rack2" +name (string) name for the site e.g. "cal-rack0" +region (string) name of the location of the server e.g. "us-west-1" comment (sentence) optionally add a comment to this setting ``` or environment variables ``` KEY: -region label the location of the server +site label the server and its location ARGS: -MINIO_REGION_NAME (string) name of the location of the server e.g. "us-west-rack2" -MINIO_REGION_COMMENT (sentence) optionally add a comment to this setting +MINIO_SITE_NAME (string) name for the site e.g. "cal-rack0" +MINIO_SITE_REGION (string) name of the location of the server e.g. "us-west-1" +MINIO_SITE_COMMENT (sentence) optionally add a comment to this setting ``` Example: ```sh -export MINIO_REGION_NAME="my_region" +export MINIO_SITE_REGION="us-west-0" +export MINIO_SITE_NAME="sfo-rack-1" minio server /data ``` diff --git a/internal/config/config.go b/internal/config/config.go index c9bc5a682..0f823bd61 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -55,6 +55,8 @@ const ( EnableOn = madmin.EnableOn EnableOff = madmin.EnableOff + RegionKey = "region" + NameKey = "name" RegionName = "name" AccessKey = "access_key" SecretKey = "secret_key" @@ -69,6 +71,7 @@ const ( IdentityLDAPSubSys = "identity_ldap" IdentityTLSSubSys = "identity_tls" CacheSubSys = "cache" + SiteSubSys = "site" RegionSubSys = "region" EtcdSubSys = "etcd" StorageClassSubSys = "storage_class" @@ -104,6 +107,7 @@ const ( // SubSystems - all supported sub-systems var SubSystems = set.CreateStringSet( CredentialsSubSys, + SiteSubSys, RegionSubSys, EtcdSubSys, CacheSubSys, @@ -144,6 +148,7 @@ var SubSystemsDynamic = set.CreateStringSet( // SubSystemsSingleTargets - subsystems which only support single target. var SubSystemsSingleTargets = set.CreateStringSet([]string{ CredentialsSubSys, + SiteSubSys, RegionSubSys, EtcdSubSys, CacheSubSys, @@ -202,6 +207,19 @@ func RegisterHelpSubSys(helpKVSMap map[string]HelpKVS) { } } +// HelpDeprecatedSubSysMap - help for all deprecated sub-systems, that may be +// removed in the future. +var HelpDeprecatedSubSysMap map[string]HelpKV + +// RegisterHelpDeprecatedSubSys - saves input help KVS for deprecated +// sub-systems globally. Should be called only once at init. +func RegisterHelpDeprecatedSubSys(helpDeprecatedKVMap map[string]HelpKV) { + HelpDeprecatedSubSysMap = map[string]HelpKV{} + for k, v := range helpDeprecatedKVMap { + HelpDeprecatedSubSysMap[k] = v + } +} + // KV - is a shorthand of each key value. type KV struct { Key string `json:"key"` @@ -449,6 +467,17 @@ var ( }, } + DefaultSiteKVS = KVS{ + KV{ + Key: NameKey, + Value: "", + }, + KV{ + Key: RegionKey, + Value: "", + }, + } + DefaultRegionKVS = KVS{ KV{ Key: RegionName, @@ -471,26 +500,66 @@ func LookupCreds(kv KVS) (auth.Credentials, error) { return auth.CreateCredentials(accessKey, secretKey) } +// Site - holds site info - name and region. +type Site struct { + Name string + Region string +} + var validRegionRegex = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-_-]+$") -// LookupRegion - get current region. -func LookupRegion(kv KVS) (string, error) { - if err := CheckValidKeys(RegionSubSys, kv, DefaultRegionKVS); err != nil { - return "", err +// validSiteNameRegex - allows lowercase letters, digits and '-', starts with +// letter. At least 2 characters long. +var validSiteNameRegex = regexp.MustCompile("^[a-z][a-z0-9-]+$") + +// LookupSite - get site related configuration. Loads configuration from legacy +// region sub-system as well. +func LookupSite(siteKV KVS, regionKV KVS) (s Site, err error) { + if err = CheckValidKeys(SiteSubSys, siteKV, DefaultSiteKVS); err != nil { + return } region := env.Get(EnvRegion, "") if region == "" { - region = env.Get(EnvRegionName, kv.Get(RegionName)) + env.Get(EnvRegionName, "") + } + if region == "" { + region = env.Get(EnvSiteRegion, siteKV.Get(RegionKey)) + } + if region == "" { + // No region config found in the site-subsystem. So lookup the legacy + // region sub-system. + if err = CheckValidKeys(RegionSubSys, regionKV, DefaultRegionKVS); err != nil { + // An invalid key was found in the region sub-system. + // Since the region sub-system cannot be (re)set as it + // is legacy, we return an error to tell the user to + // reset the region via the new command. + err = Errorf("could not load region from legacy configuration as it was invalid - use 'mc admin config set myminio site region=myregion name=myname' to set a region and name (%v)", err) + return + } + + region = regionKV.Get(RegionName) } if region != "" { - if validRegionRegex.MatchString(region) { - return region, nil + if !validRegionRegex.MatchString(region) { + err = Errorf( + "region '%s' is invalid, expected simple characters such as [us-east-1, myregion...]", + region) + return } - return "", Errorf( - "region '%s' is invalid, expected simple characters such as [us-east-1, myregion...]", - region) + s.Region = region } - return "", nil + + name := env.Get(EnvSiteName, siteKV.Get(NameKey)) + if name != "" { + if !validSiteNameRegex.MatchString(name) { + err = Errorf( + "site name '%s' is invalid, expected simple characters such as [cal-rack0, myname...]", + name) + return + } + s.Name = name + } + return } // CheckValidKeys - checks if inputs KVS has the necessary keys, @@ -626,9 +695,14 @@ func (c Config) GetKVS(s string, defaultKVS map[string]KVS) (Targets, error) { KVS: kvs, }) } else { - hkvs := HelpSubSysMap[""] - // Use help for sub-system to preserve the order. - for _, hkv := range hkvs { + // Use help for sub-system to preserve the order. Add deprecated + // keys at the end (in some order). + kvsOrder := append([]HelpKV{}, HelpSubSysMap[""]...) + for _, v := range HelpDeprecatedSubSysMap { + kvsOrder = append(kvsOrder, v) + } + + for _, hkv := range kvsOrder { if !strings.HasPrefix(hkv.Key, subSysPrefix) { continue } diff --git a/internal/config/constants.go b/internal/config/constants.go index f8cf35b0b..6bab109f7 100644 --- a/internal/config/constants.go +++ b/internal/config/constants.go @@ -31,12 +31,14 @@ const ( EnvBrowser = "MINIO_BROWSER" EnvDomain = "MINIO_DOMAIN" - EnvRegionName = "MINIO_REGION_NAME" EnvPublicIPs = "MINIO_PUBLIC_IPS" EnvFSOSync = "MINIO_FS_OSYNC" EnvArgs = "MINIO_ARGS" EnvDNSWebhook = "MINIO_DNS_WEBHOOK_ENDPOINT" + EnvSiteName = "MINIO_SITE_NAME" + EnvSiteRegion = "MINIO_SITE_REGION" + EnvMinIOSubnetLicense = "MINIO_SUBNET_LICENSE" EnvMinIOServerURL = "MINIO_SERVER_URL" EnvMinIOBrowserRedirectURL = "MINIO_BROWSER_REDIRECT_URL" @@ -51,7 +53,8 @@ const ( EnvKESClientCert = "MINIO_KMS_KES_CERT_FILE" EnvKESServerCA = "MINIO_KMS_KES_CAPATH" - EnvEndpoints = "MINIO_ENDPOINTS" // legacy - EnvWorm = "MINIO_WORM" // legacy - EnvRegion = "MINIO_REGION" // legacy + EnvEndpoints = "MINIO_ENDPOINTS" // legacy + EnvWorm = "MINIO_WORM" // legacy + EnvRegion = "MINIO_REGION" // legacy + EnvRegionName = "MINIO_REGION_NAME" // legacy ) diff --git a/internal/config/help.go b/internal/config/help.go index faebda5e7..33d8acd31 100644 --- a/internal/config/help.go +++ b/internal/config/help.go @@ -49,13 +49,34 @@ func (hkvs HelpKVS) Lookup(key string) (HelpKV, bool) { // DefaultComment used across all sub-systems. const DefaultComment = "optionally add a comment to this setting" -// Region and Worm help is documented in default config +// Region help is documented in default config var ( + SiteHelp = HelpKVS{ + HelpKV{ + Key: NameKey, + Type: "string", + Description: `name for the site e.g. "cal-rack0"`, + Optional: true, + }, + HelpKV{ + Key: RegionKey, + Type: "string", + Description: `name of the location of the server e.g. "us-west-1"`, + Optional: true, + }, + HelpKV{ + Key: Comment, + Type: "sentence", + Description: DefaultComment, + Optional: true, + }, + } + RegionHelp = HelpKVS{ HelpKV{ Key: RegionName, Type: "string", - Description: `name of the location of the server e.g. "us-west-rack2"`, + Description: `[DEPRECATED] name of the location of the server e.g. "us-west-rack2"`, Optional: true, }, HelpKV{