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 subsystemsmaster
parent
74008446fe
commit
589e32a4ed
@ -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 |
||||
} |
@ -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) |
||||
} |
||||
}) |
||||
} |
||||
} |
@ -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 |
||||
} |
@ -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