mirror of https://github.com/minio/minio.git
Refactor config and split them in packages (#8351)
This change is related to larger config migration PR change, this is a first stage change to move our configs to `cmd/config/` - divided into its subsystems
This commit is contained in:
parent
74008446fe
commit
589e32a4ed
28
cmd/certs.go
28
cmd/certs.go
|
@ -24,9 +24,10 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
"github.com/minio/minio/pkg/certs"
|
"github.com/minio/minio/pkg/certs"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TLSPrivateKeyPassword is the environment variable which contains the password used
|
// TLSPrivateKeyPassword is the environment variable which contains the password used
|
||||||
|
@ -49,19 +50,19 @@ func parsePublicCertFile(certFile string) (x509Certs []*x509.Certificate, err er
|
||||||
for len(current) > 0 {
|
for len(current) > 0 {
|
||||||
var pemBlock *pem.Block
|
var pemBlock *pem.Block
|
||||||
if pemBlock, current = pem.Decode(current); pemBlock == nil {
|
if pemBlock, current = pem.Decode(current); pemBlock == nil {
|
||||||
return nil, uiErrSSLUnexpectedData(nil).Msg("Could not read PEM block from file %s", certFile)
|
return nil, config.ErrSSLUnexpectedData(nil).Msg("Could not read PEM block from file %s", certFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
var x509Cert *x509.Certificate
|
var x509Cert *x509.Certificate
|
||||||
if x509Cert, err = x509.ParseCertificate(pemBlock.Bytes); err != nil {
|
if x509Cert, err = x509.ParseCertificate(pemBlock.Bytes); err != nil {
|
||||||
return nil, uiErrSSLUnexpectedData(err)
|
return nil, config.ErrSSLUnexpectedData(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
x509Certs = append(x509Certs, x509Cert)
|
x509Certs = append(x509Certs, x509Cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(x509Certs) == 0 {
|
if len(x509Certs) == 0 {
|
||||||
return nil, uiErrSSLUnexpectedData(nil).Msg("Empty public certificate file %s", certFile)
|
return nil, config.ErrSSLUnexpectedData(nil).Msg("Empty public certificate file %s", certFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
return x509Certs, nil
|
return x509Certs, nil
|
||||||
|
@ -105,37 +106,38 @@ func getRootCAs(certsCAsDir string) (*x509.CertPool, error) {
|
||||||
func loadX509KeyPair(certFile, keyFile string) (tls.Certificate, error) {
|
func loadX509KeyPair(certFile, keyFile string) (tls.Certificate, error) {
|
||||||
certPEMBlock, err := ioutil.ReadFile(certFile)
|
certPEMBlock, err := ioutil.ReadFile(certFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tls.Certificate{}, uiErrSSLUnexpectedError(err)
|
return tls.Certificate{}, config.ErrSSLUnexpectedError(err)
|
||||||
}
|
}
|
||||||
keyPEMBlock, err := ioutil.ReadFile(keyFile)
|
keyPEMBlock, err := ioutil.ReadFile(keyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tls.Certificate{}, uiErrSSLUnexpectedError(err)
|
return tls.Certificate{}, config.ErrSSLUnexpectedError(err)
|
||||||
}
|
}
|
||||||
key, rest := pem.Decode(keyPEMBlock)
|
key, rest := pem.Decode(keyPEMBlock)
|
||||||
if len(rest) > 0 {
|
if len(rest) > 0 {
|
||||||
return tls.Certificate{}, uiErrSSLUnexpectedData(nil).Msg("The private key contains additional data")
|
return tls.Certificate{}, config.ErrSSLUnexpectedData(nil).Msg("The private key contains additional data")
|
||||||
}
|
}
|
||||||
if x509.IsEncryptedPEMBlock(key) {
|
if x509.IsEncryptedPEMBlock(key) {
|
||||||
password, ok := os.LookupEnv(TLSPrivateKeyPassword)
|
password, ok := env.Lookup(TLSPrivateKeyPassword)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tls.Certificate{}, uiErrSSLNoPassword(nil)
|
return tls.Certificate{}, config.ErrSSLNoPassword(nil)
|
||||||
}
|
}
|
||||||
decryptedKey, decErr := x509.DecryptPEMBlock(key, []byte(password))
|
decryptedKey, decErr := x509.DecryptPEMBlock(key, []byte(password))
|
||||||
if decErr != nil {
|
if decErr != nil {
|
||||||
return tls.Certificate{}, uiErrSSLWrongPassword(decErr)
|
return tls.Certificate{}, config.ErrSSLWrongPassword(decErr)
|
||||||
}
|
}
|
||||||
keyPEMBlock = pem.EncodeToMemory(&pem.Block{Type: key.Type, Bytes: decryptedKey})
|
keyPEMBlock = pem.EncodeToMemory(&pem.Block{Type: key.Type, Bytes: decryptedKey})
|
||||||
}
|
}
|
||||||
cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
|
cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tls.Certificate{}, uiErrSSLUnexpectedData(nil).Msg(err.Error())
|
return tls.Certificate{}, config.ErrSSLUnexpectedData(nil).Msg(err.Error())
|
||||||
}
|
}
|
||||||
// Ensure that the private key is not a P-384 or P-521 EC key.
|
// Ensure that the private key is not a P-384 or P-521 EC key.
|
||||||
// The Go TLS stack does not provide constant-time implementations of P-384 and P-521.
|
// The Go TLS stack does not provide constant-time implementations of P-384 and P-521.
|
||||||
if priv, ok := cert.PrivateKey.(crypto.Signer); ok {
|
if priv, ok := cert.PrivateKey.(crypto.Signer); ok {
|
||||||
if pub, ok := priv.Public().(*ecdsa.PublicKey); ok {
|
if pub, ok := priv.Public().(*ecdsa.PublicKey); ok {
|
||||||
if name := pub.Params().Name; name == "P-384" || name == "P-521" { // unfortunately there is no cleaner way to check
|
if name := pub.Params().Name; name == "P-384" || name == "P-521" {
|
||||||
return tls.Certificate{}, uiErrSSLUnexpectedData(nil).Msg("tls: the ECDSA curve '%s' is not supported", name)
|
// unfortunately there is no cleaner way to check
|
||||||
|
return tls.Certificate{}, config.ErrSSLUnexpectedData(nil).Msg("tls: the ECDSA curve '%s' is not supported", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -30,10 +29,12 @@ import (
|
||||||
dns2 "github.com/miekg/dns"
|
dns2 "github.com/miekg/dns"
|
||||||
"github.com/minio/cli"
|
"github.com/minio/cli"
|
||||||
"github.com/minio/minio-go/v6/pkg/set"
|
"github.com/minio/minio-go/v6/pkg/set"
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/cmd/logger/target/http"
|
"github.com/minio/minio/cmd/logger/target/http"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
"github.com/minio/minio/pkg/dns"
|
"github.com/minio/minio/pkg/dns"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
xnet "github.com/minio/minio/pkg/net"
|
xnet "github.com/minio/minio/pkg/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ func verifyObjectLayerFeatures(name string, objAPI ObjectLayer) {
|
||||||
|
|
||||||
if strings.HasPrefix(name, "gateway") {
|
if strings.HasPrefix(name, "gateway") {
|
||||||
if GlobalGatewaySSE.IsSet() && GlobalKMS == nil {
|
if GlobalGatewaySSE.IsSet() && GlobalKMS == nil {
|
||||||
uiErr := uiErrInvalidGWSSEEnvValue(nil).Msg("MINIO_GATEWAY_SSE set but KMS is not configured")
|
uiErr := config.ErrInvalidGWSSEEnvValue(nil).Msg("MINIO_GATEWAY_SSE set but KMS is not configured")
|
||||||
logger.Fatal(uiErr, "Unable to start gateway with SSE")
|
logger.Fatal(uiErr, "Unable to start gateway with SSE")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,13 +76,13 @@ func checkUpdate(mode string) {
|
||||||
func loadLoggers() {
|
func loadLoggers() {
|
||||||
loggerUserAgent := getUserAgent(getMinioMode())
|
loggerUserAgent := getUserAgent(getMinioMode())
|
||||||
|
|
||||||
auditEndpoint, ok := os.LookupEnv("MINIO_AUDIT_LOGGER_HTTP_ENDPOINT")
|
auditEndpoint, ok := env.Lookup("MINIO_AUDIT_LOGGER_HTTP_ENDPOINT")
|
||||||
if ok {
|
if ok {
|
||||||
// Enable audit HTTP logging through ENV.
|
// Enable audit HTTP logging through ENV.
|
||||||
logger.AddAuditTarget(http.New(auditEndpoint, loggerUserAgent, NewCustomHTTPTransport()))
|
logger.AddAuditTarget(http.New(auditEndpoint, loggerUserAgent, NewCustomHTTPTransport()))
|
||||||
}
|
}
|
||||||
|
|
||||||
loggerEndpoint, ok := os.LookupEnv("MINIO_LOGGER_HTTP_ENDPOINT")
|
loggerEndpoint, ok := env.Lookup("MINIO_LOGGER_HTTP_ENDPOINT")
|
||||||
if ok {
|
if ok {
|
||||||
// Enable HTTP logging through ENV.
|
// Enable HTTP logging through ENV.
|
||||||
logger.AddTarget(http.New(loggerEndpoint, loggerUserAgent, NewCustomHTTPTransport()))
|
logger.AddTarget(http.New(loggerEndpoint, loggerUserAgent, NewCustomHTTPTransport()))
|
||||||
|
@ -189,31 +190,20 @@ func handleCommonCmdArgs(ctx *cli.Context) {
|
||||||
globalCLIContext.StrictS3Compat = ctx.IsSet("compat") || ctx.GlobalIsSet("compat")
|
globalCLIContext.StrictS3Compat = ctx.IsSet("compat") || ctx.GlobalIsSet("compat")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses the given compression exclude list `extensions` or `content-types`.
|
|
||||||
func parseCompressIncludes(includes []string) ([]string, error) {
|
|
||||||
for _, e := range includes {
|
|
||||||
if len(e) == 0 {
|
|
||||||
return nil, uiErrInvalidCompressionIncludesValue(nil).Msg("extension/mime-type (%s) cannot be empty", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return includes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleCommonEnvVars() {
|
func handleCommonEnvVars() {
|
||||||
compressEnvDelimiter := ","
|
|
||||||
// Start profiler if env is set.
|
// Start profiler if env is set.
|
||||||
if profiler := os.Getenv("_MINIO_PROFILER"); profiler != "" {
|
if profiler := env.Get("_MINIO_PROFILER", ""); profiler != "" {
|
||||||
var err error
|
var err error
|
||||||
globalProfiler, err = startProfiler(profiler, "")
|
globalProfiler, err = startProfiler(profiler, "")
|
||||||
logger.FatalIf(err, "Unable to setup a profiler")
|
logger.FatalIf(err, "Unable to setup a profiler")
|
||||||
}
|
}
|
||||||
|
|
||||||
accessKey := os.Getenv("MINIO_ACCESS_KEY")
|
accessKey := env.Get("MINIO_ACCESS_KEY", "")
|
||||||
secretKey := os.Getenv("MINIO_SECRET_KEY")
|
secretKey := env.Get("MINIO_SECRET_KEY", "")
|
||||||
if accessKey != "" && secretKey != "" {
|
if accessKey != "" && secretKey != "" {
|
||||||
cred, err := auth.CreateCredentials(accessKey, secretKey)
|
cred, err := auth.CreateCredentials(accessKey, secretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(uiErrInvalidCredentials(err), "Unable to validate credentials inherited from the shell environment")
|
logger.Fatal(config.ErrInvalidCredentials(err), "Unable to validate credentials inherited from the shell environment")
|
||||||
}
|
}
|
||||||
cred.Expiration = timeSentinel
|
cred.Expiration = timeSentinel
|
||||||
|
|
||||||
|
@ -222,10 +212,10 @@ func handleCommonEnvVars() {
|
||||||
globalActiveCred = cred
|
globalActiveCred = cred
|
||||||
}
|
}
|
||||||
|
|
||||||
if browser := os.Getenv("MINIO_BROWSER"); browser != "" {
|
if browser := env.Get("MINIO_BROWSER", "on"); browser != "" {
|
||||||
browserFlag, err := ParseBoolFlag(browser)
|
browserFlag, err := ParseBoolFlag(browser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(uiErrInvalidBrowserValue(nil).Msg("Unknown value `%s`", browser), "Invalid MINIO_BROWSER value in environment variable")
|
logger.Fatal(config.ErrInvalidBrowserValue(nil).Msg("Unknown value `%s`", browser), "Invalid MINIO_BROWSER value in environment variable")
|
||||||
}
|
}
|
||||||
|
|
||||||
// browser Envs are set globally, this does not represent
|
// browser Envs are set globally, this does not represent
|
||||||
|
@ -234,7 +224,7 @@ func handleCommonEnvVars() {
|
||||||
globalIsBrowserEnabled = bool(browserFlag)
|
globalIsBrowserEnabled = bool(browserFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdEndpointsEnv, ok := os.LookupEnv("MINIO_ETCD_ENDPOINTS")
|
etcdEndpointsEnv, ok := env.Lookup("MINIO_ETCD_ENDPOINTS")
|
||||||
if ok {
|
if ok {
|
||||||
etcdEndpoints := strings.Split(etcdEndpointsEnv, ",")
|
etcdEndpoints := strings.Split(etcdEndpointsEnv, ",")
|
||||||
|
|
||||||
|
@ -252,8 +242,8 @@ func handleCommonEnvVars() {
|
||||||
if etcdSecure {
|
if etcdSecure {
|
||||||
// This is only to support client side certificate authentication
|
// This is only to support client side certificate authentication
|
||||||
// https://coreos.com/etcd/docs/latest/op-guide/security.html
|
// https://coreos.com/etcd/docs/latest/op-guide/security.html
|
||||||
etcdClientCertFile, ok1 := os.LookupEnv("MINIO_ETCD_CLIENT_CERT")
|
etcdClientCertFile, ok1 := env.Lookup("MINIO_ETCD_CLIENT_CERT")
|
||||||
etcdClientCertKey, ok2 := os.LookupEnv("MINIO_ETCD_CLIENT_CERT_KEY")
|
etcdClientCertKey, ok2 := env.Lookup("MINIO_ETCD_CLIENT_CERT_KEY")
|
||||||
var getClientCertificate func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
|
var getClientCertificate func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
|
||||||
if ok1 && ok2 {
|
if ok1 && ok2 {
|
||||||
getClientCertificate = func(unused *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
getClientCertificate = func(unused *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||||
|
@ -281,18 +271,18 @@ func handleCommonEnvVars() {
|
||||||
logger.FatalIf(err, "Unable to initialize etcd with %s", etcdEndpoints)
|
logger.FatalIf(err, "Unable to initialize etcd with %s", etcdEndpoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
v, ok := os.LookupEnv("MINIO_DOMAIN")
|
v, ok := env.Lookup("MINIO_DOMAIN")
|
||||||
if ok {
|
if ok {
|
||||||
for _, domainName := range strings.Split(v, ",") {
|
for _, domainName := range strings.Split(v, ",") {
|
||||||
if _, ok = dns2.IsDomainName(domainName); !ok {
|
if _, ok = dns2.IsDomainName(domainName); !ok {
|
||||||
logger.Fatal(uiErrInvalidDomainValue(nil).Msg("Unknown value `%s`", domainName),
|
logger.Fatal(config.ErrInvalidDomainValue(nil).Msg("Unknown value `%s`", domainName),
|
||||||
"Invalid MINIO_DOMAIN value in environment variable")
|
"Invalid MINIO_DOMAIN value in environment variable")
|
||||||
}
|
}
|
||||||
globalDomainNames = append(globalDomainNames, domainName)
|
globalDomainNames = append(globalDomainNames, domainName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
minioEndpointsEnv, ok := os.LookupEnv("MINIO_PUBLIC_IPS")
|
minioEndpointsEnv, ok := env.Lookup("MINIO_PUBLIC_IPS")
|
||||||
if ok {
|
if ok {
|
||||||
minioEndpoints := strings.Split(minioEndpointsEnv, ",")
|
minioEndpoints := strings.Split(minioEndpointsEnv, ",")
|
||||||
var domainIPs = set.NewStringSet()
|
var domainIPs = set.NewStringSet()
|
||||||
|
@ -323,53 +313,10 @@ func handleCommonEnvVars() {
|
||||||
logger.FatalIf(err, "Unable to initialize DNS config for %s.", globalDomainNames)
|
logger.FatalIf(err, "Unable to initialize DNS config for %s.", globalDomainNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
if drives := os.Getenv("MINIO_CACHE_DRIVES"); drives != "" {
|
|
||||||
driveList, err := parseCacheDrives(strings.Split(drives, cacheEnvDelimiter))
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err, "Unable to parse MINIO_CACHE_DRIVES value (%s)", drives)
|
|
||||||
}
|
|
||||||
globalCacheDrives = driveList
|
|
||||||
globalIsDiskCacheEnabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if excludes := os.Getenv("MINIO_CACHE_EXCLUDE"); excludes != "" {
|
|
||||||
excludeList, err := parseCacheExcludes(strings.Split(excludes, cacheEnvDelimiter))
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err, "Unable to parse MINIO_CACHE_EXCLUDE value (`%s`)", excludes)
|
|
||||||
}
|
|
||||||
globalCacheExcludes = excludeList
|
|
||||||
}
|
|
||||||
|
|
||||||
if expiryStr := os.Getenv("MINIO_CACHE_EXPIRY"); expiryStr != "" {
|
|
||||||
expiry, err := strconv.Atoi(expiryStr)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(uiErrInvalidCacheExpiryValue(err), "Unable to parse MINIO_CACHE_EXPIRY value (`%s`)", expiryStr)
|
|
||||||
}
|
|
||||||
globalCacheExpiry = expiry
|
|
||||||
}
|
|
||||||
|
|
||||||
if maxUseStr := os.Getenv("MINIO_CACHE_MAXUSE"); maxUseStr != "" {
|
|
||||||
maxUse, err := strconv.Atoi(maxUseStr)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(uiErrInvalidCacheMaxUse(err), "Unable to parse MINIO_CACHE_MAXUSE value (`%s`)", maxUseStr)
|
|
||||||
}
|
|
||||||
// maxUse should be a valid percentage.
|
|
||||||
if maxUse > 0 && maxUse <= 100 {
|
|
||||||
globalCacheMaxUse = maxUse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if cacheEncKey := os.Getenv("MINIO_CACHE_ENCRYPTION_MASTER_KEY"); cacheEncKey != "" {
|
|
||||||
globalCacheKMSKeyID, globalCacheKMS, err = parseKMSMasterKey(cacheEncKey)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(uiErrInvalidCacheEncryptionKey(err), "Invalid cache encryption master key")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// In place update is true by default if the MINIO_UPDATE is not set
|
// In place update is true by default if the MINIO_UPDATE is not set
|
||||||
// or is not set to 'off', if MINIO_UPDATE is set to 'off' then
|
// or is not set to 'off', if MINIO_UPDATE is set to 'off' then
|
||||||
// in-place update is off.
|
// in-place update is off.
|
||||||
globalInplaceUpdateDisabled = strings.EqualFold(os.Getenv("MINIO_UPDATE"), "off")
|
globalInplaceUpdateDisabled = strings.EqualFold(env.Get("MINIO_UPDATE", "off"), "off")
|
||||||
|
|
||||||
// Validate and store the storage class env variables only for XL/Dist XL setups
|
// Validate and store the storage class env variables only for XL/Dist XL setups
|
||||||
if globalIsXL {
|
if globalIsXL {
|
||||||
|
@ -402,10 +349,10 @@ func handleCommonEnvVars() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get WORM environment variable.
|
// Get WORM environment variable.
|
||||||
if worm := os.Getenv("MINIO_WORM"); worm != "" {
|
if worm := env.Get("MINIO_WORM", "off"); worm != "" {
|
||||||
wormFlag, err := ParseBoolFlag(worm)
|
wormFlag, err := ParseBoolFlag(worm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(uiErrInvalidWormValue(nil).Msg("Unknown value `%s`", worm), "Invalid MINIO_WORM value in environment variable")
|
logger.Fatal(config.ErrInvalidWormValue(nil).Msg("Unknown value `%s`", worm), "Invalid MINIO_WORM value in environment variable")
|
||||||
}
|
}
|
||||||
|
|
||||||
// worm Envs are set globally, this does not represent
|
// worm Envs are set globally, this does not represent
|
||||||
|
@ -414,29 +361,6 @@ func handleCommonEnvVars() {
|
||||||
globalWORMEnabled = bool(wormFlag)
|
globalWORMEnabled = bool(wormFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if compress := os.Getenv("MINIO_COMPRESS"); compress != "" {
|
|
||||||
globalIsCompressionEnabled = strings.EqualFold(compress, "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
compressExtensions := os.Getenv("MINIO_COMPRESS_EXTENSIONS")
|
|
||||||
compressMimeTypes := os.Getenv("MINIO_COMPRESS_MIMETYPES")
|
|
||||||
if compressExtensions != "" || compressMimeTypes != "" {
|
|
||||||
globalIsEnvCompression = true
|
|
||||||
if compressExtensions != "" {
|
|
||||||
extensions, err := parseCompressIncludes(strings.Split(compressExtensions, compressEnvDelimiter))
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err, "Invalid MINIO_COMPRESS_EXTENSIONS value (`%s`)", extensions)
|
|
||||||
}
|
|
||||||
globalCompressExtensions = extensions
|
|
||||||
}
|
|
||||||
if compressMimeTypes != "" {
|
|
||||||
contenttypes, err := parseCompressIncludes(strings.Split(compressMimeTypes, compressEnvDelimiter))
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err, "Invalid MINIO_COMPRESS_MIMETYPES value (`%s`)", contenttypes)
|
|
||||||
}
|
|
||||||
globalCompressMimeTypes = contenttypes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func logStartupMessage(msg string, data ...interface{}) {
|
func logStartupMessage(msg string, data ...interface{}) {
|
||||||
|
|
|
@ -20,14 +20,18 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
|
"github.com/minio/minio/cmd/config/cache"
|
||||||
|
"github.com/minio/minio/cmd/config/compress"
|
||||||
|
xldap "github.com/minio/minio/cmd/config/ldap"
|
||||||
"github.com/minio/minio/cmd/crypto"
|
"github.com/minio/minio/cmd/crypto"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
"github.com/minio/minio/pkg/event"
|
"github.com/minio/minio/pkg/event"
|
||||||
"github.com/minio/minio/pkg/event/target"
|
"github.com/minio/minio/pkg/event/target"
|
||||||
"github.com/minio/minio/pkg/iam/openid"
|
"github.com/minio/minio/pkg/iam/openid"
|
||||||
|
@ -134,18 +138,10 @@ func (s *serverConfig) GetWorm() bool {
|
||||||
return bool(s.Worm)
|
return bool(s.Worm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCacheConfig sets the current cache config
|
|
||||||
func (s *serverConfig) SetCacheConfig(drives, exclude []string, expiry int, maxuse int) {
|
|
||||||
s.Cache.Drives = drives
|
|
||||||
s.Cache.Exclude = exclude
|
|
||||||
s.Cache.Expiry = expiry
|
|
||||||
s.Cache.MaxUse = maxuse
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCacheConfig gets the current cache config
|
// GetCacheConfig gets the current cache config
|
||||||
func (s *serverConfig) GetCacheConfig() CacheConfig {
|
func (s *serverConfig) GetCacheConfig() cache.Config {
|
||||||
if globalIsDiskCacheEnabled {
|
if globalIsDiskCacheEnabled {
|
||||||
return CacheConfig{
|
return cache.Config{
|
||||||
Drives: globalCacheDrives,
|
Drives: globalCacheDrives,
|
||||||
Exclude: globalCacheExcludes,
|
Exclude: globalCacheExcludes,
|
||||||
Expiry: globalCacheExpiry,
|
Expiry: globalCacheExpiry,
|
||||||
|
@ -153,7 +149,7 @@ func (s *serverConfig) GetCacheConfig() CacheConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return CacheConfig{}
|
return cache.Config{}
|
||||||
}
|
}
|
||||||
return s.Cache
|
return s.Cache
|
||||||
}
|
}
|
||||||
|
@ -246,7 +242,7 @@ func (s *serverConfig) SetCompressionConfig(extensions []string, mimeTypes []str
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCompressionConfig gets the current compression config
|
// GetCompressionConfig gets the current compression config
|
||||||
func (s *serverConfig) GetCompressionConfig() compressionConfig {
|
func (s *serverConfig) GetCompressionConfig() compress.Config {
|
||||||
return s.Compression
|
return s.Compression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,19 +264,39 @@ func (s *serverConfig) loadFromEnvs() {
|
||||||
s.SetStorageClass(globalStandardStorageClass, globalRRStorageClass)
|
s.SetStorageClass(globalStandardStorageClass, globalRRStorageClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalIsDiskCacheEnabled {
|
var err error
|
||||||
s.SetCacheConfig(globalCacheDrives, globalCacheExcludes, globalCacheExpiry, globalCacheMaxUse)
|
s.Cache, err = cache.LookupConfig(s.Cache)
|
||||||
|
if err != nil {
|
||||||
|
logger.FatalIf(err, "Unable to setup cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := Environment.LookupKMSConfig(s.KMS); err != nil {
|
if len(s.Cache.Drives) > 0 {
|
||||||
logger.FatalIf(err, "Unable to setup the KMS")
|
globalIsDiskCacheEnabled = true
|
||||||
|
globalCacheDrives = s.Cache.Drives
|
||||||
|
globalCacheExcludes = s.Cache.Exclude
|
||||||
|
globalCacheExpiry = s.Cache.Expiry
|
||||||
|
globalCacheMaxUse = s.Cache.MaxUse
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if cacheEncKey := env.Get(cache.EnvCacheEncryptionMasterKey, ""); cacheEncKey != "" {
|
||||||
|
globalCacheKMSKeyID, globalCacheKMS, err = parseKMSMasterKey(cacheEncKey)
|
||||||
|
if err != nil {
|
||||||
|
logger.FatalIf(config.ErrInvalidCacheEncryptionKey(err),
|
||||||
|
"Unable to setup encryption cache")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalIsEnvCompression {
|
if err = LookupKMSConfig(s.KMS); err != nil {
|
||||||
s.SetCompressionConfig(globalCompressExtensions, globalCompressMimeTypes)
|
logger.FatalIf(err, "Unable to setup KMS")
|
||||||
}
|
}
|
||||||
|
|
||||||
if jwksURL, ok := os.LookupEnv("MINIO_IAM_JWKS_URL"); ok {
|
s.Compression, err = compress.LookupConfig(s.Compression)
|
||||||
|
if err != nil {
|
||||||
|
logger.FatalIf(err, "Unable to setup Compression")
|
||||||
|
}
|
||||||
|
|
||||||
|
if jwksURL, ok := env.Lookup("MINIO_IAM_JWKS_URL"); ok {
|
||||||
u, err := xnet.ParseURL(jwksURL)
|
u, err := xnet.ParseURL(jwksURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.FatalIf(err, "Unable to parse MINIO_IAM_JWKS_URL %s", jwksURL)
|
logger.FatalIf(err, "Unable to parse MINIO_IAM_JWKS_URL %s", jwksURL)
|
||||||
|
@ -288,14 +304,14 @@ func (s *serverConfig) loadFromEnvs() {
|
||||||
s.OpenID.JWKS.URL = u
|
s.OpenID.JWKS.URL = u
|
||||||
}
|
}
|
||||||
|
|
||||||
if opaURL, ok := os.LookupEnv("MINIO_IAM_OPA_URL"); ok {
|
if opaURL, ok := env.Lookup("MINIO_IAM_OPA_URL"); ok {
|
||||||
u, err := xnet.ParseURL(opaURL)
|
u, err := xnet.ParseURL(opaURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.FatalIf(err, "Unable to parse MINIO_IAM_OPA_URL %s", opaURL)
|
logger.FatalIf(err, "Unable to parse MINIO_IAM_OPA_URL %s", opaURL)
|
||||||
}
|
}
|
||||||
opaArgs := iampolicy.OpaArgs{
|
opaArgs := iampolicy.OpaArgs{
|
||||||
URL: u,
|
URL: u,
|
||||||
AuthToken: os.Getenv("MINIO_IAM_OPA_AUTHTOKEN"),
|
AuthToken: env.Get("MINIO_IAM_OPA_AUTHTOKEN", ""),
|
||||||
Transport: NewCustomHTTPTransport(),
|
Transport: NewCustomHTTPTransport(),
|
||||||
CloseRespFn: xhttp.DrainBody,
|
CloseRespFn: xhttp.DrainBody,
|
||||||
}
|
}
|
||||||
|
@ -304,8 +320,7 @@ func (s *serverConfig) loadFromEnvs() {
|
||||||
s.Policy.OPA.AuthToken = opaArgs.AuthToken
|
s.Policy.OPA.AuthToken = opaArgs.AuthToken
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
s.LDAPServerConfig, err = xldap.Lookup(s.LDAPServerConfig, globalRootCAs)
|
||||||
s.LDAPServerConfig, err = newLDAPConfigFromEnv(globalRootCAs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.FatalIf(err, "Unable to parse LDAP configuration from env")
|
logger.FatalIf(err, "Unable to parse LDAP configuration from env")
|
||||||
}
|
}
|
||||||
|
@ -484,7 +499,7 @@ func newServerConfig() *serverConfig {
|
||||||
Standard: storageClass{},
|
Standard: storageClass{},
|
||||||
RRS: storageClass{},
|
RRS: storageClass{},
|
||||||
},
|
},
|
||||||
Cache: CacheConfig{
|
Cache: cache.Config{
|
||||||
Drives: []string{},
|
Drives: []string{},
|
||||||
Exclude: []string{},
|
Exclude: []string{},
|
||||||
Expiry: globalCacheExpiry,
|
Expiry: globalCacheExpiry,
|
||||||
|
@ -492,7 +507,7 @@ func newServerConfig() *serverConfig {
|
||||||
},
|
},
|
||||||
KMS: crypto.KMSConfig{},
|
KMS: crypto.KMSConfig{},
|
||||||
Notify: notifier{},
|
Notify: notifier{},
|
||||||
Compression: compressionConfig{
|
Compression: compress.Config{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Extensions: globalCompressExtensions,
|
Extensions: globalCompressExtensions,
|
||||||
MimeTypes: globalCompressMimeTypes,
|
MimeTypes: globalCompressMimeTypes,
|
||||||
|
@ -555,7 +570,7 @@ func (s *serverConfig) loadToCachedConfigs() {
|
||||||
globalCacheExpiry = cacheConf.Expiry
|
globalCacheExpiry = cacheConf.Expiry
|
||||||
globalCacheMaxUse = cacheConf.MaxUse
|
globalCacheMaxUse = cacheConf.MaxUse
|
||||||
}
|
}
|
||||||
if err := Environment.LookupKMSConfig(s.KMS); err != nil {
|
if err := LookupKMSConfig(s.KMS); err != nil {
|
||||||
logger.FatalIf(err, "Unable to setup the KMS %s", s.KMS.Vault.Endpoint)
|
logger.FatalIf(err, "Unable to setup the KMS %s", s.KMS.Vault.Endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,7 +586,7 @@ func (s *serverConfig) loadToCachedConfigs() {
|
||||||
"Unable to populate public key from JWKS URL %s", s.OpenID.JWKS.URL)
|
"Unable to populate public key from JWKS URL %s", s.OpenID.JWKS.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
globalIAMValidators = getOpenIDValidators(s)
|
globalOpenIDValidators = getOpenIDValidators(s)
|
||||||
|
|
||||||
if s.Policy.OPA.URL != nil && s.Policy.OPA.URL.String() != "" {
|
if s.Policy.OPA.URL != nil && s.Policy.OPA.URL.String() != "" {
|
||||||
opaArgs := iampolicy.OpaArgs{
|
opaArgs := iampolicy.OpaArgs{
|
||||||
|
@ -621,7 +636,7 @@ func getValidConfig(objAPI ObjectLayer) (*serverConfig, error) {
|
||||||
func loadConfig(objAPI ObjectLayer) error {
|
func loadConfig(objAPI ObjectLayer) error {
|
||||||
srvCfg, err := getValidConfig(objAPI)
|
srvCfg, err := getValidConfig(objAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uiErrInvalidConfig(nil).Msg(err.Error())
|
return config.ErrInvalidConfig(nil).Msg(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override any values from ENVs.
|
// Override any values from ENVs.
|
||||||
|
|
|
@ -19,6 +19,9 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config/cache"
|
||||||
|
"github.com/minio/minio/cmd/config/compress"
|
||||||
|
xldap "github.com/minio/minio/cmd/config/ldap"
|
||||||
"github.com/minio/minio/cmd/crypto"
|
"github.com/minio/minio/cmd/crypto"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
"github.com/minio/minio/pkg/event/target"
|
"github.com/minio/minio/pkg/event/target"
|
||||||
|
@ -592,7 +595,7 @@ type serverConfigV23 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// Notification queue configuration.
|
// Notification queue configuration.
|
||||||
Notify notifierV3 `json:"notify"`
|
Notify notifierV3 `json:"notify"`
|
||||||
|
@ -616,7 +619,7 @@ type serverConfigV24 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// Notification queue configuration.
|
// Notification queue configuration.
|
||||||
Notify notifierV3 `json:"notify"`
|
Notify notifierV3 `json:"notify"`
|
||||||
|
@ -643,14 +646,14 @@ type serverConfigV25 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// Notification queue configuration.
|
// Notification queue configuration.
|
||||||
Notify notifierV3 `json:"notify"`
|
Notify notifierV3 `json:"notify"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverConfigV26 is just like version '25', stores additionally
|
// serverConfigV26 is just like version '25', stores additionally
|
||||||
// cache max use value in 'CacheConfig'.
|
// cache max use value in 'cache.Config'.
|
||||||
type serverConfigV26 struct {
|
type serverConfigV26 struct {
|
||||||
quick.Config `json:"-"` // ignore interfaces
|
quick.Config `json:"-"` // ignore interfaces
|
||||||
|
|
||||||
|
@ -667,7 +670,7 @@ type serverConfigV26 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// Notification queue configuration.
|
// Notification queue configuration.
|
||||||
Notify notifierV3 `json:"notify"`
|
Notify notifierV3 `json:"notify"`
|
||||||
|
@ -708,7 +711,7 @@ type serverConfigV27 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// Notification queue configuration.
|
// Notification queue configuration.
|
||||||
Notify notifierV3 `json:"notify"`
|
Notify notifierV3 `json:"notify"`
|
||||||
|
@ -736,7 +739,7 @@ type serverConfigV28 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// KMS configuration
|
// KMS configuration
|
||||||
KMS crypto.KMSConfig `json:"kms"`
|
KMS crypto.KMSConfig `json:"kms"`
|
||||||
|
@ -751,13 +754,6 @@ type serverConfigV28 struct {
|
||||||
// serverConfigV29 is just like version '28'.
|
// serverConfigV29 is just like version '28'.
|
||||||
type serverConfigV29 serverConfigV28
|
type serverConfigV29 serverConfigV28
|
||||||
|
|
||||||
// compressionConfig represents the compression settings.
|
|
||||||
type compressionConfig struct {
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
Extensions []string `json:"extensions"`
|
|
||||||
MimeTypes []string `json:"mime-types"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// serverConfigV30 is just like version '29', stores additionally
|
// serverConfigV30 is just like version '29', stores additionally
|
||||||
// extensions and mimetypes fields for compression.
|
// extensions and mimetypes fields for compression.
|
||||||
type serverConfigV30 struct {
|
type serverConfigV30 struct {
|
||||||
|
@ -772,7 +768,7 @@ type serverConfigV30 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// KMS configuration
|
// KMS configuration
|
||||||
KMS crypto.KMSConfig `json:"kms"`
|
KMS crypto.KMSConfig `json:"kms"`
|
||||||
|
@ -784,7 +780,7 @@ type serverConfigV30 struct {
|
||||||
Logger loggerConfig `json:"logger"`
|
Logger loggerConfig `json:"logger"`
|
||||||
|
|
||||||
// Compression configuration
|
// Compression configuration
|
||||||
Compression compressionConfig `json:"compress"`
|
Compression compress.Config `json:"compress"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverConfigV31 is just like version '30', with OPA and OpenID configuration.
|
// serverConfigV31 is just like version '30', with OPA and OpenID configuration.
|
||||||
|
@ -800,7 +796,7 @@ type serverConfigV31 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// KMS configuration
|
// KMS configuration
|
||||||
KMS crypto.KMSConfig `json:"kms"`
|
KMS crypto.KMSConfig `json:"kms"`
|
||||||
|
@ -812,7 +808,7 @@ type serverConfigV31 struct {
|
||||||
Logger loggerConfig `json:"logger"`
|
Logger loggerConfig `json:"logger"`
|
||||||
|
|
||||||
// Compression configuration
|
// Compression configuration
|
||||||
Compression compressionConfig `json:"compress"`
|
Compression compress.Config `json:"compress"`
|
||||||
|
|
||||||
// OpenID configuration
|
// OpenID configuration
|
||||||
OpenID struct {
|
OpenID struct {
|
||||||
|
@ -855,7 +851,7 @@ type serverConfigV32 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// KMS configuration
|
// KMS configuration
|
||||||
KMS crypto.KMSConfig `json:"kms"`
|
KMS crypto.KMSConfig `json:"kms"`
|
||||||
|
@ -867,7 +863,7 @@ type serverConfigV32 struct {
|
||||||
Logger loggerConfig `json:"logger"`
|
Logger loggerConfig `json:"logger"`
|
||||||
|
|
||||||
// Compression configuration
|
// Compression configuration
|
||||||
Compression compressionConfig `json:"compress"`
|
Compression compress.Config `json:"compress"`
|
||||||
|
|
||||||
// OpenID configuration
|
// OpenID configuration
|
||||||
OpenID struct {
|
OpenID struct {
|
||||||
|
@ -899,7 +895,7 @@ type serverConfigV33 struct {
|
||||||
StorageClass storageClassConfig `json:"storageclass"`
|
StorageClass storageClassConfig `json:"storageclass"`
|
||||||
|
|
||||||
// Cache configuration
|
// Cache configuration
|
||||||
Cache CacheConfig `json:"cache"`
|
Cache cache.Config `json:"cache"`
|
||||||
|
|
||||||
// KMS configuration
|
// KMS configuration
|
||||||
KMS crypto.KMSConfig `json:"kms"`
|
KMS crypto.KMSConfig `json:"kms"`
|
||||||
|
@ -911,7 +907,7 @@ type serverConfigV33 struct {
|
||||||
Logger loggerConfig `json:"logger"`
|
Logger loggerConfig `json:"logger"`
|
||||||
|
|
||||||
// Compression configuration
|
// Compression configuration
|
||||||
Compression compressionConfig `json:"compress"`
|
Compression compress.Config `json:"compress"`
|
||||||
|
|
||||||
// OpenID configuration
|
// OpenID configuration
|
||||||
OpenID struct {
|
OpenID struct {
|
||||||
|
@ -927,5 +923,5 @@ type serverConfigV33 struct {
|
||||||
// Add new external policy enforcements here.
|
// Add new external policy enforcements here.
|
||||||
} `json:"policy"`
|
} `json:"policy"`
|
||||||
|
|
||||||
LDAPServerConfig ldapServerConfig `json:"ldapserverconfig"`
|
LDAPServerConfig xldap.Config `json:"ldapserverconfig"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* MinIO Cloud Storage, (C) 2018 MinIO, Inc.
|
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cmd
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -22,11 +22,12 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
"github.com/minio/minio/pkg/ellipses"
|
"github.com/minio/minio/pkg/ellipses"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CacheConfig represents cache config settings
|
// Config represents cache config settings
|
||||||
type CacheConfig struct {
|
type Config struct {
|
||||||
Drives []string `json:"drives"`
|
Drives []string `json:"drives"`
|
||||||
Expiry int `json:"expiry"`
|
Expiry int `json:"expiry"`
|
||||||
MaxUse int `json:"maxuse"`
|
MaxUse int `json:"maxuse"`
|
||||||
|
@ -35,8 +36,8 @@ type CacheConfig struct {
|
||||||
|
|
||||||
// UnmarshalJSON - implements JSON unmarshal interface for unmarshalling
|
// UnmarshalJSON - implements JSON unmarshal interface for unmarshalling
|
||||||
// json entries for CacheConfig.
|
// json entries for CacheConfig.
|
||||||
func (cfg *CacheConfig) UnmarshalJSON(data []byte) (err error) {
|
func (cfg *Config) UnmarshalJSON(data []byte) (err error) {
|
||||||
type Alias CacheConfig
|
type Alias Config
|
||||||
var _cfg = &struct {
|
var _cfg = &struct {
|
||||||
*Alias
|
*Alias
|
||||||
}{
|
}{
|
||||||
|
@ -83,7 +84,7 @@ func parseCacheDrives(drives []string) ([]string, error) {
|
||||||
|
|
||||||
for _, d := range endpoints {
|
for _, d := range endpoints {
|
||||||
if !filepath.IsAbs(d) {
|
if !filepath.IsAbs(d) {
|
||||||
return nil, uiErrInvalidCacheDrivesValue(nil).Msg("cache dir should be absolute path: %s", d)
|
return nil, config.ErrInvalidCacheDrivesValue(nil).Msg("cache dir should be absolute path: %s", d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return endpoints, nil
|
return endpoints, nil
|
||||||
|
@ -93,7 +94,7 @@ func parseCacheDrives(drives []string) ([]string, error) {
|
||||||
func parseCacheDrivePaths(arg string) (ep []string, err error) {
|
func parseCacheDrivePaths(arg string) (ep []string, err error) {
|
||||||
patterns, perr := ellipses.FindEllipsesPatterns(arg)
|
patterns, perr := ellipses.FindEllipsesPatterns(arg)
|
||||||
if perr != nil {
|
if perr != nil {
|
||||||
return []string{}, uiErrInvalidCacheDrivesValue(nil).Msg(perr.Error())
|
return []string{}, config.ErrInvalidCacheDrivesValue(nil).Msg(perr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, lbls := range patterns.Expand() {
|
for _, lbls := range patterns.Expand() {
|
||||||
|
@ -107,10 +108,10 @@ func parseCacheDrivePaths(arg string) (ep []string, err error) {
|
||||||
func parseCacheExcludes(excludes []string) ([]string, error) {
|
func parseCacheExcludes(excludes []string) ([]string, error) {
|
||||||
for _, e := range excludes {
|
for _, e := range excludes {
|
||||||
if len(e) == 0 {
|
if len(e) == 0 {
|
||||||
return nil, uiErrInvalidCacheExcludesValue(nil).Msg("cache exclude path (%s) cannot be empty", e)
|
return nil, config.ErrInvalidCacheExcludesValue(nil).Msg("cache exclude path (%s) cannot be empty", e)
|
||||||
}
|
}
|
||||||
if hasPrefix(e, SlashSeparator) {
|
if strings.HasPrefix(e, "/") {
|
||||||
return nil, uiErrInvalidCacheExcludesValue(nil).Msg("cache exclude pattern (%s) cannot start with / as prefix", e)
|
return nil, config.ErrInvalidCacheExcludesValue(nil).Msg("cache exclude pattern (%s) cannot start with / as prefix", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return excludes, nil
|
return excludes, nil
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* MinIO Cloud Storage, (C) 2018 MinIO, Inc.
|
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cmd
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -35,7 +35,7 @@ func TestParseCacheDrives(t *testing.T) {
|
||||||
{"bucket1/*;*.png;images/trip/barcelona/*", []string{}, false},
|
{"bucket1/*;*.png;images/trip/barcelona/*", []string{}, false},
|
||||||
{"bucket1", []string{}, false},
|
{"bucket1", []string{}, false},
|
||||||
}
|
}
|
||||||
if runtime.GOOS == globalWindowsOSName {
|
if runtime.GOOS == "windows" {
|
||||||
testCases = append(testCases, struct {
|
testCases = append(testCases, struct {
|
||||||
driveStr string
|
driveStr string
|
||||||
expectedPatterns []string
|
expectedPatterns []string
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cache ENVs
|
||||||
|
const (
|
||||||
|
EnvCacheDrives = "MINIO_CACHE_DRIVES"
|
||||||
|
EnvCacheExclude = "MINIO_CACHE_EXCLUDE"
|
||||||
|
EnvCacheExpiry = "MINIO_CACHE_EXPIRY"
|
||||||
|
EnvCacheMaxUse = "MINIO_CACHE_MAXUSE"
|
||||||
|
EnvCacheEncryptionMasterKey = "MINIO_CACHE_ENCRYPTION_MASTER_KEY"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cacheEnvDelimiter = ";"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LookupConfig - extracts cache configuration provided by environment
|
||||||
|
// variables and merge them with provided CacheConfiguration.
|
||||||
|
func LookupConfig(cfg Config) (Config, error) {
|
||||||
|
if drives := env.Get(EnvCacheDrives, strings.Join(cfg.Drives, ",")); drives != "" {
|
||||||
|
driveList, err := parseCacheDrives(strings.Split(drives, cacheEnvDelimiter))
|
||||||
|
if err != nil {
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
|
cfg.Drives = driveList
|
||||||
|
}
|
||||||
|
|
||||||
|
if excludes := env.Get(EnvCacheExclude, strings.Join(cfg.Exclude, ",")); excludes != "" {
|
||||||
|
excludeList, err := parseCacheExcludes(strings.Split(excludes, cacheEnvDelimiter))
|
||||||
|
if err != nil {
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
|
cfg.Exclude = excludeList
|
||||||
|
}
|
||||||
|
|
||||||
|
if expiryStr := env.Get(EnvCacheExpiry, strconv.Itoa(cfg.Expiry)); expiryStr != "" {
|
||||||
|
expiry, err := strconv.Atoi(expiryStr)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, config.ErrInvalidCacheExpiryValue(err)
|
||||||
|
}
|
||||||
|
cfg.Expiry = expiry
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxUseStr := env.Get(EnvCacheMaxUse, strconv.Itoa(cfg.MaxUse)); maxUseStr != "" {
|
||||||
|
maxUse, err := strconv.Atoi(maxUseStr)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, config.ErrInvalidCacheMaxUse(err)
|
||||||
|
}
|
||||||
|
// maxUse should be a valid percentage.
|
||||||
|
if maxUse > 0 && maxUse <= 100 {
|
||||||
|
cfg.MaxUse = maxUse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compress
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config represents the compression settings.
|
||||||
|
type Config struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Extensions []string `json:"extensions"`
|
||||||
|
MimeTypes []string `json:"mime-types"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compression environment variables
|
||||||
|
const (
|
||||||
|
EnvMinioCompress = "MINIO_COMPRESS"
|
||||||
|
EnvMinioCompressExtensions = "MINIO_COMPRESS_EXTENSIONS"
|
||||||
|
EnvMinioCompressMimeTypes = "MINIO_COMPRESS_MIMETYPES"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parses the given compression exclude list `extensions` or `content-types`.
|
||||||
|
func parseCompressIncludes(includes []string) ([]string, error) {
|
||||||
|
for _, e := range includes {
|
||||||
|
if len(e) == 0 {
|
||||||
|
return nil, config.ErrInvalidCompressionIncludesValue(nil).Msg("extension/mime-type (%s) cannot be empty", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return includes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupConfig - lookup compression config.
|
||||||
|
func LookupConfig(cfg Config) (Config, error) {
|
||||||
|
const compressEnvDelimiter = ","
|
||||||
|
if compress := env.Get(EnvMinioCompress, strconv.FormatBool(cfg.Enabled)); compress != "" {
|
||||||
|
cfg.Enabled = strings.EqualFold(compress, "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
compressExtensions := env.Get(EnvMinioCompressExtensions, strings.Join(cfg.Extensions, ","))
|
||||||
|
compressMimeTypes := env.Get(EnvMinioCompressMimeTypes, strings.Join(cfg.MimeTypes, ","))
|
||||||
|
if compressExtensions != "" || compressMimeTypes != "" {
|
||||||
|
if compressExtensions != "" {
|
||||||
|
extensions, err := parseCompressIncludes(strings.Split(compressExtensions, compressEnvDelimiter))
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("%s: Invalid MINIO_COMPRESS_EXTENSIONS value (`%s`)", err, extensions)
|
||||||
|
}
|
||||||
|
cfg.Extensions = extensions
|
||||||
|
}
|
||||||
|
if compressMimeTypes != "" {
|
||||||
|
contenttypes, err := parseCompressIncludes(strings.Split(compressMimeTypes, compressEnvDelimiter))
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("%s: Invalid MINIO_COMPRESS_MIMETYPES value (`%s`)", err, contenttypes)
|
||||||
|
}
|
||||||
|
cfg.MimeTypes = contenttypes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cmd
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -22,12 +22,14 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
// uiErr is a structure which contains all information
|
// Err is a structure which contains all information
|
||||||
// to print a fatal error message in json or pretty mode
|
// to print a fatal error message in json or pretty mode
|
||||||
// uiErr implements error so we can use it anywhere
|
// Err implements error so we can use it anywhere
|
||||||
type uiErr struct {
|
type Err struct {
|
||||||
msg string
|
msg string
|
||||||
detail string
|
detail string
|
||||||
action string
|
action string
|
||||||
|
@ -35,16 +37,16 @@ type uiErr struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the error message
|
// Return the error message
|
||||||
func (u uiErr) Error() string {
|
func (u Err) Error() string {
|
||||||
if u.detail == "" {
|
if u.detail == "" {
|
||||||
return u.msg
|
return u.msg
|
||||||
}
|
}
|
||||||
return u.detail
|
return u.detail
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the current error's message
|
// Msg - Replace the current error's message
|
||||||
func (u uiErr) Msg(m string, args ...interface{}) uiErr {
|
func (u Err) Msg(m string, args ...interface{}) Err {
|
||||||
return uiErr{
|
return Err{
|
||||||
msg: fmt.Sprintf(m, args...),
|
msg: fmt.Sprintf(m, args...),
|
||||||
detail: u.detail,
|
detail: u.detail,
|
||||||
action: u.action,
|
action: u.action,
|
||||||
|
@ -52,14 +54,15 @@ func (u uiErr) Msg(m string, args ...interface{}) uiErr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type uiErrFn func(err error) uiErr
|
// ErrFn function wrapper
|
||||||
|
type ErrFn func(err error) Err
|
||||||
|
|
||||||
// Create a UI error generator, this is needed to simplify
|
// Create a UI error generator, this is needed to simplify
|
||||||
// the update of the detailed error message in several places
|
// the update of the detailed error message in several places
|
||||||
// in MinIO code
|
// in MinIO code
|
||||||
func newUIErrFn(msg, action, hint string) uiErrFn {
|
func newErrFn(msg, action, hint string) ErrFn {
|
||||||
return func(err error) uiErr {
|
return func(err error) Err {
|
||||||
u := uiErr{
|
u := Err{
|
||||||
msg: msg,
|
msg: msg,
|
||||||
action: action,
|
action: action,
|
||||||
hint: hint,
|
hint: hint,
|
||||||
|
@ -71,35 +74,35 @@ func newUIErrFn(msg, action, hint string) uiErrFn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// errorToUIError inspects the passed error and transforms it
|
// ErrorToErr inspects the passed error and transforms it
|
||||||
// to the appropriate UI error.
|
// to the appropriate UI error.
|
||||||
func errorToUIErr(err error) uiErr {
|
func ErrorToErr(err error) Err {
|
||||||
// If this is already a uiErr, do nothing
|
// If this is already a Err, do nothing
|
||||||
if e, ok := err.(uiErr); ok {
|
if e, ok := err.(Err); ok {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show a generic message for known golang errors
|
// Show a generic message for known golang errors
|
||||||
if errors.Is(err, syscall.EADDRINUSE) {
|
if errors.Is(err, syscall.EADDRINUSE) {
|
||||||
return uiErrPortAlreadyInUse(err).Msg("Specified port is already in use")
|
return ErrPortAlreadyInUse(err).Msg("Specified port is already in use")
|
||||||
} else if errors.Is(err, syscall.EACCES) {
|
} else if errors.Is(err, syscall.EACCES) {
|
||||||
return uiErrPortAccess(err).Msg("Insufficient permissions to use specified port")
|
return ErrPortAccess(err).Msg("Insufficient permissions to use specified port")
|
||||||
} else if os.IsPermission(err) {
|
} else if os.IsPermission(err) {
|
||||||
return uiErrNoPermissionsToAccessDirFiles(err).Msg("Insufficient permissions to access path")
|
return ErrNoPermissionsToAccessDirFiles(err).Msg("Insufficient permissions to access path")
|
||||||
} else if errors.Is(err, io.ErrUnexpectedEOF) {
|
} else if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||||
return uiErrUnexpectedDataContent(err)
|
return ErrUnexpectedDataContent(err)
|
||||||
} else {
|
} else {
|
||||||
// Failed to identify what type of error this, return a simple UI error
|
// Failed to identify what type of error this, return a simple UI error
|
||||||
return uiErr{msg: err.Error()}
|
return Err{msg: err.Error()}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fmtError() converts a fatal error message to a more clear error
|
// FmtError converts a fatal error message to a more clear error
|
||||||
// using some colors
|
// using some colors
|
||||||
func fmtError(introMsg string, err error, jsonFlag bool) string {
|
func FmtError(introMsg string, err error, jsonFlag bool) string {
|
||||||
renderedTxt := ""
|
renderedTxt := ""
|
||||||
uiErr := errorToUIErr(err)
|
uiErr := ErrorToErr(err)
|
||||||
// JSON print
|
// JSON print
|
||||||
if jsonFlag {
|
if jsonFlag {
|
||||||
// Message text in json should be simple
|
// Message text in json should be simple
|
||||||
|
@ -111,18 +114,18 @@ func fmtError(introMsg string, err error, jsonFlag bool) string {
|
||||||
// Pretty print error message
|
// Pretty print error message
|
||||||
introMsg += ": "
|
introMsg += ": "
|
||||||
if uiErr.msg != "" {
|
if uiErr.msg != "" {
|
||||||
introMsg += colorBold(uiErr.msg)
|
introMsg += color.Bold(uiErr.msg)
|
||||||
} else {
|
} else {
|
||||||
introMsg += colorBold(err.Error())
|
introMsg += color.Bold(err.Error())
|
||||||
}
|
}
|
||||||
renderedTxt += colorRed(introMsg) + "\n"
|
renderedTxt += color.Red(introMsg) + "\n"
|
||||||
// Add action message
|
// Add action message
|
||||||
if uiErr.action != "" {
|
if uiErr.action != "" {
|
||||||
renderedTxt += "> " + colorBgYellow(colorBlack(uiErr.action)) + "\n"
|
renderedTxt += "> " + color.BgYellow(color.Black(uiErr.action)) + "\n"
|
||||||
}
|
}
|
||||||
// Add hint
|
// Add hint
|
||||||
if uiErr.hint != "" {
|
if uiErr.hint != "" {
|
||||||
renderedTxt += colorBold("HINT:") + "\n"
|
renderedTxt += color.Bold("HINT:") + "\n"
|
||||||
renderedTxt += " " + uiErr.hint
|
renderedTxt += " " + uiErr.hint
|
||||||
}
|
}
|
||||||
return renderedTxt
|
return renderedTxt
|
|
@ -14,101 +14,102 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cmd
|
package config
|
||||||
|
|
||||||
|
// UI errors
|
||||||
var (
|
var (
|
||||||
uiErrInvalidConfig = newUIErrFn(
|
ErrInvalidConfig = newErrFn(
|
||||||
"Invalid value found in the configuration file",
|
"Invalid value found in the configuration file",
|
||||||
"Please ensure a valid value in the configuration file",
|
"Please ensure a valid value in the configuration file",
|
||||||
"For more details, refer to https://docs.min.io/docs/minio-server-configuration-guide",
|
"For more details, refer to https://docs.min.io/docs/minio-server-configuration-guide",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidBrowserValue = newUIErrFn(
|
ErrInvalidBrowserValue = newErrFn(
|
||||||
"Invalid browser value",
|
"Invalid browser value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"Browser can only accept `on` and `off` values. To disable web browser access, set this value to `off`",
|
"Browser can only accept `on` and `off` values. To disable web browser access, set this value to `off`",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidDomainValue = newUIErrFn(
|
ErrInvalidDomainValue = newErrFn(
|
||||||
"Invalid domain value",
|
"Invalid domain value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"Domain can only accept DNS compatible values",
|
"Domain can only accept DNS compatible values",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidErasureSetSize = newUIErrFn(
|
ErrInvalidErasureSetSize = newErrFn(
|
||||||
"Invalid erasure set size",
|
"Invalid erasure set size",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"Erasure set can only accept any of [4, 6, 8, 10, 12, 14, 16] values",
|
"Erasure set can only accept any of [4, 6, 8, 10, 12, 14, 16] values",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidWormValue = newUIErrFn(
|
ErrInvalidWormValue = newErrFn(
|
||||||
"Invalid WORM value",
|
"Invalid WORM value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"WORM can only accept `on` and `off` values. To enable WORM, set this value to `on`",
|
"WORM can only accept `on` and `off` values. To enable WORM, set this value to `on`",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidCacheDrivesValue = newUIErrFn(
|
ErrInvalidCacheDrivesValue = newErrFn(
|
||||||
"Invalid cache drive value",
|
"Invalid cache drive value",
|
||||||
"Please check the value in this ENV variable",
|
"Please check the value in this ENV variable",
|
||||||
"MINIO_CACHE_DRIVES: Mounted drives or directories are delimited by `;`",
|
"MINIO_CACHE_DRIVES: Mounted drives or directories are delimited by `;`",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidCacheExcludesValue = newUIErrFn(
|
ErrInvalidCacheExcludesValue = newErrFn(
|
||||||
"Invalid cache excludes value",
|
"Invalid cache excludes value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"MINIO_CACHE_EXCLUDE: Cache exclusion patterns are delimited by `;`",
|
"MINIO_CACHE_EXCLUDE: Cache exclusion patterns are delimited by `;`",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidCacheExpiryValue = newUIErrFn(
|
ErrInvalidCacheExpiryValue = newErrFn(
|
||||||
"Invalid cache expiry value",
|
"Invalid cache expiry value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"MINIO_CACHE_EXPIRY: Valid cache expiry duration is in days",
|
"MINIO_CACHE_EXPIRY: Valid cache expiry duration is in days",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidCacheMaxUse = newUIErrFn(
|
ErrInvalidCacheMaxUse = newErrFn(
|
||||||
"Invalid cache max-use value",
|
"Invalid cache max-use value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"MINIO_CACHE_MAXUSE: Valid cache max-use value between 0-100",
|
"MINIO_CACHE_MAXUSE: Valid cache max-use value between 0-100",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidCacheEncryptionKey = newUIErrFn(
|
ErrInvalidCacheEncryptionKey = newErrFn(
|
||||||
"Invalid cache encryption master key value",
|
"Invalid cache encryption master key value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"MINIO_CACHE_ENCRYPTION_MASTER_KEY: For more information, please refer to https://docs.min.io/docs/minio-disk-cache-guide",
|
"MINIO_CACHE_ENCRYPTION_MASTER_KEY: For more information, please refer to https://docs.min.io/docs/minio-disk-cache-guide",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidCredentials = newUIErrFn(
|
ErrInvalidCredentials = newErrFn(
|
||||||
"Invalid credentials",
|
"Invalid credentials",
|
||||||
"Please provide correct credentials",
|
"Please provide correct credentials",
|
||||||
`Access key length should be between minimum 3 characters in length.
|
`Access key length should be between minimum 3 characters in length.
|
||||||
Secret key should be in between 8 and 40 characters`,
|
Secret key should be in between 8 and 40 characters`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrEnvCredentialsMissingGateway = newUIErrFn(
|
ErrEnvCredentialsMissingGateway = newErrFn(
|
||||||
"Credentials missing",
|
"Credentials missing",
|
||||||
"Please set your credentials in the environment",
|
"Please set your credentials in the environment",
|
||||||
`In Gateway mode, access and secret keys should be specified via environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY respectively`,
|
`In Gateway mode, access and secret keys should be specified via environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY respectively`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrEnvCredentialsMissingDistributed = newUIErrFn(
|
ErrEnvCredentialsMissingDistributed = newErrFn(
|
||||||
"Credentials missing",
|
"Credentials missing",
|
||||||
"Please set your credentials in the environment",
|
"Please set your credentials in the environment",
|
||||||
`In distributed server mode, access and secret keys should be specified via environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY respectively`,
|
`In distributed server mode, access and secret keys should be specified via environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY respectively`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidErasureEndpoints = newUIErrFn(
|
ErrInvalidErasureEndpoints = newErrFn(
|
||||||
"Invalid endpoint(s) in erasure mode",
|
"Invalid endpoint(s) in erasure mode",
|
||||||
"Please provide correct combination of local/remote paths",
|
"Please provide correct combination of local/remote paths",
|
||||||
"For more information, please refer to https://docs.min.io/docs/minio-erasure-code-quickstart-guide",
|
"For more information, please refer to https://docs.min.io/docs/minio-erasure-code-quickstart-guide",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidNumberOfErasureEndpoints = newUIErrFn(
|
ErrInvalidNumberOfErasureEndpoints = newErrFn(
|
||||||
"Invalid total number of endpoints for erasure mode",
|
"Invalid total number of endpoints for erasure mode",
|
||||||
"Please provide an even number of endpoints greater or equal to 4",
|
"Please provide an even number of endpoints greater or equal to 4",
|
||||||
"For more information, please refer to https://docs.min.io/docs/minio-erasure-code-quickstart-guide",
|
"For more information, please refer to https://docs.min.io/docs/minio-erasure-code-quickstart-guide",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrStorageClassValue = newUIErrFn(
|
ErrStorageClassValue = newErrFn(
|
||||||
"Invalid storage class value",
|
"Invalid storage class value",
|
||||||
"Please check the value",
|
"Please check the value",
|
||||||
`MINIO_STORAGE_CLASS_STANDARD: Format "EC:<Default_Parity_Standard_Class>" (e.g. "EC:3"). This sets the number of parity disks for MinIO server in Standard mode. Objects are stored in Standard mode, if storage class is not defined in Put request
|
`MINIO_STORAGE_CLASS_STANDARD: Format "EC:<Default_Parity_Standard_Class>" (e.g. "EC:3"). This sets the number of parity disks for MinIO server in Standard mode. Objects are stored in Standard mode, if storage class is not defined in Put request
|
||||||
|
@ -116,13 +117,13 @@ MINIO_STORAGE_CLASS_RRS: Format "EC:<Default_Parity_Reduced_Redundancy_Class>" (
|
||||||
Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storage-class for more information`,
|
Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storage-class for more information`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrUnexpectedBackendVersion = newUIErrFn(
|
ErrUnexpectedBackendVersion = newErrFn(
|
||||||
"Backend version seems to be too recent",
|
"Backend version seems to be too recent",
|
||||||
"Please update to the latest MinIO version",
|
"Please update to the latest MinIO version",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidAddressFlag = newUIErrFn(
|
ErrInvalidAddressFlag = newErrFn(
|
||||||
"--address input is invalid",
|
"--address input is invalid",
|
||||||
"Please check --address parameter",
|
"Please check --address parameter",
|
||||||
`--address binds to a specific ADDRESS:PORT, ADDRESS can be an IPv4/IPv6 address or hostname (default port is ':9000')
|
`--address binds to a specific ADDRESS:PORT, ADDRESS can be an IPv4/IPv6 address or hostname (default port is ':9000')
|
||||||
|
@ -131,7 +132,7 @@ Refer to the link https://github.com/minio/minio/tree/master/docs/erasure/storag
|
||||||
--address '[fe80::da00:a6c8:e3ae:ddd7]:9000'`,
|
--address '[fe80::da00:a6c8:e3ae:ddd7]:9000'`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidFSEndpoint = newUIErrFn(
|
ErrInvalidFSEndpoint = newErrFn(
|
||||||
"Invalid endpoint for standalone FS mode",
|
"Invalid endpoint for standalone FS mode",
|
||||||
"Please check the FS endpoint",
|
"Please check the FS endpoint",
|
||||||
`FS mode requires only one writable disk path
|
`FS mode requires only one writable disk path
|
||||||
|
@ -139,91 +140,91 @@ Example 1:
|
||||||
$ minio server /data/minio/`,
|
$ minio server /data/minio/`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrUnableToWriteInBackend = newUIErrFn(
|
ErrUnableToWriteInBackend = newErrFn(
|
||||||
"Unable to write to the backend",
|
"Unable to write to the backend",
|
||||||
"Please ensure MinIO binary has write permissions for the backend",
|
"Please ensure MinIO binary has write permissions for the backend",
|
||||||
`Verify if MinIO binary is running as the same user who has write permissions for the backend`,
|
`Verify if MinIO binary is running as the same user who has write permissions for the backend`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrPortAlreadyInUse = newUIErrFn(
|
ErrPortAlreadyInUse = newErrFn(
|
||||||
"Port is already in use",
|
"Port is already in use",
|
||||||
"Please ensure no other program uses the same address/port",
|
"Please ensure no other program uses the same address/port",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrPortAccess = newUIErrFn(
|
ErrPortAccess = newErrFn(
|
||||||
"Unable to use specified port",
|
"Unable to use specified port",
|
||||||
"Please ensure MinIO binary has 'cap_net_bind_service=+ep' permissions",
|
"Please ensure MinIO binary has 'cap_net_bind_service=+ep' permissions",
|
||||||
`Use 'sudo setcap cap_net_bind_service=+ep /path/to/minio' to provide sufficient permissions`,
|
`Use 'sudo setcap cap_net_bind_service=+ep /path/to/minio' to provide sufficient permissions`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrNoPermissionsToAccessDirFiles = newUIErrFn(
|
ErrNoPermissionsToAccessDirFiles = newErrFn(
|
||||||
"Missing permissions to access the specified path",
|
"Missing permissions to access the specified path",
|
||||||
"Please ensure the specified path can be accessed",
|
"Please ensure the specified path can be accessed",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrSSLUnexpectedError = newUIErrFn(
|
ErrSSLUnexpectedError = newErrFn(
|
||||||
"Invalid TLS certificate",
|
"Invalid TLS certificate",
|
||||||
"Please check the content of your certificate data",
|
"Please check the content of your certificate data",
|
||||||
`Only PEM (x.509) format is accepted as valid public & private certificates`,
|
`Only PEM (x.509) format is accepted as valid public & private certificates`,
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrSSLUnexpectedData = newUIErrFn(
|
ErrSSLUnexpectedData = newErrFn(
|
||||||
"Invalid TLS certificate",
|
"Invalid TLS certificate",
|
||||||
"Please check your certificate",
|
"Please check your certificate",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrSSLNoPassword = newUIErrFn(
|
ErrSSLNoPassword = newErrFn(
|
||||||
"Missing TLS password",
|
"Missing TLS password",
|
||||||
"Please set the password to environment variable `"+TLSPrivateKeyPassword+"` so that the private key can be decrypted",
|
"Please set the password to environment variable `MINIO_CERT_PASSWD` so that the private key can be decrypted",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrNoCertsAndHTTPSEndpoints = newUIErrFn(
|
ErrNoCertsAndHTTPSEndpoints = newErrFn(
|
||||||
"HTTPS specified in endpoints, but no TLS certificate is found on the local machine",
|
"HTTPS specified in endpoints, but no TLS certificate is found on the local machine",
|
||||||
"Please add TLS certificate or use HTTP endpoints only",
|
"Please add TLS certificate or use HTTP endpoints only",
|
||||||
"Refer to https://docs.min.io/docs/how-to-secure-access-to-minio-server-with-tls for information about how to load a TLS certificate in your server",
|
"Refer to https://docs.min.io/docs/how-to-secure-access-to-minio-server-with-tls for information about how to load a TLS certificate in your server",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrCertsAndHTTPEndpoints = newUIErrFn(
|
ErrCertsAndHTTPEndpoints = newErrFn(
|
||||||
"HTTP specified in endpoints, but the server in the local machine is configured with a TLS certificate",
|
"HTTP specified in endpoints, but the server in the local machine is configured with a TLS certificate",
|
||||||
"Please remove the certificate in the configuration directory or switch to HTTPS",
|
"Please remove the certificate in the configuration directory or switch to HTTPS",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrSSLWrongPassword = newUIErrFn(
|
ErrSSLWrongPassword = newErrFn(
|
||||||
"Unable to decrypt the private key using the provided password",
|
"Unable to decrypt the private key using the provided password",
|
||||||
"Please set the correct password in environment variable "+TLSPrivateKeyPassword,
|
"Please set the correct password in environment variable `MINIO_CERT_PASSWD`",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrUnexpectedDataContent = newUIErrFn(
|
ErrUnexpectedDataContent = newErrFn(
|
||||||
"Unexpected data content",
|
"Unexpected data content",
|
||||||
"Please contact MinIO at https://slack.min.io",
|
"Please contact MinIO at https://slack.min.io",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrUnexpectedError = newUIErrFn(
|
ErrUnexpectedError = newErrFn(
|
||||||
"Unexpected error",
|
"Unexpected error",
|
||||||
"Please contact MinIO at https://slack.min.io",
|
"Please contact MinIO at https://slack.min.io",
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidCompressionIncludesValue = newUIErrFn(
|
ErrInvalidCompressionIncludesValue = newErrFn(
|
||||||
"Invalid compression include value",
|
"Invalid compression include value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"Compress extensions/mime-types are delimited by `,`. For eg, MINIO_COMPRESS_ATTR=\"A,B,C\"",
|
"Compress extensions/mime-types are delimited by `,`. For eg, MINIO_COMPRESS_ATTR=\"A,B,C\"",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidGWSSEValue = newUIErrFn(
|
ErrInvalidGWSSEValue = newErrFn(
|
||||||
"Invalid gateway SSE value",
|
"Invalid gateway SSE value",
|
||||||
"Please check the passed value",
|
"Please check the passed value",
|
||||||
"MINIO_GATEWAY_SSE: Gateway SSE accepts only C and S3 as valid values. Delimit by `;` to set more than one value",
|
"MINIO_GATEWAY_SSE: Gateway SSE accepts only C and S3 as valid values. Delimit by `;` to set more than one value",
|
||||||
)
|
)
|
||||||
|
|
||||||
uiErrInvalidGWSSEEnvValue = newUIErrFn(
|
ErrInvalidGWSSEEnvValue = newErrFn(
|
||||||
"Invalid gateway SSE configuration",
|
"Invalid gateway SSE configuration",
|
||||||
"",
|
"",
|
||||||
"Refer to https://docs.min.io/docs/minio-kms-quickstart-guide.html for setting up SSE",
|
"Refer to https://docs.min.io/docs/minio-kms-quickstart-guide.html for setting up SSE",
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
|
ldap "gopkg.in/ldap.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultLDAPExpiry = time.Hour * 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config contains AD/LDAP server connectivity information.
|
||||||
|
type Config struct {
|
||||||
|
IsEnabled bool `json:"enabled"`
|
||||||
|
|
||||||
|
// E.g. "ldap.minio.io:636"
|
||||||
|
ServerAddr string `json:"serverAddr"`
|
||||||
|
|
||||||
|
// STS credentials expiry duration
|
||||||
|
STSExpiryDuration string `json:"stsExpiryDuration"`
|
||||||
|
stsExpiryDuration time.Duration // contains converted value
|
||||||
|
|
||||||
|
RootCAs *x509.CertPool `json:"-"`
|
||||||
|
|
||||||
|
// Format string for usernames
|
||||||
|
UsernameFormat string `json:"usernameFormat"`
|
||||||
|
|
||||||
|
GroupSearchBaseDN string `json:"groupSearchBaseDN"`
|
||||||
|
GroupSearchFilter string `json:"groupSearchFilter"`
|
||||||
|
GroupNameAttribute string `json:"groupNameAttribute"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LDAP keys and envs.
|
||||||
|
const (
|
||||||
|
ServerAddr = "server_addr"
|
||||||
|
STSExpiry = "sts_expiry"
|
||||||
|
UsernameFormat = "username_format"
|
||||||
|
GroupSearchFilter = "group_search_filter"
|
||||||
|
GroupNameAttribute = "group_name_attribute"
|
||||||
|
GroupSearchBaseDN = "group_search_base_dn"
|
||||||
|
|
||||||
|
EnvServerAddr = "MINIO_IDENTITY_LDAP_SERVER_ADDR"
|
||||||
|
EnvSTSExpiry = "MINIO_IDENTITY_LDAP_STS_EXPIRY"
|
||||||
|
EnvUsernameFormat = "MINIO_IDENTITY_LDAP_USERNAME_FORMAT"
|
||||||
|
EnvGroupSearchFilter = "MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER"
|
||||||
|
EnvGroupNameAttribute = "MINIO_IDENTITY_LDAP_GROUP_NAME_ATTRIBUTE"
|
||||||
|
EnvGroupSearchBaseDN = "MINIO_IDENTITY_LDAP_GROUP_SEARCH_BASE_DN"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Connect connect to ldap server.
|
||||||
|
func (l *Config) Connect() (ldapConn *ldap.Conn, err error) {
|
||||||
|
if l == nil {
|
||||||
|
// Happens when LDAP is not configured.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return ldap.DialTLS("tcp", l.ServerAddr, &tls.Config{RootCAs: l.RootCAs})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExpiryDuration - return parsed expiry duration.
|
||||||
|
func (l Config) GetExpiryDuration() time.Duration {
|
||||||
|
return l.stsExpiryDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup - initializes LDAP config, overrides config, if any ENV values are set.
|
||||||
|
func Lookup(cfg Config, rootCAs *x509.CertPool) (l Config, err error) {
|
||||||
|
if cfg.ServerAddr == "" && cfg.IsEnabled {
|
||||||
|
return l, errors.New("ldap server cannot initialize with empty LDAP server")
|
||||||
|
}
|
||||||
|
l.RootCAs = rootCAs
|
||||||
|
ldapServer := env.Get(EnvServerAddr, cfg.ServerAddr)
|
||||||
|
if ldapServer == "" {
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
l.IsEnabled = true
|
||||||
|
l.ServerAddr = ldapServer
|
||||||
|
l.stsExpiryDuration = defaultLDAPExpiry
|
||||||
|
if v := env.Get(EnvSTSExpiry, cfg.STSExpiryDuration); v != "" {
|
||||||
|
expDur, err := time.ParseDuration(v)
|
||||||
|
if err != nil {
|
||||||
|
return l, errors.New("LDAP expiry time err:" + err.Error())
|
||||||
|
}
|
||||||
|
if expDur <= 0 {
|
||||||
|
return l, errors.New("LDAP expiry time has to be positive")
|
||||||
|
}
|
||||||
|
l.STSExpiryDuration = v
|
||||||
|
l.stsExpiryDuration = expDur
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := env.Get(EnvUsernameFormat, cfg.UsernameFormat); v != "" {
|
||||||
|
subs, err := NewSubstituter("username", "test")
|
||||||
|
if err != nil {
|
||||||
|
return l, err
|
||||||
|
}
|
||||||
|
if _, err := subs.Substitute(v); err != nil {
|
||||||
|
return l, fmt.Errorf("Only username may be substituted in the username format: %s", err)
|
||||||
|
}
|
||||||
|
l.UsernameFormat = v
|
||||||
|
}
|
||||||
|
|
||||||
|
grpSearchFilter := env.Get(EnvGroupSearchFilter, cfg.GroupSearchFilter)
|
||||||
|
grpSearchNameAttr := env.Get(EnvGroupNameAttribute, cfg.GroupNameAttribute)
|
||||||
|
grpSearchBaseDN := env.Get(EnvGroupSearchBaseDN, cfg.GroupSearchBaseDN)
|
||||||
|
|
||||||
|
// Either all group params must be set or none must be set.
|
||||||
|
allNotSet := grpSearchFilter == "" && grpSearchNameAttr == "" && grpSearchBaseDN == ""
|
||||||
|
allSet := grpSearchFilter != "" && grpSearchNameAttr != "" && grpSearchBaseDN != ""
|
||||||
|
if !allNotSet && !allSet {
|
||||||
|
return l, errors.New("All group related parameters must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if allSet {
|
||||||
|
subs, err := NewSubstituter("username", "test", "usernamedn", "test2")
|
||||||
|
if err != nil {
|
||||||
|
return l, err
|
||||||
|
}
|
||||||
|
if _, err := subs.Substitute(grpSearchFilter); err != nil {
|
||||||
|
return l, fmt.Errorf("Only username and usernamedn may be substituted in the group search filter string: %s", err)
|
||||||
|
}
|
||||||
|
l.GroupSearchFilter = grpSearchFilter
|
||||||
|
l.GroupNameAttribute = grpSearchNameAttr
|
||||||
|
subs, err = NewSubstituter("username", "test", "usernamedn", "test2")
|
||||||
|
if err != nil {
|
||||||
|
return l, err
|
||||||
|
}
|
||||||
|
if _, err := subs.Substitute(grpSearchBaseDN); err != nil {
|
||||||
|
return l, fmt.Errorf("Only username and usernamedn may be substituted in the base DN string: %s", err)
|
||||||
|
}
|
||||||
|
l.GroupSearchBaseDN = grpSearchBaseDN
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substituter - This type is to allow restricted runtime
|
||||||
|
// substitutions of variables in LDAP configuration items during
|
||||||
|
// runtime.
|
||||||
|
type Substituter struct {
|
||||||
|
vals map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSubstituter - sets up the substituter for usage, for e.g.:
|
||||||
|
//
|
||||||
|
// subber := NewSubstituter("username", "john")
|
||||||
|
func NewSubstituter(v ...string) (Substituter, error) {
|
||||||
|
if len(v)%2 != 0 {
|
||||||
|
return Substituter{}, errors.New("Need an even number of arguments")
|
||||||
|
}
|
||||||
|
vals := make(map[string]string)
|
||||||
|
for i := 0; i < len(v); i += 2 {
|
||||||
|
vals[v[i]] = v[i+1]
|
||||||
|
}
|
||||||
|
return Substituter{vals: vals}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substitute - performs substitution on the given string `t`. Returns
|
||||||
|
// an error if there are any variables in the input that do not have
|
||||||
|
// values in the substituter. E.g.:
|
||||||
|
//
|
||||||
|
// subber.Substitute("uid=${username},cn=users,dc=example,dc=com")
|
||||||
|
//
|
||||||
|
// returns "uid=john,cn=users,dc=example,dc=com"
|
||||||
|
//
|
||||||
|
// whereas:
|
||||||
|
//
|
||||||
|
// subber.Substitute("uid=${usernamedn}")
|
||||||
|
//
|
||||||
|
// returns an error.
|
||||||
|
func (s *Substituter) Substitute(t string) (string, error) {
|
||||||
|
for k, v := range s.vals {
|
||||||
|
re := regexp.MustCompile(fmt.Sprintf(`\$\{%s\}`, k))
|
||||||
|
t = re.ReplaceAllLiteralString(t, v)
|
||||||
|
}
|
||||||
|
// Check if all requested substitutions have been made.
|
||||||
|
re := regexp.MustCompile(`\$\{.*\}`)
|
||||||
|
if re.MatchString(t) {
|
||||||
|
return "", errors.New("unsupported substitution requested")
|
||||||
|
}
|
||||||
|
return t, nil
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSubstituter(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
KV []string
|
||||||
|
SubstitutableStr string
|
||||||
|
SubstitutedStr string
|
||||||
|
ErrExpected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
KV: []string{"username", "john"},
|
||||||
|
SubstitutableStr: "uid=${username},cn=users,dc=example,dc=com",
|
||||||
|
SubstitutedStr: "uid=john,cn=users,dc=example,dc=com",
|
||||||
|
ErrExpected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
KV: []string{"username", "john"},
|
||||||
|
SubstitutableStr: "uid=${usernamedn},cn=users,dc=example,dc=com",
|
||||||
|
ErrExpected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
KV: []string{"username"},
|
||||||
|
SubstitutableStr: "uid=${usernamedn},cn=users,dc=example,dc=com",
|
||||||
|
ErrExpected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) {
|
||||||
|
subber, err := NewSubstituter(test.KV...)
|
||||||
|
if err != nil && !test.ErrExpected {
|
||||||
|
t.Errorf("Unexpected failure %s", err)
|
||||||
|
}
|
||||||
|
gotStr, err := subber.Substitute(test.SubstitutableStr)
|
||||||
|
if err != nil && !test.ErrExpected {
|
||||||
|
t.Errorf("Unexpected failure %s", err)
|
||||||
|
}
|
||||||
|
if gotStr != test.SubstitutedStr {
|
||||||
|
t.Errorf("Expected %s, got %s", test.SubstitutedStr, gotStr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,8 +47,6 @@ const (
|
||||||
cacheDataFile = "part.1"
|
cacheDataFile = "part.1"
|
||||||
cacheMetaVersion = "1.0.0"
|
cacheMetaVersion = "1.0.0"
|
||||||
|
|
||||||
cacheEnvDelimiter = ";"
|
|
||||||
|
|
||||||
// SSECacheEncrypted is the metadata key indicating that the object
|
// SSECacheEncrypted is the metadata key indicating that the object
|
||||||
// is a cache entry encrypted with cache KMS master key in globalCacheKMS.
|
// is a cache entry encrypted with cache KMS master key in globalCacheKMS.
|
||||||
SSECacheEncrypted = "X-Minio-Internal-Encrypted-Cache"
|
SSECacheEncrypted = "X-Minio-Internal-Encrypted-Cache"
|
||||||
|
|
|
@ -13,7 +13,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/djherbis/atime"
|
"github.com/djherbis/atime"
|
||||||
|
"github.com/minio/minio/cmd/config/cache"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
"github.com/minio/minio/pkg/wildcard"
|
"github.com/minio/minio/pkg/wildcard"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -389,7 +391,7 @@ func (c *cacheObjects) hashIndex(bucket, object string) int {
|
||||||
|
|
||||||
// newCache initializes the cacheFSObjects for the "drives" specified in config.json
|
// newCache initializes the cacheFSObjects for the "drives" specified in config.json
|
||||||
// or the global env overrides.
|
// or the global env overrides.
|
||||||
func newCache(config CacheConfig) ([]*diskCache, bool, error) {
|
func newCache(config cache.Config) ([]*diskCache, bool, error) {
|
||||||
var caches []*diskCache
|
var caches []*diskCache
|
||||||
ctx := logger.SetReqInfo(context.Background(), &logger.ReqInfo{})
|
ctx := logger.SetReqInfo(context.Background(), &logger.ReqInfo{})
|
||||||
formats, migrating, err := loadAndValidateCacheFormat(ctx, config.Drives)
|
formats, migrating, err := loadAndValidateCacheFormat(ctx, config.Drives)
|
||||||
|
@ -446,7 +448,7 @@ func checkAtimeSupport(dir string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (c *cacheObjects) migrateCacheFromV1toV2(ctx context.Context) {
|
func (c *cacheObjects) migrateCacheFromV1toV2(ctx context.Context) {
|
||||||
logStartupMessage(colorBlue("Cache migration initiated ...."))
|
logStartupMessage(color.Blue("Cache migration initiated ...."))
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
errs := make([]error, len(c.cache))
|
errs := make([]error, len(c.cache))
|
||||||
|
@ -482,7 +484,7 @@ func (c *cacheObjects) migrateCacheFromV1toV2(ctx context.Context) {
|
||||||
c.migMutex.Lock()
|
c.migMutex.Lock()
|
||||||
defer c.migMutex.Unlock()
|
defer c.migMutex.Unlock()
|
||||||
c.migrating = false
|
c.migrating = false
|
||||||
logStartupMessage(colorBlue("Cache migration completed successfully."))
|
logStartupMessage(color.Blue("Cache migration completed successfully."))
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObject - caches the uploaded object for single Put operations
|
// PutObject - caches the uploaded object for single Put operations
|
||||||
|
@ -535,7 +537,7 @@ func (c *cacheObjects) PutObject(ctx context.Context, bucket, object string, r *
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns cacheObjects for use by Server.
|
// Returns cacheObjects for use by Server.
|
||||||
func newServerCacheObjects(ctx context.Context, config CacheConfig) (CacheObjectLayer, error) {
|
func newServerCacheObjects(ctx context.Context, config cache.Config) (CacheObjectLayer, error) {
|
||||||
// list of disk caches for cache "drives" specified in config.json or MINIO_CACHE_DRIVES env var.
|
// list of disk caches for cache "drives" specified in config.json or MINIO_CACHE_DRIVES env var.
|
||||||
cache, migrateSw, err := newCache(config)
|
cache, migrateSw, err := newCache(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -18,12 +18,13 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/minio/minio-go/v6/pkg/set"
|
"github.com/minio/minio-go/v6/pkg/set"
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
"github.com/minio/minio/pkg/ellipses"
|
"github.com/minio/minio/pkg/ellipses"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file implements and supports ellipses pattern for
|
// This file implements and supports ellipses pattern for
|
||||||
|
@ -77,13 +78,13 @@ func getSetIndexes(args []string, totalSizes []uint64) (setIndexes [][]uint64, e
|
||||||
}
|
}
|
||||||
|
|
||||||
var customSetDriveCount uint64
|
var customSetDriveCount uint64
|
||||||
if v := os.Getenv("MINIO_ERASURE_SET_DRIVE_COUNT"); v != "" {
|
if v := env.Get("MINIO_ERASURE_SET_DRIVE_COUNT", ""); v != "" {
|
||||||
customSetDriveCount, err = strconv.ParseUint(v, 10, 64)
|
customSetDriveCount, err = strconv.ParseUint(v, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, uiErrInvalidErasureSetSize(err)
|
return nil, config.ErrInvalidErasureSetSize(err)
|
||||||
}
|
}
|
||||||
if !isValidSetSize(customSetDriveCount) {
|
if !isValidSetSize(customSetDriveCount) {
|
||||||
return nil, uiErrInvalidErasureSetSize(nil)
|
return nil, config.ErrInvalidErasureSetSize(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +92,7 @@ func getSetIndexes(args []string, totalSizes []uint64) (setIndexes [][]uint64, e
|
||||||
for _, totalSize := range totalSizes {
|
for _, totalSize := range totalSizes {
|
||||||
// Check if totalSize has minimum range upto setSize
|
// Check if totalSize has minimum range upto setSize
|
||||||
if totalSize < setSizes[0] || totalSize < customSetDriveCount {
|
if totalSize < setSizes[0] || totalSize < customSetDriveCount {
|
||||||
return nil, uiErrInvalidNumberOfErasureEndpoints(nil)
|
return nil, config.ErrInvalidNumberOfErasureEndpoints(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,17 +126,17 @@ func getSetIndexes(args []string, totalSizes []uint64) (setIndexes [][]uint64, e
|
||||||
if customSetDriveCount > 0 {
|
if customSetDriveCount > 0 {
|
||||||
msg := fmt.Sprintf("Invalid set drive count, leads to non-uniform distribution for the given number of disks. Possible values for custom set count are %d", possibleSetCounts(setSize))
|
msg := fmt.Sprintf("Invalid set drive count, leads to non-uniform distribution for the given number of disks. Possible values for custom set count are %d", possibleSetCounts(setSize))
|
||||||
if customSetDriveCount > setSize {
|
if customSetDriveCount > setSize {
|
||||||
return nil, uiErrInvalidErasureSetSize(nil).Msg(msg)
|
return nil, config.ErrInvalidErasureSetSize(nil).Msg(msg)
|
||||||
}
|
}
|
||||||
if setSize%customSetDriveCount != 0 {
|
if setSize%customSetDriveCount != 0 {
|
||||||
return nil, uiErrInvalidErasureSetSize(nil).Msg(msg)
|
return nil, config.ErrInvalidErasureSetSize(nil).Msg(msg)
|
||||||
}
|
}
|
||||||
setSize = customSetDriveCount
|
setSize = customSetDriveCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether setSize is with the supported range.
|
// Check whether setSize is with the supported range.
|
||||||
if !isValidSetSize(setSize) {
|
if !isValidSetSize(setSize) {
|
||||||
return nil, uiErrInvalidNumberOfErasureEndpoints(nil)
|
return nil, config.ErrInvalidNumberOfErasureEndpoints(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range totalSizes {
|
for i := range totalSizes {
|
||||||
|
@ -198,14 +199,14 @@ func parseEndpointSet(args ...string) (ep endpointSet, err error) {
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
patterns, perr := ellipses.FindEllipsesPatterns(arg)
|
patterns, perr := ellipses.FindEllipsesPatterns(arg)
|
||||||
if perr != nil {
|
if perr != nil {
|
||||||
return endpointSet{}, uiErrInvalidErasureEndpoints(nil).Msg(perr.Error())
|
return endpointSet{}, config.ErrInvalidErasureEndpoints(nil).Msg(perr.Error())
|
||||||
}
|
}
|
||||||
argPatterns[i] = patterns
|
argPatterns[i] = patterns
|
||||||
}
|
}
|
||||||
|
|
||||||
ep.setIndexes, err = getSetIndexes(args, getTotalSizes(argPatterns))
|
ep.setIndexes, err = getSetIndexes(args, getTotalSizes(argPatterns))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return endpointSet{}, uiErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
return endpointSet{}, config.ErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
ep.argPatterns = argPatterns
|
ep.argPatterns = argPatterns
|
||||||
|
@ -254,7 +255,7 @@ func GetAllSets(args ...string) ([][]string, error) {
|
||||||
for _, sargs := range setArgs {
|
for _, sargs := range setArgs {
|
||||||
for _, arg := range sargs {
|
for _, arg := range sargs {
|
||||||
if uniqueArgs.Contains(arg) {
|
if uniqueArgs.Contains(arg) {
|
||||||
return nil, uiErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("Input args (%s) has duplicate ellipses", args))
|
return nil, config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("Input args (%s) has duplicate ellipses", args))
|
||||||
}
|
}
|
||||||
uniqueArgs.Add(arg)
|
uniqueArgs.Add(arg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -32,7 +31,9 @@ import (
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
"github.com/minio/cli"
|
"github.com/minio/cli"
|
||||||
"github.com/minio/minio-go/v6/pkg/set"
|
"github.com/minio/minio-go/v6/pkg/set"
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
"github.com/minio/minio/pkg/mountinfo"
|
"github.com/minio/minio/pkg/mountinfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -377,14 +378,14 @@ func CreateEndpoints(serverAddr string, args ...[]string) (string, EndpointList,
|
||||||
return serverAddr, endpoints, setupType, err
|
return serverAddr, endpoints, setupType, err
|
||||||
}
|
}
|
||||||
if endpoint.Type() != PathEndpointType {
|
if endpoint.Type() != PathEndpointType {
|
||||||
return serverAddr, endpoints, setupType, uiErrInvalidFSEndpoint(nil).Msg("use path style endpoint for FS setup")
|
return serverAddr, endpoints, setupType, config.ErrInvalidFSEndpoint(nil).Msg("use path style endpoint for FS setup")
|
||||||
}
|
}
|
||||||
endpoints = append(endpoints, endpoint)
|
endpoints = append(endpoints, endpoint)
|
||||||
setupType = FSSetupType
|
setupType = FSSetupType
|
||||||
|
|
||||||
// Check for cross device mounts if any.
|
// Check for cross device mounts if any.
|
||||||
if err = checkCrossDeviceMounts(endpoints); err != nil {
|
if err = checkCrossDeviceMounts(endpoints); err != nil {
|
||||||
return serverAddr, endpoints, setupType, uiErrInvalidFSEndpoint(nil).Msg(err.Error())
|
return serverAddr, endpoints, setupType, config.ErrInvalidFSEndpoint(nil).Msg(err.Error())
|
||||||
}
|
}
|
||||||
return serverAddr, endpoints, setupType, nil
|
return serverAddr, endpoints, setupType, nil
|
||||||
}
|
}
|
||||||
|
@ -395,12 +396,12 @@ func CreateEndpoints(serverAddr string, args ...[]string) (string, EndpointList,
|
||||||
var eps EndpointList
|
var eps EndpointList
|
||||||
eps, err = NewEndpointList(iargs...)
|
eps, err = NewEndpointList(iargs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return serverAddr, endpoints, setupType, uiErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
return serverAddr, endpoints, setupType, config.ErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for cross device mounts if any.
|
// Check for cross device mounts if any.
|
||||||
if err = checkCrossDeviceMounts(eps); err != nil {
|
if err = checkCrossDeviceMounts(eps); err != nil {
|
||||||
return serverAddr, endpoints, setupType, uiErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
return serverAddr, endpoints, setupType, config.ErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ep := range eps {
|
for _, ep := range eps {
|
||||||
|
@ -417,7 +418,7 @@ func CreateEndpoints(serverAddr string, args ...[]string) (string, EndpointList,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := endpoints.UpdateIsLocal(); err != nil {
|
if err := endpoints.UpdateIsLocal(); err != nil {
|
||||||
return serverAddr, endpoints, setupType, uiErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
return serverAddr, endpoints, setupType, config.ErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here all endpoints are URL style.
|
// Here all endpoints are URL style.
|
||||||
|
@ -445,7 +446,7 @@ func CreateEndpoints(serverAddr string, args ...[]string) (string, EndpointList,
|
||||||
|
|
||||||
// No local endpoint found.
|
// No local endpoint found.
|
||||||
if localEndpointCount == 0 {
|
if localEndpointCount == 0 {
|
||||||
return serverAddr, endpoints, setupType, uiErrInvalidErasureEndpoints(nil).Msg("no endpoint pointing to the local machine is found")
|
return serverAddr, endpoints, setupType, config.ErrInvalidErasureEndpoints(nil).Msg("no endpoint pointing to the local machine is found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether same path is not used in endpoints of a host on different port.
|
// Check whether same path is not used in endpoints of a host on different port.
|
||||||
|
@ -461,7 +462,7 @@ func CreateEndpoints(serverAddr string, args ...[]string) (string, EndpointList,
|
||||||
if IPSet, ok := pathIPMap[endpoint.Path]; ok {
|
if IPSet, ok := pathIPMap[endpoint.Path]; ok {
|
||||||
if !IPSet.Intersection(hostIPSet).IsEmpty() {
|
if !IPSet.Intersection(hostIPSet).IsEmpty() {
|
||||||
return serverAddr, endpoints, setupType,
|
return serverAddr, endpoints, setupType,
|
||||||
uiErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("path '%s' can not be served by different port on same address", endpoint.Path))
|
config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("path '%s' can not be served by different port on same address", endpoint.Path))
|
||||||
}
|
}
|
||||||
pathIPMap[endpoint.Path] = IPSet.Union(hostIPSet)
|
pathIPMap[endpoint.Path] = IPSet.Union(hostIPSet)
|
||||||
} else {
|
} else {
|
||||||
|
@ -479,7 +480,7 @@ func CreateEndpoints(serverAddr string, args ...[]string) (string, EndpointList,
|
||||||
}
|
}
|
||||||
if localPathSet.Contains(endpoint.Path) {
|
if localPathSet.Contains(endpoint.Path) {
|
||||||
return serverAddr, endpoints, setupType,
|
return serverAddr, endpoints, setupType,
|
||||||
uiErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("path '%s' cannot be served by different address on same server", endpoint.Path))
|
config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("path '%s' cannot be served by different address on same server", endpoint.Path))
|
||||||
}
|
}
|
||||||
localPathSet.Add(endpoint.Path)
|
localPathSet.Add(endpoint.Path)
|
||||||
}
|
}
|
||||||
|
@ -490,10 +491,10 @@ func CreateEndpoints(serverAddr string, args ...[]string) (string, EndpointList,
|
||||||
if !localPortSet.Contains(serverAddrPort) {
|
if !localPortSet.Contains(serverAddrPort) {
|
||||||
if len(localPortSet) > 1 {
|
if len(localPortSet) > 1 {
|
||||||
return serverAddr, endpoints, setupType,
|
return serverAddr, endpoints, setupType,
|
||||||
uiErrInvalidErasureEndpoints(nil).Msg("port number in server address must match with one of the port in local endpoints")
|
config.ErrInvalidErasureEndpoints(nil).Msg("port number in server address must match with one of the port in local endpoints")
|
||||||
}
|
}
|
||||||
return serverAddr, endpoints, setupType,
|
return serverAddr, endpoints, setupType,
|
||||||
uiErrInvalidErasureEndpoints(nil).Msg("server address and local endpoint have different ports")
|
config.ErrInvalidErasureEndpoints(nil).Msg("server address and local endpoint have different ports")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,9 +572,9 @@ func CreateEndpoints(serverAddr string, args ...[]string) (string, EndpointList,
|
||||||
return serverAddr, endpoints, setupType, err
|
return serverAddr, endpoints, setupType, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, dok := os.LookupEnv("MINIO_DOMAIN")
|
_, dok := env.Lookup("MINIO_DOMAIN")
|
||||||
_, eok := os.LookupEnv("MINIO_ETCD_ENDPOINTS")
|
_, eok := env.Lookup("MINIO_ETCD_ENDPOINTS")
|
||||||
_, iok := os.LookupEnv("MINIO_PUBLIC_IPS")
|
_, iok := env.Lookup("MINIO_PUBLIC_IPS")
|
||||||
if dok && eok && !iok {
|
if dok && eok && !iok {
|
||||||
updateDomainIPs(uniqueArgs)
|
updateDomainIPs(uniqueArgs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/minio/minio/cmd/crypto"
|
"github.com/minio/minio/cmd/crypto"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -76,30 +76,6 @@ const (
|
||||||
EnvVaultNamespace = "MINIO_SSE_VAULT_NAMESPACE"
|
EnvVaultNamespace = "MINIO_SSE_VAULT_NAMESPACE"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Environment provides functions for accessing environment
|
|
||||||
// variables.
|
|
||||||
var Environment = environment{}
|
|
||||||
|
|
||||||
type environment struct{}
|
|
||||||
|
|
||||||
// Get retrieves the value of the environment variable named
|
|
||||||
// by the key. If the variable is present in the environment the
|
|
||||||
// value (which may be empty) is returned. Otherwise it returns
|
|
||||||
// the specified default value.
|
|
||||||
func (environment) Get(key, defaultValue string) string {
|
|
||||||
if v, ok := os.LookupEnv(key); ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lookup retrieves the value of the environment variable named
|
|
||||||
// by the key. If the variable is present in the environment the
|
|
||||||
// value (which may be empty) is returned and the boolean is true.
|
|
||||||
// Otherwise the returned value will be empty and the boolean will
|
|
||||||
// be false.
|
|
||||||
func (environment) Lookup(key string) (string, bool) { return os.LookupEnv(key) }
|
|
||||||
|
|
||||||
// LookupKMSConfig extracts the KMS configuration provided by environment
|
// LookupKMSConfig extracts the KMS configuration provided by environment
|
||||||
// variables and merge them with the provided KMS configuration. The
|
// variables and merge them with the provided KMS configuration. The
|
||||||
// merging follows the following rules:
|
// merging follows the following rules:
|
||||||
|
@ -113,7 +89,7 @@ func (environment) Lookup(key string) (string, bool) { return os.LookupEnv(key)
|
||||||
//
|
//
|
||||||
// It sets the global KMS configuration according to the merged configuration
|
// It sets the global KMS configuration according to the merged configuration
|
||||||
// on success.
|
// on success.
|
||||||
func (env environment) LookupKMSConfig(config crypto.KMSConfig) (err error) {
|
func LookupKMSConfig(config crypto.KMSConfig) (err error) {
|
||||||
// Lookup Hashicorp-Vault configuration & overwrite config entry if ENV var is present
|
// Lookup Hashicorp-Vault configuration & overwrite config entry if ENV var is present
|
||||||
config.Vault.Endpoint = env.Get(EnvVaultEndpoint, config.Vault.Endpoint)
|
config.Vault.Endpoint = env.Get(EnvVaultEndpoint, config.Vault.Endpoint)
|
||||||
config.Vault.CAPath = env.Get(EnvVaultCAPath, config.Vault.CAPath)
|
config.Vault.CAPath = env.Get(EnvVaultCAPath, config.Vault.CAPath)
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/lock"
|
"github.com/minio/minio/pkg/lock"
|
||||||
)
|
)
|
||||||
|
@ -153,7 +154,7 @@ func formatFSMigrate(ctx context.Context, wlk *lock.LockedFile, fsPath string) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if version != formatFSVersionV2 {
|
if version != formatFSVersionV2 {
|
||||||
return uiErrUnexpectedBackendVersion(fmt.Errorf(`%s file: expected FS version: %s, found FS version: %s`, formatConfigFile, formatFSVersionV2, version))
|
return config.ErrUnexpectedBackendVersion(fmt.Errorf(`%s file: expected FS version: %s, found FS version: %s`, formatConfigFile, formatFSVersionV2, version))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import (
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/minio/minio-go/v6/pkg/s3utils"
|
"github.com/minio/minio-go/v6/pkg/s3utils"
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/lifecycle"
|
"github.com/minio/minio/pkg/lifecycle"
|
||||||
"github.com/minio/minio/pkg/lock"
|
"github.com/minio/minio/pkg/lock"
|
||||||
|
@ -116,7 +117,7 @@ func NewFSObjectLayer(fsPath string) (ObjectLayer, error) {
|
||||||
if err == errMinDiskSize {
|
if err == errMinDiskSize {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, uiErrUnableToWriteInBackend(err)
|
return nil, config.ErrUnableToWriteInBackend(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign a new UUID for FS minio mode. Each server instance
|
// Assign a new UUID for FS minio mode. Each server instance
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* MinIO Cloud Storage, (C) 2017 MinIO, Inc.
|
* MinIO Cloud Storage, (C) 2017-2019 MinIO, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,11 +18,12 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
"github.com/minio/minio/pkg/hash"
|
"github.com/minio/minio/pkg/hash"
|
||||||
xnet "github.com/minio/minio/pkg/net"
|
xnet "github.com/minio/minio/pkg/net"
|
||||||
|
|
||||||
|
@ -365,14 +366,14 @@ func parseGatewaySSE(s string) (gatewaySSE, error) {
|
||||||
gwSlice = append(gwSlice, v)
|
gwSlice = append(gwSlice, v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, uiErrInvalidGWSSEValue(nil).Msg("gateway SSE cannot be (%s) ", v)
|
return nil, config.ErrInvalidGWSSEValue(nil).Msg("gateway SSE cannot be (%s) ", v)
|
||||||
}
|
}
|
||||||
return gatewaySSE(gwSlice), nil
|
return gatewaySSE(gwSlice), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle gateway env vars
|
// handle gateway env vars
|
||||||
func handleGatewayEnvVars() {
|
func handleGatewayEnvVars() {
|
||||||
gwsseVal, ok := os.LookupEnv("MINIO_GATEWAY_SSE")
|
gwsseVal, ok := env.Lookup("MINIO_GATEWAY_SSE")
|
||||||
if ok {
|
if ok {
|
||||||
var err error
|
var err error
|
||||||
GlobalGatewaySSE, err = parseGatewaySSE(gwsseVal)
|
GlobalGatewaySSE, err = parseGatewaySSE(gwsseVal)
|
||||||
|
|
|
@ -27,14 +27,17 @@ import (
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/minio/cli"
|
"github.com/minio/cli"
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/certs"
|
"github.com/minio/minio/pkg/certs"
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
logger.Init(GOPATH, GOROOT)
|
logger.Init(GOPATH, GOROOT)
|
||||||
logger.RegisterUIError(fmtError)
|
logger.RegisterError(config.FmtError)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -141,7 +144,7 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
|
||||||
|
|
||||||
// Validate if we have access, secret set through environment.
|
// Validate if we have access, secret set through environment.
|
||||||
if !globalIsEnvCreds {
|
if !globalIsEnvCreds {
|
||||||
logger.Fatal(uiErrEnvCredentialsMissingGateway(nil), "Unable to start gateway")
|
logger.Fatal(config.ErrEnvCredentialsMissingGateway(nil), "Unable to start gateway")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set system resources to maximum.
|
// Set system resources to maximum.
|
||||||
|
@ -250,7 +253,7 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
|
||||||
loadLoggers()
|
loadLoggers()
|
||||||
|
|
||||||
// This is only to uniquely identify each gateway deployments.
|
// This is only to uniquely identify each gateway deployments.
|
||||||
globalDeploymentID = os.Getenv("MINIO_GATEWAY_DEPLOYMENT_ID")
|
globalDeploymentID = env.Get("MINIO_GATEWAY_DEPLOYMENT_ID", mustGetUUID())
|
||||||
logger.SetDeploymentID(globalDeploymentID)
|
logger.SetDeploymentID(globalDeploymentID)
|
||||||
|
|
||||||
var cacheConfig = globalServerConfig.GetCacheConfig()
|
var cacheConfig = globalServerConfig.GetCacheConfig()
|
||||||
|
@ -298,7 +301,7 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
|
||||||
|
|
||||||
// Print a warning message if gateway is not ready for production before the startup banner.
|
// Print a warning message if gateway is not ready for production before the startup banner.
|
||||||
if !gw.Production() {
|
if !gw.Production() {
|
||||||
logStartupMessage(colorYellow(" *** Warning: Not Ready for Production ***"))
|
logStartupMessage(color.Yellow(" *** Warning: Not Ready for Production ***"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print gateway startup message.
|
// Print gateway startup message.
|
||||||
|
|
|
@ -20,6 +20,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Prints the formatted startup message.
|
// Prints the formatted startup message.
|
||||||
|
@ -55,15 +57,15 @@ func printGatewayCommonMsg(apiEndpoints []string) {
|
||||||
apiEndpointStr := strings.Join(apiEndpoints, " ")
|
apiEndpointStr := strings.Join(apiEndpoints, " ")
|
||||||
|
|
||||||
// Colorize the message and print.
|
// Colorize the message and print.
|
||||||
logStartupMessage(colorBlue("Endpoint: ") + colorBold(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 1), apiEndpointStr)))
|
logStartupMessage(color.Blue("Endpoint: ") + color.Bold(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 1), apiEndpointStr)))
|
||||||
if isTerminal() && !globalCLIContext.Anonymous {
|
if color.IsTerminal() && !globalCLIContext.Anonymous {
|
||||||
logStartupMessage(colorBlue("AccessKey: ") + colorBold(fmt.Sprintf("%s ", cred.AccessKey)))
|
logStartupMessage(color.Blue("AccessKey: ") + color.Bold(fmt.Sprintf("%s ", cred.AccessKey)))
|
||||||
logStartupMessage(colorBlue("SecretKey: ") + colorBold(fmt.Sprintf("%s ", cred.SecretKey)))
|
logStartupMessage(color.Blue("SecretKey: ") + color.Bold(fmt.Sprintf("%s ", cred.SecretKey)))
|
||||||
}
|
}
|
||||||
printEventNotifiers()
|
printEventNotifiers()
|
||||||
|
|
||||||
if globalIsBrowserEnabled {
|
if globalIsBrowserEnabled {
|
||||||
logStartupMessage(colorBlue("\nBrowser Access:"))
|
logStartupMessage(color.Blue("\nBrowser Access:"))
|
||||||
logStartupMessage(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 3), apiEndpointStr))
|
logStartupMessage(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 3), apiEndpointStr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -41,6 +40,7 @@ import (
|
||||||
miniogopolicy "github.com/minio/minio-go/v6/pkg/policy"
|
miniogopolicy "github.com/minio/minio-go/v6/pkg/policy"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
"github.com/minio/minio/pkg/policy"
|
"github.com/minio/minio/pkg/policy"
|
||||||
"github.com/minio/minio/pkg/policy/condition"
|
"github.com/minio/minio/pkg/policy/condition"
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ EXAMPLES:
|
||||||
// Handler for 'minio gateway gcs' command line.
|
// Handler for 'minio gateway gcs' command line.
|
||||||
func gcsGatewayMain(ctx *cli.Context) {
|
func gcsGatewayMain(ctx *cli.Context) {
|
||||||
projectID := ctx.Args().First()
|
projectID := ctx.Args().First()
|
||||||
if projectID == "" && os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") == "" {
|
if projectID == "" && env.Get("GOOGLE_APPLICATION_CREDENTIALS", "") == "" {
|
||||||
logger.LogIf(context.Background(), errGCSProjectIDNotFound)
|
logger.LogIf(context.Background(), errGCSProjectIDNotFound)
|
||||||
cli.ShowCommandHelpAndExit(ctx, "gcs", 1)
|
cli.ShowCommandHelpAndExit(ctx, "gcs", 1)
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ func (g *GCS) NewGatewayLayer(creds auth.Credentials) (minio.ObjectLayer, error)
|
||||||
if g.projectID == "" {
|
if g.projectID == "" {
|
||||||
// If project ID is not provided on command line, we figure it out
|
// If project ID is not provided on command line, we figure it out
|
||||||
// from the credentials.json file.
|
// from the credentials.json file.
|
||||||
g.projectID, err = gcsParseProjectID(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
|
g.projectID, err = gcsParseProjectID(env.Get("GOOGLE_APPLICATION_CREDENTIALS", ""))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ import (
|
||||||
minio "github.com/minio/minio/cmd"
|
minio "github.com/minio/minio/cmd"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
xnet "github.com/minio/minio/pkg/net"
|
xnet "github.com/minio/minio/pkg/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -126,32 +127,24 @@ func (g *HDFS) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKerberosClient() (*krb.Client, error) {
|
func getKerberosClient() (*krb.Client, error) {
|
||||||
configPath := os.Getenv("KRB5_CONFIG")
|
cfg, err := config.Load(env.Get("KRB5_CONFIG", "/etc/krb5.conf"))
|
||||||
if configPath == "" {
|
|
||||||
configPath = "/etc/krb5.conf"
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg, err := config.Load(configPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the ccache location from the environment,
|
u, err := user.Current()
|
||||||
// falling back to the default location.
|
if err != nil {
|
||||||
ccachePath := os.Getenv("KRB5CCNAME")
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the ccache location from the environment, falling back to the default location.
|
||||||
|
ccachePath := env.Get("KRB5CCNAME", fmt.Sprintf("/tmp/krb5cc_%s", u.Uid))
|
||||||
if strings.Contains(ccachePath, ":") {
|
if strings.Contains(ccachePath, ":") {
|
||||||
if strings.HasPrefix(ccachePath, "FILE:") {
|
if strings.HasPrefix(ccachePath, "FILE:") {
|
||||||
ccachePath = strings.TrimPrefix(ccachePath, "FILE:")
|
ccachePath = strings.TrimPrefix(ccachePath, "FILE:")
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to use kerberos ccache: %s", ccachePath)
|
return nil, fmt.Errorf("unable to use kerberos ccache: %s", ccachePath)
|
||||||
}
|
}
|
||||||
} else if ccachePath == "" {
|
|
||||||
u, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ccachePath = fmt.Sprintf("/tmp/krb5cc_%s", u.Uid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ccache, err := credentials.LoadCCache(ccachePath)
|
ccache, err := credentials.LoadCCache(ccachePath)
|
||||||
|
@ -192,20 +185,18 @@ func (g *HDFS) NewGatewayLayer(creds auth.Credentials) (minio.ObjectLayer, error
|
||||||
opts.Addresses = addresses
|
opts.Addresses = addresses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to lookup local user: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
if opts.KerberosClient != nil {
|
if opts.KerberosClient != nil {
|
||||||
opts.KerberosClient, err = getKerberosClient()
|
opts.KerberosClient, err = getKerberosClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Unable to initialize kerberos client: %s", err)
|
return nil, fmt.Errorf("Unable to initialize kerberos client: %s", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
opts.User = os.Getenv("HADOOP_USER_NAME")
|
opts.User = env.Get("HADOOP_USER_NAME", u.Username)
|
||||||
if opts.User == "" {
|
|
||||||
u, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Unable to lookup local user: %s", err)
|
|
||||||
}
|
|
||||||
opts.User = u.Username
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clnt, err := hdfs.NewClient(opts)
|
clnt, err := hdfs.NewClient(opts)
|
||||||
|
|
|
@ -18,16 +18,13 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
isatty "github.com/mattn/go-isatty"
|
|
||||||
"github.com/minio/minio-go/v6/pkg/set"
|
"github.com/minio/minio-go/v6/pkg/set"
|
||||||
|
|
||||||
etcd "github.com/coreos/etcd/clientv3"
|
etcd "github.com/coreos/etcd/clientv3"
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/minio/minio/cmd/crypto"
|
"github.com/minio/minio/cmd/crypto"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
|
@ -269,7 +266,7 @@ var (
|
||||||
standardExcludeCompressContentTypes = []string{"video/*", "audio/*", "application/zip", "application/x-gzip", "application/x-zip-compressed", " application/x-compress", "application/x-spoon"}
|
standardExcludeCompressContentTypes = []string{"video/*", "audio/*", "application/zip", "application/x-gzip", "application/x-zip-compressed", " application/x-compress", "application/x-spoon"}
|
||||||
|
|
||||||
// Authorization validators list.
|
// Authorization validators list.
|
||||||
globalIAMValidators *openid.Validators
|
globalOpenIDValidators *openid.Validators
|
||||||
|
|
||||||
// OPA policy system.
|
// OPA policy system.
|
||||||
globalPolicyOPA *iampolicy.Opa
|
globalPolicyOPA *iampolicy.Opa
|
||||||
|
@ -288,64 +285,6 @@ var (
|
||||||
// Add new variable global values here.
|
// Add new variable global values here.
|
||||||
)
|
)
|
||||||
|
|
||||||
// global colors.
|
|
||||||
var (
|
|
||||||
// Check if we stderr, stdout are dumb terminals, we do not apply
|
|
||||||
// ansi coloring on dumb terminals.
|
|
||||||
isTerminal = func() bool {
|
|
||||||
return isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stderr.Fd())
|
|
||||||
}
|
|
||||||
|
|
||||||
colorBold = func() func(a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.Bold).SprintFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprint
|
|
||||||
}()
|
|
||||||
colorRed = func() func(format string, a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.FgRed).SprintfFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf
|
|
||||||
}()
|
|
||||||
colorBlue = func() func(format string, a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.FgBlue).SprintfFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf
|
|
||||||
}()
|
|
||||||
colorYellow = func() func(format string, a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.FgYellow).SprintfFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf
|
|
||||||
}()
|
|
||||||
colorCyanBold = func() func(a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
color.New(color.FgCyan, color.Bold).SprintFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprint
|
|
||||||
}()
|
|
||||||
colorYellowBold = func() func(format string, a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.FgYellow, color.Bold).SprintfFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf
|
|
||||||
}()
|
|
||||||
colorBgYellow = func() func(format string, a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.BgYellow).SprintfFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf
|
|
||||||
}()
|
|
||||||
colorBlack = func() func(format string, a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.FgBlack).SprintfFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf
|
|
||||||
}()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Returns minio global information, as a key value map.
|
// Returns minio global information, as a key value map.
|
||||||
// returned list of global values is not an exhaustive
|
// returned list of global values is not an exhaustive
|
||||||
// list. Feel free to add new relevant fields.
|
// list. Feel free to add new relevant fields.
|
||||||
|
|
180
cmd/ldap-ops.go
180
cmd/ldap-ops.go
|
@ -1,180 +0,0 @@
|
||||||
/*
|
|
||||||
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
ldap "gopkg.in/ldap.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultLDAPExpiry = time.Hour * 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// ldapServerConfig contains server connectivity information.
|
|
||||||
type ldapServerConfig struct {
|
|
||||||
IsEnabled bool `json:"enabled"`
|
|
||||||
|
|
||||||
// E.g. "ldap.minio.io:636"
|
|
||||||
ServerAddr string `json:"serverAddr"`
|
|
||||||
|
|
||||||
// STS credentials expiry duration
|
|
||||||
STSExpiryDuration string `json:"stsExpiryDuration"`
|
|
||||||
stsExpiryDuration time.Duration // contains converted value
|
|
||||||
rootCAs *x509.CertPool // contains custom CAs for ldaps server.
|
|
||||||
|
|
||||||
// Skips TLS verification (for testing, not
|
|
||||||
// recommended in production).
|
|
||||||
SkipTLSVerify bool `json:"skipTLSverify"`
|
|
||||||
|
|
||||||
// Format string for usernames
|
|
||||||
UsernameFormat string `json:"usernameFormat"`
|
|
||||||
|
|
||||||
GroupSearchBaseDN string `json:"groupSearchBaseDN"`
|
|
||||||
GroupSearchFilter string `json:"groupSearchFilter"`
|
|
||||||
GroupNameAttribute string `json:"groupNameAttribute"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *ldapServerConfig) Connect() (ldapConn *ldap.Conn, err error) {
|
|
||||||
if l == nil {
|
|
||||||
// Happens when LDAP is not configured.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if l.SkipTLSVerify {
|
|
||||||
ldapConn, err = ldap.DialTLS("tcp", l.ServerAddr, &tls.Config{RootCAs: l.rootCAs, InsecureSkipVerify: true})
|
|
||||||
} else {
|
|
||||||
ldapConn, err = ldap.DialTLS("tcp", l.ServerAddr, &tls.Config{RootCAs: l.rootCAs})
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// newLDAPConfigFromEnv loads configuration from the environment
|
|
||||||
func newLDAPConfigFromEnv(rootCAs *x509.CertPool) (l ldapServerConfig, err error) {
|
|
||||||
if ldapServer, ok := os.LookupEnv("MINIO_IDENTITY_LDAP_SERVER_ADDR"); ok {
|
|
||||||
l.IsEnabled = ok
|
|
||||||
l.ServerAddr = ldapServer
|
|
||||||
|
|
||||||
// Save root CAs
|
|
||||||
l.rootCAs = rootCAs
|
|
||||||
l.SkipTLSVerify = os.Getenv("MINIO_IDENTITY_LDAP_TLS_SKIP_VERIFY") == "true"
|
|
||||||
|
|
||||||
if v := os.Getenv("MINIO_IDENTITY_LDAP_STS_EXPIRY"); v != "" {
|
|
||||||
expDur, err := time.ParseDuration(v)
|
|
||||||
if err != nil {
|
|
||||||
return l, errors.New("LDAP expiry time err:" + err.Error())
|
|
||||||
}
|
|
||||||
if expDur <= 0 {
|
|
||||||
return l, errors.New("LDAP expiry time has to be positive")
|
|
||||||
}
|
|
||||||
l.STSExpiryDuration = v
|
|
||||||
l.stsExpiryDuration = expDur
|
|
||||||
} else {
|
|
||||||
l.stsExpiryDuration = defaultLDAPExpiry
|
|
||||||
}
|
|
||||||
|
|
||||||
if v := os.Getenv("MINIO_IDENTITY_LDAP_USERNAME_FORMAT"); v != "" {
|
|
||||||
subs := newSubstituter("username", "test")
|
|
||||||
if _, err := subs.substitute(v); err != nil {
|
|
||||||
return l, errors.New("Only username may be substituted in the username format")
|
|
||||||
}
|
|
||||||
l.UsernameFormat = v
|
|
||||||
}
|
|
||||||
|
|
||||||
grpSearchFilter := os.Getenv("MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER")
|
|
||||||
grpSearchNameAttr := os.Getenv("MINIO_IDENTITY_LDAP_GROUP_NAME_ATTRIBUTE")
|
|
||||||
grpSearchBaseDN := os.Getenv("MINIO_IDENTITY_LDAP_GROUP_SEARCH_BASE_DN")
|
|
||||||
|
|
||||||
// Either all group params must be set or none must be set.
|
|
||||||
allNotSet := grpSearchFilter == "" && grpSearchNameAttr == "" && grpSearchBaseDN == ""
|
|
||||||
allSet := grpSearchFilter != "" && grpSearchNameAttr != "" && grpSearchBaseDN != ""
|
|
||||||
if !allNotSet && !allSet {
|
|
||||||
return l, errors.New("All group related parameters must be set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if allSet {
|
|
||||||
subs := newSubstituter("username", "test", "usernamedn", "test2")
|
|
||||||
if _, err := subs.substitute(grpSearchFilter); err != nil {
|
|
||||||
return l, errors.New("Only username and usernamedn may be substituted in the group search filter string")
|
|
||||||
}
|
|
||||||
l.GroupSearchFilter = grpSearchFilter
|
|
||||||
|
|
||||||
l.GroupNameAttribute = grpSearchNameAttr
|
|
||||||
|
|
||||||
subs = newSubstituter("username", "test", "usernamedn", "test2")
|
|
||||||
if _, err := subs.substitute(grpSearchBaseDN); err != nil {
|
|
||||||
return l, errors.New("Only username and usernamedn may be substituted in the base DN string")
|
|
||||||
}
|
|
||||||
l.GroupSearchBaseDN = grpSearchBaseDN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// substituter - This type is to allow restricted runtime
|
|
||||||
// substitutions of variables in LDAP configuration items during
|
|
||||||
// runtime.
|
|
||||||
type substituter struct {
|
|
||||||
vals map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// newSubstituter - sets up the substituter for usage, for e.g.:
|
|
||||||
//
|
|
||||||
// subber := newSubstituter("username", "john")
|
|
||||||
func newSubstituter(v ...string) substituter {
|
|
||||||
if len(v)%2 != 0 {
|
|
||||||
log.Fatal("Need an even number of arguments")
|
|
||||||
}
|
|
||||||
vals := make(map[string]string)
|
|
||||||
for i := 0; i < len(v); i += 2 {
|
|
||||||
vals[v[i]] = v[i+1]
|
|
||||||
}
|
|
||||||
return substituter{vals: vals}
|
|
||||||
}
|
|
||||||
|
|
||||||
// substitute - performs substitution on the given string `t`. Returns
|
|
||||||
// an error if there are any variables in the input that do not have
|
|
||||||
// values in the substituter. E.g.:
|
|
||||||
//
|
|
||||||
// subber.substitute("uid=${username},cn=users,dc=example,dc=com")
|
|
||||||
//
|
|
||||||
// returns "uid=john,cn=users,dc=example,dc=com"
|
|
||||||
//
|
|
||||||
// whereas:
|
|
||||||
//
|
|
||||||
// subber.substitute("uid=${usernamedn}")
|
|
||||||
//
|
|
||||||
// returns an error.
|
|
||||||
func (s *substituter) substitute(t string) (string, error) {
|
|
||||||
for k, v := range s.vals {
|
|
||||||
re := regexp.MustCompile(fmt.Sprintf(`\$\{%s\}`, k))
|
|
||||||
t = re.ReplaceAllLiteralString(t, v)
|
|
||||||
}
|
|
||||||
// Check if all requested substitutions have been made.
|
|
||||||
re := regexp.MustCompile(`\$\{.*\}`)
|
|
||||||
if re.MatchString(t) {
|
|
||||||
return "", errors.New("unsupported substitution requested")
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
c "github.com/minio/mc/pkg/console"
|
c "github.com/minio/mc/pkg/console"
|
||||||
"github.com/minio/minio/cmd/logger/message/log"
|
"github.com/minio/minio/cmd/logger/message/log"
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Console interface describes the methods that need to be implemented to satisfy the interface requirements.
|
// Console interface describes the methods that need to be implemented to satisfy the interface requirements.
|
||||||
|
@ -89,8 +90,8 @@ func (f fatalMsg) quiet(msg string, args ...interface{}) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logTag = "ERROR"
|
logTag = "ERROR"
|
||||||
logBanner = ColorBgRed(ColorFgWhite(ColorBold(logTag))) + " "
|
logBanner = color.BgRed(color.FgWhite(color.Bold(logTag))) + " "
|
||||||
emptyBanner = ColorBgRed(strings.Repeat(" ", len(logTag))) + " "
|
emptyBanner = color.BgRed(strings.Repeat(" ", len(logTag))) + " "
|
||||||
bannerWidth = len(logTag) + 1
|
bannerWidth = len(logTag) + 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -139,9 +139,9 @@ func IsQuiet() bool {
|
||||||
return quietFlag
|
return quietFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterUIError registers the specified rendering function. This latter
|
// RegisterError registers the specified rendering function. This latter
|
||||||
// will be called for a pretty rendering of fatal errors.
|
// will be called for a pretty rendering of fatal errors.
|
||||||
func RegisterUIError(f func(string, error, bool) string) {
|
func RegisterError(f func(string, error, bool) string) {
|
||||||
errorFmtFunc = f
|
errorFmtFunc = f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
|
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/cmd/logger/message/log"
|
"github.com/minio/minio/cmd/logger/message/log"
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Target implements loggerTarget to send log
|
// Target implements loggerTarget to send log
|
||||||
|
@ -103,7 +104,7 @@ func (c *Target) Send(e interface{}) error {
|
||||||
tagString = "\n " + tagString
|
tagString = "\n " + tagString
|
||||||
}
|
}
|
||||||
|
|
||||||
var msg = logger.ColorFgRed(logger.ColorBold(entry.Trace.Message))
|
var msg = color.FgRed(color.Bold(entry.Trace.Message))
|
||||||
var output = fmt.Sprintf("\n%s\n%s%s%s%s%s%s\nError: %s%s\n%s",
|
var output = fmt.Sprintf("\n%s\n%s%s%s%s%s%s\nError: %s%s\n%s",
|
||||||
apiString, timeString, deploymentID, requestID, remoteHost, host, userAgent,
|
apiString, timeString, deploymentID, requestID, remoteHost, host, userAgent,
|
||||||
msg, tagString, strings.Join(trace, "\n"))
|
msg, tagString, strings.Join(trace, "\n"))
|
||||||
|
|
|
@ -18,45 +18,9 @@ package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/minio/minio/pkg/color"
|
||||||
isatty "github.com/mattn/go-isatty"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Global colors.
|
|
||||||
var (
|
|
||||||
// Check if we stderr, stdout are dumb terminals, we do not apply
|
|
||||||
// ansi coloring on dumb terminals.
|
|
||||||
isTerminal = func() bool {
|
|
||||||
return isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stderr.Fd())
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorBold = func() func(a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.Bold).SprintFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprint
|
|
||||||
}()
|
|
||||||
ColorFgRed = func() func(a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.FgRed).SprintFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprint
|
|
||||||
}()
|
|
||||||
ColorBgRed = func() func(format string, a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.BgRed).SprintfFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf
|
|
||||||
}()
|
|
||||||
ColorFgWhite = func() func(format string, a ...interface{}) string {
|
|
||||||
if isTerminal() {
|
|
||||||
return color.New(color.FgWhite).SprintfFunc()
|
|
||||||
}
|
|
||||||
return fmt.Sprintf
|
|
||||||
}()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ansiRE = regexp.MustCompile("(\x1b[^m]*m)")
|
var ansiRE = regexp.MustCompile("(\x1b[^m]*m)")
|
||||||
|
@ -68,19 +32,19 @@ func ansiEscape(format string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ansiMoveRight(n int) {
|
func ansiMoveRight(n int) {
|
||||||
if isTerminal() {
|
if color.IsTerminal() {
|
||||||
ansiEscape("[%dC", n)
|
ansiEscape("[%dC", n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ansiSaveAttributes() {
|
func ansiSaveAttributes() {
|
||||||
if isTerminal() {
|
if color.IsTerminal() {
|
||||||
ansiEscape("7")
|
ansiEscape("7")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ansiRestoreAttributes() {
|
func ansiRestoreAttributes() {
|
||||||
if isTerminal() {
|
if color.IsTerminal() {
|
||||||
ansiEscape("8")
|
ansiEscape("8")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/minio/minio-go/v6/pkg/set"
|
"github.com/minio/minio-go/v6/pkg/set"
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -334,7 +335,7 @@ func sameLocalAddrs(addr1, addr2 string) (bool, error) {
|
||||||
func CheckLocalServerAddr(serverAddr string) error {
|
func CheckLocalServerAddr(serverAddr string) error {
|
||||||
host, port, err := net.SplitHostPort(serverAddr)
|
host, port, err := net.SplitHostPort(serverAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uiErrInvalidAddressFlag(err)
|
return config.ErrInvalidAddressFlag(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip off IPv6 zone information.
|
// Strip off IPv6 zone information.
|
||||||
|
@ -345,9 +346,9 @@ func CheckLocalServerAddr(serverAddr string) error {
|
||||||
// Check whether port is a valid port number.
|
// Check whether port is a valid port number.
|
||||||
p, err := strconv.Atoi(port)
|
p, err := strconv.Atoi(port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uiErrInvalidAddressFlag(err).Msg("invalid port number")
|
return config.ErrInvalidAddressFlag(err).Msg("invalid port number")
|
||||||
} else if p < 1 || p > 65535 {
|
} else if p < 1 || p > 65535 {
|
||||||
return uiErrInvalidAddressFlag(nil).Msg("port number must be between 1 to 65535")
|
return config.ErrInvalidAddressFlag(nil).Msg("port number must be between 1 to 65535")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0.0.0.0 is a wildcard address and refers to local network
|
// 0.0.0.0 is a wildcard address and refers to local network
|
||||||
|
@ -359,7 +360,7 @@ func CheckLocalServerAddr(serverAddr string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !isLocalHost {
|
if !isLocalHost {
|
||||||
return uiErrInvalidAddressFlag(nil).Msg("host in server address should be this server")
|
return config.ErrInvalidAddressFlag(nil).Msg("host in server address should be this server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,14 +28,17 @@ import (
|
||||||
|
|
||||||
"github.com/minio/cli"
|
"github.com/minio/cli"
|
||||||
"github.com/minio/dsync/v2"
|
"github.com/minio/dsync/v2"
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/certs"
|
"github.com/minio/minio/pkg/certs"
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
logger.Init(GOPATH, GOROOT)
|
logger.Init(GOPATH, GOROOT)
|
||||||
logger.RegisterUIError(fmtError)
|
logger.RegisterError(config.FmtError)
|
||||||
gob.Register(VerifyFileError(""))
|
gob.Register(VerifyFileError(""))
|
||||||
gob.Register(DeleteFileError(""))
|
gob.Register(DeleteFileError(""))
|
||||||
}
|
}
|
||||||
|
@ -133,7 +136,7 @@ EXAMPLES:
|
||||||
// Checks if endpoints are either available through environment
|
// Checks if endpoints are either available through environment
|
||||||
// or command line, returns false if both fails.
|
// or command line, returns false if both fails.
|
||||||
func endpointsPresent(ctx *cli.Context) bool {
|
func endpointsPresent(ctx *cli.Context) bool {
|
||||||
_, ok := os.LookupEnv("MINIO_ENDPOINTS")
|
_, ok := env.Lookup("MINIO_ENDPOINTS")
|
||||||
if !ok {
|
if !ok {
|
||||||
ok = ctx.Args().Present()
|
ok = ctx.Args().Present()
|
||||||
}
|
}
|
||||||
|
@ -150,12 +153,12 @@ func serverHandleCmdArgs(ctx *cli.Context) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if len(ctx.Args()) > serverCommandLineArgsMax {
|
if len(ctx.Args()) > serverCommandLineArgsMax {
|
||||||
uErr := uiErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("Invalid total number of endpoints (%d) passed, supported upto 32 unique arguments",
|
uErr := config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("Invalid total number of endpoints (%d) passed, supported upto 32 unique arguments",
|
||||||
len(ctx.Args())))
|
len(ctx.Args())))
|
||||||
logger.FatalIf(uErr, "Unable to validate passed endpoints")
|
logger.FatalIf(uErr, "Unable to validate passed endpoints")
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints := strings.Fields(os.Getenv("MINIO_ENDPOINTS"))
|
endpoints := strings.Fields(env.Get("MINIO_ENDPOINTS", ""))
|
||||||
if len(endpoints) > 0 {
|
if len(endpoints) > 0 {
|
||||||
globalMinioAddr, globalEndpoints, setupType, globalXLSetCount, globalXLSetDriveCount, err = createServerEndpoints(globalCLIContext.Addr, endpoints...)
|
globalMinioAddr, globalEndpoints, setupType, globalXLSetCount, globalXLSetDriveCount, err = createServerEndpoints(globalCLIContext.Addr, endpoints...)
|
||||||
} else {
|
} else {
|
||||||
|
@ -184,7 +187,7 @@ func serverHandleEnvVars() {
|
||||||
// Handle common environment variables.
|
// Handle common environment variables.
|
||||||
handleCommonEnvVars()
|
handleCommonEnvVars()
|
||||||
|
|
||||||
if serverRegion := os.Getenv("MINIO_REGION"); serverRegion != "" {
|
if serverRegion := env.Get("MINIO_REGION", ""); serverRegion != "" {
|
||||||
// region Envs are set globally.
|
// region Envs are set globally.
|
||||||
globalIsEnvRegion = true
|
globalIsEnvRegion = true
|
||||||
globalServerRegion = serverRegion
|
globalServerRegion = serverRegion
|
||||||
|
@ -222,10 +225,10 @@ func serverMain(ctx *cli.Context) {
|
||||||
// Is distributed setup, error out if no certificates are found for HTTPS endpoints.
|
// Is distributed setup, error out if no certificates are found for HTTPS endpoints.
|
||||||
if globalIsDistXL {
|
if globalIsDistXL {
|
||||||
if globalEndpoints.IsHTTPS() && !globalIsSSL {
|
if globalEndpoints.IsHTTPS() && !globalIsSSL {
|
||||||
logger.Fatal(uiErrNoCertsAndHTTPSEndpoints(nil), "Unable to start the server")
|
logger.Fatal(config.ErrNoCertsAndHTTPSEndpoints(nil), "Unable to start the server")
|
||||||
}
|
}
|
||||||
if !globalEndpoints.IsHTTPS() && globalIsSSL {
|
if !globalEndpoints.IsHTTPS() && globalIsSSL {
|
||||||
logger.Fatal(uiErrCertsAndHTTPEndpoints(nil), "Unable to start the server")
|
logger.Fatal(config.ErrCertsAndHTTPEndpoints(nil), "Unable to start the server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +238,7 @@ func serverMain(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalIsDiskCacheEnabled {
|
if globalIsDiskCacheEnabled {
|
||||||
logger.StartupMessage(colorRed(colorBold("Disk caching is allowed only for gateway deployments")))
|
logger.StartupMessage(color.Red(color.Bold("Disk caching is allowed only for gateway deployments")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This code should be removed in future releases and we should have mandatory
|
// FIXME: This code should be removed in future releases and we should have mandatory
|
||||||
|
@ -245,14 +248,14 @@ func serverMain(ctx *cli.Context) {
|
||||||
// Check for backward compatibility and newer style.
|
// Check for backward compatibility and newer style.
|
||||||
if !globalIsEnvCreds && globalIsDistXL {
|
if !globalIsEnvCreds && globalIsDistXL {
|
||||||
// Try to load old config file if any, for backward compatibility.
|
// Try to load old config file if any, for backward compatibility.
|
||||||
var config = &serverConfig{}
|
var cfg = &serverConfig{}
|
||||||
if _, err = Load(getConfigFile(), config); err == nil {
|
if _, err = Load(getConfigFile(), cfg); err == nil {
|
||||||
globalActiveCred = config.Credential
|
globalActiveCred = cfg.Credential
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
if _, err = Load(getConfigFile()+".deprecated", config); err == nil {
|
if _, err = Load(getConfigFile()+".deprecated", cfg); err == nil {
|
||||||
globalActiveCred = config.Credential
|
globalActiveCred = cfg.Credential
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +265,8 @@ func serverMain(ctx *cli.Context) {
|
||||||
logger.Info(`Supplying credentials from your 'config.json' is **DEPRECATED**, Access key and Secret key in distributed server mode is expected to be specified with environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY. This approach will become mandatory in future releases, please migrate to this approach soon.`)
|
logger.Info(`Supplying credentials from your 'config.json' is **DEPRECATED**, Access key and Secret key in distributed server mode is expected to be specified with environment variables MINIO_ACCESS_KEY and MINIO_SECRET_KEY. This approach will become mandatory in future releases, please migrate to this approach soon.`)
|
||||||
} else {
|
} else {
|
||||||
// Credential is not available anywhere by both means, we cannot start distributed setup anymore, fail eagerly.
|
// Credential is not available anywhere by both means, we cannot start distributed setup anymore, fail eagerly.
|
||||||
logger.Fatal(uiErrEnvCredentialsMissingDistributed(nil), "Unable to initialize the server in distributed mode")
|
logger.Fatal(config.ErrEnvCredentialsMissingDistributed(nil),
|
||||||
|
"Unable to initialize the server in distributed mode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +297,7 @@ func serverMain(ctx *cli.Context) {
|
||||||
var handler http.Handler
|
var handler http.Handler
|
||||||
handler, err = configureServerHandler(globalEndpoints)
|
handler, err = configureServerHandler(globalEndpoints)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(uiErrUnexpectedError(err), "Unable to configure one of server's RPC services")
|
logger.Fatal(config.ErrUnexpectedError(err), "Unable to configure one of server's RPC services")
|
||||||
}
|
}
|
||||||
|
|
||||||
var getCert certs.GetCertificateFunc
|
var getCert certs.GetCertificateFunc
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
|
color "github.com/minio/minio/pkg/color"
|
||||||
xnet "github.com/minio/minio/pkg/net"
|
xnet "github.com/minio/minio/pkg/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -121,18 +122,18 @@ func printServerCommonMsg(apiEndpoints []string) {
|
||||||
apiEndpointStr := strings.Join(apiEndpoints, " ")
|
apiEndpointStr := strings.Join(apiEndpoints, " ")
|
||||||
|
|
||||||
// Colorize the message and print.
|
// Colorize the message and print.
|
||||||
logStartupMessage(colorBlue("Endpoint: ") + colorBold(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 1), apiEndpointStr)))
|
logStartupMessage(color.Blue("Endpoint: ") + color.Bold(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 1), apiEndpointStr)))
|
||||||
if isTerminal() && !globalCLIContext.Anonymous {
|
if color.IsTerminal() && !globalCLIContext.Anonymous {
|
||||||
logStartupMessage(colorBlue("AccessKey: ") + colorBold(fmt.Sprintf("%s ", cred.AccessKey)))
|
logStartupMessage(color.Blue("AccessKey: ") + color.Bold(fmt.Sprintf("%s ", cred.AccessKey)))
|
||||||
logStartupMessage(colorBlue("SecretKey: ") + colorBold(fmt.Sprintf("%s ", cred.SecretKey)))
|
logStartupMessage(color.Blue("SecretKey: ") + color.Bold(fmt.Sprintf("%s ", cred.SecretKey)))
|
||||||
if region != "" {
|
if region != "" {
|
||||||
logStartupMessage(colorBlue("Region: ") + colorBold(fmt.Sprintf(getFormatStr(len(region), 3), region)))
|
logStartupMessage(color.Blue("Region: ") + color.Bold(fmt.Sprintf(getFormatStr(len(region), 3), region)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printEventNotifiers()
|
printEventNotifiers()
|
||||||
|
|
||||||
if globalIsBrowserEnabled {
|
if globalIsBrowserEnabled {
|
||||||
logStartupMessage(colorBlue("\nBrowser Access:"))
|
logStartupMessage(color.Blue("\nBrowser Access:"))
|
||||||
logStartupMessage(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 3), apiEndpointStr))
|
logStartupMessage(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 3), apiEndpointStr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,9 +145,9 @@ func printEventNotifiers() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
arnMsg := colorBlue("SQS ARNs: ")
|
arnMsg := color.Blue("SQS ARNs: ")
|
||||||
for _, arn := range arns {
|
for _, arn := range arns {
|
||||||
arnMsg += colorBold(fmt.Sprintf(getFormatStr(len(arn), 1), arn))
|
arnMsg += color.Bold(fmt.Sprintf(getFormatStr(len(arn), 1), arn))
|
||||||
}
|
}
|
||||||
|
|
||||||
logStartupMessage(arnMsg)
|
logStartupMessage(arnMsg)
|
||||||
|
@ -159,13 +160,15 @@ func printCLIAccessMsg(endPoint string, alias string) {
|
||||||
cred := globalServerConfig.GetCredential()
|
cred := globalServerConfig.GetCredential()
|
||||||
|
|
||||||
// Configure 'mc', following block prints platform specific information for minio client.
|
// Configure 'mc', following block prints platform specific information for minio client.
|
||||||
if isTerminal() {
|
if color.IsTerminal() {
|
||||||
logStartupMessage(colorBlue("\nCommand-line Access: ") + mcQuickStartGuide)
|
logStartupMessage(color.Blue("\nCommand-line Access: ") + mcQuickStartGuide)
|
||||||
if runtime.GOOS == globalWindowsOSName {
|
if runtime.GOOS == globalWindowsOSName {
|
||||||
mcMessage := fmt.Sprintf("$ mc.exe config host add %s %s %s %s", alias, endPoint, cred.AccessKey, cred.SecretKey)
|
mcMessage := fmt.Sprintf("$ mc.exe config host add %s %s %s %s", alias,
|
||||||
|
endPoint, cred.AccessKey, cred.SecretKey)
|
||||||
logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
|
logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
|
||||||
} else {
|
} else {
|
||||||
mcMessage := fmt.Sprintf("$ mc config host add %s %s %s %s", alias, endPoint, cred.AccessKey, cred.SecretKey)
|
mcMessage := fmt.Sprintf("$ mc config host add %s %s %s %s", alias,
|
||||||
|
endPoint, cred.AccessKey, cred.SecretKey)
|
||||||
logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
|
logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,12 +176,12 @@ func printCLIAccessMsg(endPoint string, alias string) {
|
||||||
|
|
||||||
// Prints startup message for Object API acces, prints link to our SDK documentation.
|
// Prints startup message for Object API acces, prints link to our SDK documentation.
|
||||||
func printObjectAPIMsg() {
|
func printObjectAPIMsg() {
|
||||||
logStartupMessage(colorBlue("\nObject API (Amazon S3 compatible):"))
|
logStartupMessage(color.Blue("\nObject API (Amazon S3 compatible):"))
|
||||||
logStartupMessage(colorBlue(" Go: ") + fmt.Sprintf(getFormatStr(len(goQuickStartGuide), 8), goQuickStartGuide))
|
logStartupMessage(color.Blue(" Go: ") + fmt.Sprintf(getFormatStr(len(goQuickStartGuide), 8), goQuickStartGuide))
|
||||||
logStartupMessage(colorBlue(" Java: ") + fmt.Sprintf(getFormatStr(len(javaQuickStartGuide), 6), javaQuickStartGuide))
|
logStartupMessage(color.Blue(" Java: ") + fmt.Sprintf(getFormatStr(len(javaQuickStartGuide), 6), javaQuickStartGuide))
|
||||||
logStartupMessage(colorBlue(" Python: ") + fmt.Sprintf(getFormatStr(len(pyQuickStartGuide), 4), pyQuickStartGuide))
|
logStartupMessage(color.Blue(" Python: ") + fmt.Sprintf(getFormatStr(len(pyQuickStartGuide), 4), pyQuickStartGuide))
|
||||||
logStartupMessage(colorBlue(" JavaScript: ") + jsQuickStartGuide)
|
logStartupMessage(color.Blue(" JavaScript: ") + jsQuickStartGuide)
|
||||||
logStartupMessage(colorBlue(" .NET: ") + fmt.Sprintf(getFormatStr(len(dotnetQuickStartGuide), 6), dotnetQuickStartGuide))
|
logStartupMessage(color.Blue(" .NET: ") + fmt.Sprintf(getFormatStr(len(dotnetQuickStartGuide), 6), dotnetQuickStartGuide))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get formatted disk/storage info message.
|
// Get formatted disk/storage info message.
|
||||||
|
@ -186,7 +189,7 @@ func getStorageInfoMsg(storageInfo StorageInfo) string {
|
||||||
var msg string
|
var msg string
|
||||||
if storageInfo.Backend.Type == BackendErasure {
|
if storageInfo.Backend.Type == BackendErasure {
|
||||||
diskInfo := fmt.Sprintf(" %d Online, %d Offline. ", storageInfo.Backend.OnlineDisks, storageInfo.Backend.OfflineDisks)
|
diskInfo := fmt.Sprintf(" %d Online, %d Offline. ", storageInfo.Backend.OnlineDisks, storageInfo.Backend.OfflineDisks)
|
||||||
msg += colorBlue("Status:") + fmt.Sprintf(getFormatStr(len(diskInfo), 8), diskInfo)
|
msg += color.Blue("Status:") + fmt.Sprintf(getFormatStr(len(diskInfo), 8), diskInfo)
|
||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
@ -199,7 +202,7 @@ func printStorageInfo(storageInfo StorageInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printCacheStorageInfo(storageInfo CacheStorageInfo) {
|
func printCacheStorageInfo(storageInfo CacheStorageInfo) {
|
||||||
msg := fmt.Sprintf("%s %s Free, %s Total", colorBlue("Cache Capacity:"),
|
msg := fmt.Sprintf("%s %s Free, %s Total", color.Blue("Cache Capacity:"),
|
||||||
humanize.IBytes(uint64(storageInfo.Free)),
|
humanize.IBytes(uint64(storageInfo.Free)),
|
||||||
humanize.IBytes(uint64(storageInfo.Total)))
|
humanize.IBytes(uint64(storageInfo.Total)))
|
||||||
logStartupMessage(msg)
|
logStartupMessage(msg)
|
||||||
|
@ -207,14 +210,14 @@ func printCacheStorageInfo(storageInfo CacheStorageInfo) {
|
||||||
|
|
||||||
// Prints certificate expiry date warning
|
// Prints certificate expiry date warning
|
||||||
func getCertificateChainMsg(certs []*x509.Certificate) string {
|
func getCertificateChainMsg(certs []*x509.Certificate) string {
|
||||||
msg := colorBlue("\nCertificate expiry info:\n")
|
msg := color.Blue("\nCertificate expiry info:\n")
|
||||||
totalCerts := len(certs)
|
totalCerts := len(certs)
|
||||||
var expiringCerts int
|
var expiringCerts int
|
||||||
for i := totalCerts - 1; i >= 0; i-- {
|
for i := totalCerts - 1; i >= 0; i-- {
|
||||||
cert := certs[i]
|
cert := certs[i]
|
||||||
if cert.NotAfter.Before(UTCNow().Add(globalMinioCertExpireWarnDays)) {
|
if cert.NotAfter.Before(UTCNow().Add(globalMinioCertExpireWarnDays)) {
|
||||||
expiringCerts++
|
expiringCerts++
|
||||||
msg += fmt.Sprintf(colorBold("#%d %s will expire on %s\n"), expiringCerts, cert.Subject.CommonName, cert.NotAfter)
|
msg += fmt.Sprintf(color.Bold("#%d %s will expire on %s\n"), expiringCerts, cert.Subject.CommonName, cert.NotAfter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if expiringCerts > 0 {
|
if expiringCerts > 0 {
|
||||||
|
|
|
@ -25,6 +25,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests if we generate storage info.
|
// Tests if we generate storage info.
|
||||||
|
@ -53,8 +55,8 @@ func TestCertificateExpiryInfo(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedMsg := colorBlue("\nCertificate expiry info:\n") +
|
expectedMsg := color.Blue("\nCertificate expiry info:\n") +
|
||||||
colorBold(fmt.Sprintf("#1 Test cert will expire on %s\n", expiredDate))
|
color.Bold(fmt.Sprintf("#1 Test cert will expire on %s\n", expiredDate))
|
||||||
|
|
||||||
// When
|
// When
|
||||||
msg := getCertificateChainMsg(fakeCerts)
|
msg := getCertificateChainMsg(fakeCerts)
|
||||||
|
|
|
@ -22,6 +22,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -104,20 +106,20 @@ func parseStorageClass(storageClassEnv string) (sc storageClass, err error) {
|
||||||
|
|
||||||
// only two elements allowed in the string - "scheme" and "number of parity disks"
|
// only two elements allowed in the string - "scheme" and "number of parity disks"
|
||||||
if len(s) > 2 {
|
if len(s) > 2 {
|
||||||
return storageClass{}, uiErrStorageClassValue(nil).Msg("Too many sections in " + storageClassEnv)
|
return storageClass{}, config.ErrStorageClassValue(nil).Msg("Too many sections in " + storageClassEnv)
|
||||||
} else if len(s) < 2 {
|
} else if len(s) < 2 {
|
||||||
return storageClass{}, uiErrStorageClassValue(nil).Msg("Too few sections in " + storageClassEnv)
|
return storageClass{}, config.ErrStorageClassValue(nil).Msg("Too few sections in " + storageClassEnv)
|
||||||
}
|
}
|
||||||
|
|
||||||
// only allowed scheme is "EC"
|
// only allowed scheme is "EC"
|
||||||
if s[0] != supportedStorageClassScheme {
|
if s[0] != supportedStorageClassScheme {
|
||||||
return storageClass{}, uiErrStorageClassValue(nil).Msg("Unsupported scheme " + s[0] + ". Supported scheme is EC")
|
return storageClass{}, config.ErrStorageClassValue(nil).Msg("Unsupported scheme " + s[0] + ". Supported scheme is EC")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of parity disks should be integer
|
// Number of parity disks should be integer
|
||||||
parityDisks, err := strconv.Atoi(s[1])
|
parityDisks, err := strconv.Atoi(s[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return storageClass{}, uiErrStorageClassValue(err)
|
return storageClass{}, config.ErrStorageClassValue(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sc = storageClass{
|
sc = storageClass{
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/minio/minio/cmd/config"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
)
|
)
|
||||||
|
@ -573,7 +574,8 @@ func registerStorageRESTHandlers(router *mux.Router, endpoints EndpointList) {
|
||||||
}
|
}
|
||||||
storage, err := newPosix(endpoint.Path)
|
storage, err := newPosix(endpoint.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(uiErrUnableToWriteInBackend(err), "Unable to initialize posix backend")
|
logger.Fatal(config.ErrUnableToWriteInBackend(err),
|
||||||
|
"Unable to initialize posix backend")
|
||||||
}
|
}
|
||||||
|
|
||||||
server := &storageRESTServer{storage, mustGetUUID()}
|
server := &storageRESTServer{storage, mustGetUUID()}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
xldap "github.com/minio/minio/cmd/config/ldap"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
"github.com/minio/minio/pkg/auth"
|
"github.com/minio/minio/pkg/auth"
|
||||||
|
@ -263,12 +264,12 @@ func (sts *stsAPIHandlers) AssumeRoleWithJWT(w http.ResponseWriter, r *http.Requ
|
||||||
ctx = newContext(r, w, action)
|
ctx = newContext(r, w, action)
|
||||||
defer logger.AuditLog(w, r, action, nil)
|
defer logger.AuditLog(w, r, action, nil)
|
||||||
|
|
||||||
if globalIAMValidators == nil {
|
if globalOpenIDValidators == nil {
|
||||||
writeSTSErrorResponse(ctx, w, ErrSTSNotInitialized, errServerNotInitialized)
|
writeSTSErrorResponse(ctx, w, ErrSTSNotInitialized, errServerNotInitialized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := globalIAMValidators.Get("jwt")
|
v, err := globalOpenIDValidators.Get("jwt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
|
writeSTSErrorResponse(ctx, w, ErrSTSInvalidParameterValue, err)
|
||||||
return
|
return
|
||||||
|
@ -471,10 +472,10 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
usernameSubs := newSubstituter("username", ldapUsername)
|
usernameSubs, _ := xldap.NewSubstituter("username", ldapUsername)
|
||||||
// We ignore error below as we already validated the username
|
// We ignore error below as we already validated the username
|
||||||
// format string at startup.
|
// format string at startup.
|
||||||
usernameDN, _ := usernameSubs.substitute(globalServerConfig.LDAPServerConfig.UsernameFormat)
|
usernameDN, _ := usernameSubs.Substitute(globalServerConfig.LDAPServerConfig.UsernameFormat)
|
||||||
// Bind with user credentials to validate the password
|
// Bind with user credentials to validate the password
|
||||||
err = ldapConn.Bind(usernameDN, ldapPassword)
|
err = ldapConn.Bind(usernameDN, ldapPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -486,14 +487,14 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
|
||||||
if globalServerConfig.LDAPServerConfig.GroupSearchFilter != "" {
|
if globalServerConfig.LDAPServerConfig.GroupSearchFilter != "" {
|
||||||
// Verified user credentials. Now we find the groups they are
|
// Verified user credentials. Now we find the groups they are
|
||||||
// a member of.
|
// a member of.
|
||||||
searchSubs := newSubstituter(
|
searchSubs, _ := xldap.NewSubstituter(
|
||||||
"username", ldapUsername,
|
"username", ldapUsername,
|
||||||
"usernamedn", usernameDN,
|
"usernamedn", usernameDN,
|
||||||
)
|
)
|
||||||
// We ignore error below as we already validated the search string
|
// We ignore error below as we already validated the search string
|
||||||
// at startup.
|
// at startup.
|
||||||
groupSearchFilter, _ := searchSubs.substitute(globalServerConfig.LDAPServerConfig.GroupSearchFilter)
|
groupSearchFilter, _ := searchSubs.Substitute(globalServerConfig.LDAPServerConfig.GroupSearchFilter)
|
||||||
baseDN, _ := searchSubs.substitute(globalServerConfig.LDAPServerConfig.GroupSearchBaseDN)
|
baseDN, _ := searchSubs.Substitute(globalServerConfig.LDAPServerConfig.GroupSearchBaseDN)
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
baseDN,
|
baseDN,
|
||||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
@ -513,7 +514,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithLDAPIdentity(w http.ResponseWriter, r *
|
||||||
groups = append(groups, entry.Attributes[0].Values...)
|
groups = append(groups, entry.Attributes[0].Values...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expiryDur := globalServerConfig.LDAPServerConfig.stsExpiryDuration
|
expiryDur := globalServerConfig.LDAPServerConfig.GetExpiryDuration()
|
||||||
m := map[string]interface{}{
|
m := map[string]interface{}{
|
||||||
"exp": UTCNow().Add(expiryDur).Unix(),
|
"exp": UTCNow().Add(expiryDur).Unix(),
|
||||||
"ldapUser": ldapUsername,
|
"ldapUser": ldapUsername,
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
"github.com/cheggaaa/pb"
|
"github.com/cheggaaa/pb"
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
// prepareUpdateMessage - prepares the update message, only if a
|
// prepareUpdateMessage - prepares the update message, only if a
|
||||||
|
@ -54,8 +55,8 @@ func colorizeUpdateMessage(updateString string, newerThan string) string {
|
||||||
line2Length := len(fmt.Sprintf(msgLine2Fmt, updateString))
|
line2Length := len(fmt.Sprintf(msgLine2Fmt, updateString))
|
||||||
|
|
||||||
// Populate lines with color coding.
|
// Populate lines with color coding.
|
||||||
line1InColor := fmt.Sprintf(msgLine1Fmt, colorYellowBold(newerThan))
|
line1InColor := fmt.Sprintf(msgLine1Fmt, color.YellowBold(newerThan))
|
||||||
line2InColor := fmt.Sprintf(msgLine2Fmt, colorCyanBold(updateString))
|
line2InColor := fmt.Sprintf(msgLine2Fmt, color.CyanBold(updateString))
|
||||||
|
|
||||||
// calculate the rectangular box size.
|
// calculate the rectangular box size.
|
||||||
maxContentWidth := int(math.Max(float64(line1Length), float64(line2Length)))
|
maxContentWidth := int(math.Max(float64(line1Length), float64(line2Length)))
|
||||||
|
@ -89,10 +90,10 @@ func colorizeUpdateMessage(updateString string, newerThan string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := []string{
|
lines := []string{
|
||||||
colorYellowBold(topLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + topRightChar),
|
color.YellowBold(topLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + topRightChar),
|
||||||
vertBarChar + line1InColor + strings.Repeat(" ", maxContentWidth-line1Length) + vertBarChar,
|
vertBarChar + line1InColor + strings.Repeat(" ", maxContentWidth-line1Length) + vertBarChar,
|
||||||
vertBarChar + line2InColor + strings.Repeat(" ", maxContentWidth-line2Length) + vertBarChar,
|
vertBarChar + line2InColor + strings.Repeat(" ", maxContentWidth-line2Length) + vertBarChar,
|
||||||
colorYellowBold(bottomLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + bottomRightChar),
|
color.YellowBold(bottomLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + bottomRightChar),
|
||||||
}
|
}
|
||||||
return "\n" + strings.Join(lines, "\n") + "\n"
|
return "\n" + strings.Join(lines, "\n") + "\n"
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/minio/minio/pkg/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests update notifier string builder.
|
// Tests update notifier string builder.
|
||||||
|
@ -68,8 +70,8 @@ func TestPrepareUpdateMessage(t *testing.T) {
|
||||||
|
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
output := prepareUpdateMessage(testCase.dlURL, testCase.older)
|
output := prepareUpdateMessage(testCase.dlURL, testCase.older)
|
||||||
line1 := fmt.Sprintf("%s %s", plainMsg, colorYellowBold(testCase.expectedSubStr))
|
line1 := fmt.Sprintf("%s %s", plainMsg, color.YellowBold(testCase.expectedSubStr))
|
||||||
line2 := fmt.Sprintf("Update: %s", colorCyanBold(testCase.dlURL))
|
line2 := fmt.Sprintf("Update: %s", color.CyanBold(testCase.dlURL))
|
||||||
// Uncomment below to see message appearance:
|
// Uncomment below to see message appearance:
|
||||||
// fmt.Println(output)
|
// fmt.Println(output)
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/inconshreveable/go-update"
|
"github.com/inconshreveable/go-update"
|
||||||
xhttp "github.com/minio/minio/cmd/http"
|
xhttp "github.com/minio/minio/cmd/http"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
|
"github.com/minio/minio/pkg/env"
|
||||||
xnet "github.com/minio/minio/pkg/net"
|
xnet "github.com/minio/minio/pkg/net"
|
||||||
_ "github.com/minio/sha256-simd" // Needed for sha256 hash verifier.
|
_ "github.com/minio/sha256-simd" // Needed for sha256 hash verifier.
|
||||||
)
|
)
|
||||||
|
@ -144,7 +145,7 @@ func IsDocker() bool {
|
||||||
func IsDCOS() bool {
|
func IsDCOS() bool {
|
||||||
// http://mesos.apache.org/documentation/latest/docker-containerizer/
|
// http://mesos.apache.org/documentation/latest/docker-containerizer/
|
||||||
// Mesos docker containerizer sets this value
|
// Mesos docker containerizer sets this value
|
||||||
return os.Getenv("MESOS_CONTAINER_NAME") != ""
|
return env.Get("MESOS_CONTAINER_NAME", "") != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsKubernetes returns true if minio is running in kubernetes.
|
// IsKubernetes returns true if minio is running in kubernetes.
|
||||||
|
@ -153,7 +154,7 @@ func IsKubernetes() bool {
|
||||||
// indeed running inside a kubernetes pod
|
// indeed running inside a kubernetes pod
|
||||||
// is KUBERNETES_SERVICE_HOST but in future
|
// is KUBERNETES_SERVICE_HOST but in future
|
||||||
// we might need to enhance this.
|
// we might need to enhance this.
|
||||||
return os.Getenv("KUBERNETES_SERVICE_HOST") != ""
|
return env.Get("KUBERNETES_SERVICE_HOST", "") != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsBOSH returns true if minio is deployed from a bosh package
|
// IsBOSH returns true if minio is deployed from a bosh package
|
||||||
|
@ -247,7 +248,7 @@ func getUserAgent(mode string) string {
|
||||||
uaAppend(" MinIO/", ReleaseTag)
|
uaAppend(" MinIO/", ReleaseTag)
|
||||||
uaAppend(" MinIO/", CommitID)
|
uaAppend(" MinIO/", CommitID)
|
||||||
if IsDCOS() {
|
if IsDCOS() {
|
||||||
universePkgVersion := os.Getenv("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION")
|
universePkgVersion := env.Get("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION", "")
|
||||||
// On DC/OS environment try to the get universe package version.
|
// On DC/OS environment try to the get universe package version.
|
||||||
if universePkgVersion != "" {
|
if universePkgVersion != "" {
|
||||||
uaAppend(" MinIO/universe-", universePkgVersion)
|
uaAppend(" MinIO/universe-", universePkgVersion)
|
||||||
|
@ -262,7 +263,7 @@ func getUserAgent(mode string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pcfTileVersion := os.Getenv("MINIO_PCF_TILE_VERSION")
|
pcfTileVersion := env.Get("MINIO_PCF_TILE_VERSION", "")
|
||||||
if pcfTileVersion != "" {
|
if pcfTileVersion != "" {
|
||||||
uaAppend(" MinIO/pcf-tile-", pcfTileVersion)
|
uaAppend(" MinIO/pcf-tile-", pcfTileVersion)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
|
)
|
||||||
|
|
||||||
|
// global colors.
|
||||||
|
var (
|
||||||
|
// Check if we stderr, stdout are dumb terminals, we do not apply
|
||||||
|
// ansi coloring on dumb terminals.
|
||||||
|
IsTerminal = func() bool {
|
||||||
|
return isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stderr.Fd())
|
||||||
|
}
|
||||||
|
|
||||||
|
Bold = func() func(a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.Bold).SprintFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprint
|
||||||
|
}()
|
||||||
|
Red = func() func(format string, a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.FgRed).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
Blue = func() func(format string, a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.FgBlue).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
Yellow = func() func(format string, a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.FgYellow).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
CyanBold = func() func(a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
color.New(color.FgCyan, color.Bold).SprintFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprint
|
||||||
|
}()
|
||||||
|
YellowBold = func() func(format string, a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.FgYellow, color.Bold).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
BgYellow = func() func(format string, a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.BgYellow).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
Black = func() func(format string, a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.FgBlack).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
FgRed = func() func(a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.FgRed).SprintFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprint
|
||||||
|
}()
|
||||||
|
BgRed = func() func(format string, a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.BgRed).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
FgWhite = func() func(format string, a ...interface{}) string {
|
||||||
|
if IsTerminal() {
|
||||||
|
return color.New(color.FgWhite).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
)
|
|
@ -0,0 +1,21 @@
|
||||||
|
package env
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
// Get retrieves the value of the environment variable named
|
||||||
|
// by the key. If the variable is present in the environment the
|
||||||
|
// value (which may be empty) is returned. Otherwise it returns
|
||||||
|
// the specified default value.
|
||||||
|
func Get(key, defaultValue string) string {
|
||||||
|
if v, ok := os.LookupEnv(key); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup retrieves the value of the environment variable named
|
||||||
|
// by the key. If the variable is present in the environment the
|
||||||
|
// value (which may be empty) is returned and the boolean is true.
|
||||||
|
// Otherwise the returned value will be empty and the boolean will
|
||||||
|
// be false.
|
||||||
|
func Lookup(key string) (string, bool) { return os.LookupEnv(key) }
|
Loading…
Reference in New Issue