github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/config/api/api.go (about) 1 // Copyright (c) 2015-2023 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 api 19 20 import ( 21 "encoding/json" 22 "errors" 23 "fmt" 24 "math" 25 "strconv" 26 "strings" 27 "time" 28 29 "github.com/minio/minio/internal/config" 30 "github.com/minio/pkg/v2/env" 31 ) 32 33 // API sub-system constants 34 const ( 35 apiRequestsMax = "requests_max" 36 apiRequestsDeadline = "requests_deadline" 37 apiClusterDeadline = "cluster_deadline" 38 apiCorsAllowOrigin = "cors_allow_origin" 39 apiRemoteTransportDeadline = "remote_transport_deadline" 40 apiListQuorum = "list_quorum" 41 apiReplicationPriority = "replication_priority" 42 apiReplicationMaxWorkers = "replication_max_workers" 43 44 apiTransitionWorkers = "transition_workers" 45 apiStaleUploadsCleanupInterval = "stale_uploads_cleanup_interval" 46 apiStaleUploadsExpiry = "stale_uploads_expiry" 47 apiDeleteCleanupInterval = "delete_cleanup_interval" 48 apiDisableODirect = "disable_odirect" 49 apiODirect = "odirect" 50 apiGzipObjects = "gzip_objects" 51 apiRootAccess = "root_access" 52 apiSyncEvents = "sync_events" 53 apiObjectMaxVersions = "object_max_versions" 54 55 EnvAPIRequestsMax = "MINIO_API_REQUESTS_MAX" 56 EnvAPIRequestsDeadline = "MINIO_API_REQUESTS_DEADLINE" 57 EnvAPIClusterDeadline = "MINIO_API_CLUSTER_DEADLINE" 58 EnvAPICorsAllowOrigin = "MINIO_API_CORS_ALLOW_ORIGIN" 59 EnvAPIRemoteTransportDeadline = "MINIO_API_REMOTE_TRANSPORT_DEADLINE" 60 EnvAPITransitionWorkers = "MINIO_API_TRANSITION_WORKERS" 61 EnvAPIListQuorum = "MINIO_API_LIST_QUORUM" 62 EnvAPISecureCiphers = "MINIO_API_SECURE_CIPHERS" // default config.EnableOn 63 EnvAPIReplicationPriority = "MINIO_API_REPLICATION_PRIORITY" 64 EnvAPIReplicationMaxWorkers = "MINIO_API_REPLICATION_MAX_WORKERS" 65 EnvAPIStaleUploadsCleanupInterval = "MINIO_API_STALE_UPLOADS_CLEANUP_INTERVAL" 66 EnvAPIStaleUploadsExpiry = "MINIO_API_STALE_UPLOADS_EXPIRY" 67 EnvAPIDeleteCleanupInterval = "MINIO_API_DELETE_CLEANUP_INTERVAL" 68 EnvDeleteCleanupInterval = "MINIO_DELETE_CLEANUP_INTERVAL" 69 EnvAPIODirect = "MINIO_API_ODIRECT" 70 EnvAPIDisableODirect = "MINIO_API_DISABLE_ODIRECT" 71 EnvAPIGzipObjects = "MINIO_API_GZIP_OBJECTS" 72 EnvAPIRootAccess = "MINIO_API_ROOT_ACCESS" // default config.EnableOn 73 EnvAPISyncEvents = "MINIO_API_SYNC_EVENTS" // default "off" 74 EnvAPIObjectMaxVersions = "MINIO_API_OBJECT_MAX_VERSIONS" 75 EnvAPIObjectMaxVersionsLegacy = "_MINIO_OBJECT_MAX_VERSIONS" 76 ) 77 78 // Deprecated key and ENVs 79 const ( 80 apiReadyDeadline = "ready_deadline" 81 apiReplicationWorkers = "replication_workers" 82 apiReplicationFailedWorkers = "replication_failed_workers" 83 ) 84 85 // DefaultKVS - default storage class config 86 var ( 87 DefaultKVS = config.KVS{ 88 config.KV{ 89 Key: apiRequestsMax, 90 Value: "0", 91 }, 92 config.KV{ 93 Key: apiRequestsDeadline, 94 Value: "10s", 95 }, 96 config.KV{ 97 Key: apiClusterDeadline, 98 Value: "10s", 99 }, 100 config.KV{ 101 Key: apiCorsAllowOrigin, 102 Value: "*", 103 }, 104 config.KV{ 105 Key: apiRemoteTransportDeadline, 106 Value: "2h", 107 }, 108 config.KV{ 109 Key: apiListQuorum, 110 Value: "strict", 111 }, 112 config.KV{ 113 Key: apiReplicationPriority, 114 Value: "auto", 115 }, 116 config.KV{ 117 Key: apiReplicationMaxWorkers, 118 Value: "500", 119 }, 120 config.KV{ 121 Key: apiTransitionWorkers, 122 Value: "100", 123 }, 124 config.KV{ 125 Key: apiStaleUploadsCleanupInterval, 126 Value: "6h", 127 }, 128 config.KV{ 129 Key: apiStaleUploadsExpiry, 130 Value: "24h", 131 }, 132 config.KV{ 133 Key: apiDeleteCleanupInterval, 134 Value: "5m", 135 }, 136 config.KV{ 137 Key: apiDisableODirect, 138 Value: "", 139 HiddenIfEmpty: true, 140 }, 141 config.KV{ 142 Key: apiODirect, 143 Value: config.EnableOn, 144 }, 145 config.KV{ 146 Key: apiGzipObjects, 147 Value: config.EnableOff, 148 }, 149 config.KV{ 150 Key: apiRootAccess, 151 Value: config.EnableOn, 152 }, 153 config.KV{ 154 Key: apiSyncEvents, 155 Value: config.EnableOff, 156 }, 157 config.KV{ 158 Key: apiObjectMaxVersions, 159 Value: "9223372036854775807", 160 }, 161 } 162 ) 163 164 // Config storage class configuration 165 type Config struct { 166 RequestsMax int `json:"requests_max"` 167 RequestsDeadline time.Duration `json:"requests_deadline"` 168 ClusterDeadline time.Duration `json:"cluster_deadline"` 169 CorsAllowOrigin []string `json:"cors_allow_origin"` 170 RemoteTransportDeadline time.Duration `json:"remote_transport_deadline"` 171 ListQuorum string `json:"list_quorum"` 172 ReplicationPriority string `json:"replication_priority"` 173 ReplicationMaxWorkers int `json:"replication_max_workers"` 174 TransitionWorkers int `json:"transition_workers"` 175 StaleUploadsCleanupInterval time.Duration `json:"stale_uploads_cleanup_interval"` 176 StaleUploadsExpiry time.Duration `json:"stale_uploads_expiry"` 177 DeleteCleanupInterval time.Duration `json:"delete_cleanup_interval"` 178 EnableODirect bool `json:"enable_odirect"` 179 GzipObjects bool `json:"gzip_objects"` 180 RootAccess bool `json:"root_access"` 181 SyncEvents bool `json:"sync_events"` 182 ObjectMaxVersions int64 `json:"object_max_versions"` 183 } 184 185 // UnmarshalJSON - Validate SS and RRS parity when unmarshalling JSON. 186 func (sCfg *Config) UnmarshalJSON(data []byte) error { 187 type Alias Config 188 aux := &struct { 189 *Alias 190 }{ 191 Alias: (*Alias)(sCfg), 192 } 193 return json.Unmarshal(data, &aux) 194 } 195 196 // LookupConfig - lookup api config and override with valid environment settings if any. 197 func LookupConfig(kvs config.KVS) (cfg Config, err error) { 198 deprecatedKeys := []string{ 199 apiReadyDeadline, 200 "extend_list_cache_life", 201 apiReplicationWorkers, 202 apiReplicationFailedWorkers, 203 "expiry_workers", 204 } 205 206 disableODirect := env.Get(EnvAPIDisableODirect, kvs.Get(apiDisableODirect)) == config.EnableOn 207 enableODirect := env.Get(EnvAPIODirect, kvs.Get(apiODirect)) == config.EnableOn 208 gzipObjects := env.Get(EnvAPIGzipObjects, kvs.Get(apiGzipObjects)) == config.EnableOn 209 rootAccess := env.Get(EnvAPIRootAccess, kvs.Get(apiRootAccess)) == config.EnableOn 210 211 cfg = Config{ 212 EnableODirect: enableODirect || !disableODirect, 213 GzipObjects: gzipObjects, 214 RootAccess: rootAccess, 215 } 216 217 var corsAllowOrigin []string 218 corsList := env.Get(EnvAPICorsAllowOrigin, kvs.Get(apiCorsAllowOrigin)) 219 if corsList == "" { 220 corsAllowOrigin = []string{"*"} // defaults to '*' 221 } else { 222 corsAllowOrigin = strings.Split(corsList, ",") 223 for _, cors := range corsAllowOrigin { 224 if cors == "" { 225 return cfg, errors.New("invalid cors value") 226 } 227 } 228 } 229 cfg.CorsAllowOrigin = corsAllowOrigin 230 231 if err = config.CheckValidKeys(config.APISubSys, kvs, DefaultKVS, deprecatedKeys...); err != nil { 232 return cfg, err 233 } 234 235 // Check environment variables parameters 236 requestsMax, err := strconv.Atoi(env.Get(EnvAPIRequestsMax, kvs.GetWithDefault(apiRequestsMax, DefaultKVS))) 237 if err != nil { 238 return cfg, err 239 } 240 241 cfg.RequestsMax = requestsMax 242 if requestsMax < 0 { 243 return cfg, errors.New("invalid API max requests value") 244 } 245 246 requestsDeadline, err := time.ParseDuration(env.Get(EnvAPIRequestsDeadline, kvs.GetWithDefault(apiRequestsDeadline, DefaultKVS))) 247 if err != nil { 248 return cfg, err 249 } 250 cfg.RequestsDeadline = requestsDeadline 251 252 clusterDeadline, err := time.ParseDuration(env.Get(EnvAPIClusterDeadline, kvs.GetWithDefault(apiClusterDeadline, DefaultKVS))) 253 if err != nil { 254 return cfg, err 255 } 256 cfg.ClusterDeadline = clusterDeadline 257 258 remoteTransportDeadline, err := time.ParseDuration(env.Get(EnvAPIRemoteTransportDeadline, kvs.GetWithDefault(apiRemoteTransportDeadline, DefaultKVS))) 259 if err != nil { 260 return cfg, err 261 } 262 cfg.RemoteTransportDeadline = remoteTransportDeadline 263 264 listQuorum := env.Get(EnvAPIListQuorum, kvs.GetWithDefault(apiListQuorum, DefaultKVS)) 265 switch listQuorum { 266 case "strict", "optimal", "reduced", "disk", "auto": 267 default: 268 return cfg, fmt.Errorf("invalid value %v for list_quorum: will default to 'strict'", listQuorum) 269 } 270 cfg.ListQuorum = listQuorum 271 272 replicationPriority := env.Get(EnvAPIReplicationPriority, kvs.GetWithDefault(apiReplicationPriority, DefaultKVS)) 273 switch replicationPriority { 274 case "slow", "fast", "auto": 275 default: 276 return cfg, fmt.Errorf("invalid value %v for replication_priority", replicationPriority) 277 } 278 cfg.ReplicationPriority = replicationPriority 279 replicationMaxWorkers, err := strconv.Atoi(env.Get(EnvAPIReplicationMaxWorkers, kvs.GetWithDefault(apiReplicationMaxWorkers, DefaultKVS))) 280 if err != nil { 281 return cfg, err 282 } 283 284 if replicationMaxWorkers <= 0 || replicationMaxWorkers > 500 { 285 return cfg, config.ErrInvalidReplicationWorkersValue(nil).Msg("Number of replication workers should be between 1 and 500") 286 } 287 cfg.ReplicationMaxWorkers = replicationMaxWorkers 288 transitionWorkers, err := strconv.Atoi(env.Get(EnvAPITransitionWorkers, kvs.GetWithDefault(apiTransitionWorkers, DefaultKVS))) 289 if err != nil { 290 return cfg, err 291 } 292 cfg.TransitionWorkers = transitionWorkers 293 294 v := env.Get(EnvAPIDeleteCleanupInterval, kvs.Get(apiDeleteCleanupInterval)) 295 if v == "" { 296 v = env.Get(EnvDeleteCleanupInterval, kvs.GetWithDefault(apiDeleteCleanupInterval, DefaultKVS)) 297 } 298 299 deleteCleanupInterval, err := time.ParseDuration(v) 300 if err != nil { 301 return cfg, err 302 } 303 cfg.DeleteCleanupInterval = deleteCleanupInterval 304 305 staleUploadsCleanupInterval, err := time.ParseDuration(env.Get(EnvAPIStaleUploadsCleanupInterval, kvs.GetWithDefault(apiStaleUploadsCleanupInterval, DefaultKVS))) 306 if err != nil { 307 return cfg, err 308 } 309 cfg.StaleUploadsCleanupInterval = staleUploadsCleanupInterval 310 311 staleUploadsExpiry, err := time.ParseDuration(env.Get(EnvAPIStaleUploadsExpiry, kvs.GetWithDefault(apiStaleUploadsExpiry, DefaultKVS))) 312 if err != nil { 313 return cfg, err 314 } 315 cfg.StaleUploadsExpiry = staleUploadsExpiry 316 317 cfg.SyncEvents = env.Get(EnvAPISyncEvents, kvs.Get(apiSyncEvents)) == config.EnableOn 318 319 maxVerStr := env.Get(EnvAPIObjectMaxVersions, "") 320 if maxVerStr == "" { 321 maxVerStr = env.Get(EnvAPIObjectMaxVersionsLegacy, kvs.Get(apiObjectMaxVersions)) 322 } 323 if maxVerStr != "" { 324 maxVersions, err := strconv.ParseInt(maxVerStr, 10, 64) 325 if err != nil { 326 return cfg, err 327 } 328 if maxVersions <= 0 { 329 return cfg, fmt.Errorf("invalid object max versions value: %v", maxVersions) 330 } 331 cfg.ObjectMaxVersions = maxVersions 332 } else { 333 cfg.ObjectMaxVersions = math.MaxInt64 334 } 335 336 return cfg, nil 337 }