mirror of
https://github.com/pgsty/minio.git
synced 2026-08-14 10:43:15 +03:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 829ecb2086 | |||
| d3564a4b09 | |||
| a244753f47 | |||
| 745782a77a | |||
| 246cbe1312 | |||
| 6c941122eb | |||
| 1a884cd8e1 | |||
| 18f008f7c7 | |||
| 6d42569ade | |||
| 5ed781a330 | |||
| 66fcd02aa2 | |||
| 1fc0e9a6aa | |||
| 91567ba916 | |||
| d80826b05d | |||
| 45bcf73185 | |||
| 78dc08bdc2 | |||
| f98f115ac2 | |||
| bf409936e7 | |||
| b4364723ef | |||
| bcc6359dec | |||
| 787a72a993 | |||
| d9eb962969 | |||
| f221153776 | |||
| 67596ef0cc | |||
| bf5bfe589f | |||
| af78c3925a | |||
| d144958669 | |||
| 5a64003f6f | |||
| 311718309c | |||
| 98479d7ffd | |||
| 90e505e58f | |||
| 410b8dd0fd | |||
| c2f25b6f62 | |||
| 03a2a74697 | |||
| 2807c11410 | |||
| 39d51ce845 | |||
| a216583d95 |
+7
-5
@@ -18,7 +18,8 @@ ENV MINIO_ACCESS_KEY_FILE=access_key \
|
||||
MINIO_ROOT_PASSWORD_FILE=secret_key \
|
||||
MINIO_KMS_SECRET_KEY_FILE=kms_master_key \
|
||||
MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" \
|
||||
MINIO_CONFIG_ENV_FILE=config.env
|
||||
MINIO_CONFIG_ENV_FILE=config.env \
|
||||
PATH=$PATH:/opt/bin
|
||||
|
||||
COPY dockerscripts/verify-minio.sh /usr/bin/verify-minio.sh
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
@@ -30,11 +31,12 @@ RUN \
|
||||
microdnf install curl ca-certificates shadow-utils util-linux iproute iputils --nodocs && \
|
||||
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
|
||||
microdnf install minisign --nodocs && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE} -o /usr/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.sha256sum -o /usr/bin/minio.sha256sum && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.minisig -o /usr/bin/minio.minisig && \
|
||||
mkdir -p /opt/bin && chmod -R 777 /opt/bin && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE} -o /opt/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.sha256sum -o /opt/bin/minio.sha256sum && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.minisig -o /opt/bin/minio.minisig && \
|
||||
microdnf clean all && \
|
||||
chmod +x /usr/bin/minio && \
|
||||
chmod +x /opt/bin/minio && \
|
||||
chmod +x /usr/bin/docker-entrypoint.sh && \
|
||||
chmod +x /usr/bin/verify-minio.sh && \
|
||||
/usr/bin/verify-minio.sh
|
||||
|
||||
@@ -18,7 +18,8 @@ ENV MINIO_ACCESS_KEY_FILE=access_key \
|
||||
MINIO_ROOT_PASSWORD_FILE=secret_key \
|
||||
MINIO_KMS_SECRET_KEY_FILE=kms_master_key \
|
||||
MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" \
|
||||
MINIO_CONFIG_ENV_FILE=config.env
|
||||
MINIO_CONFIG_ENV_FILE=config.env \
|
||||
PATH=$PATH:/opt/bin
|
||||
|
||||
COPY dockerscripts/verify-minio.sh /usr/bin/verify-minio.sh
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
@@ -30,11 +31,12 @@ RUN \
|
||||
microdnf install curl ca-certificates shadow-utils util-linux iproute iputils --nodocs && \
|
||||
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
|
||||
microdnf install minisign --nodocs && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips -o /usr/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips.sha256sum -o /usr/bin/minio.sha256sum && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips.minisig -o /usr/bin/minio.minisig && \
|
||||
mkdir -p /opt/bin && chmod -R 777 /opt/bin && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips -o /opt/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips.sha256sum -o /opt/bin/minio.sha256sum && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips.minisig -o /opt/bin/minio.minisig && \
|
||||
microdnf clean all && \
|
||||
chmod +x /usr/bin/minio && \
|
||||
chmod +x /opt/bin/minio && \
|
||||
chmod +x /usr/bin/docker-entrypoint.sh && \
|
||||
chmod +x /usr/bin/verify-minio.sh && \
|
||||
/usr/bin/verify-minio.sh
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
FROM scratch
|
||||
|
||||
COPY minio /minio
|
||||
|
||||
CMD ["/minio"]
|
||||
@@ -1081,8 +1081,12 @@ func (a adminAPIHandlers) AccountInfoHandler(w http.ResponseWriter, r *http.Requ
|
||||
if rd || wr {
|
||||
// Fetch the data usage of the current bucket
|
||||
var size uint64
|
||||
var objectsCount uint64
|
||||
var objectsHist map[string]uint64
|
||||
if !dataUsageInfo.LastUpdate.IsZero() {
|
||||
size = dataUsageInfo.BucketsUsage[bucket.Name].Size
|
||||
objectsCount = dataUsageInfo.BucketsUsage[bucket.Name].ObjectsCount
|
||||
objectsHist = dataUsageInfo.BucketsUsage[bucket.Name].ObjectSizesHistogram
|
||||
}
|
||||
// Fetch the prefix usage of the current bucket
|
||||
var prefixUsage map[string]uint64
|
||||
@@ -1093,11 +1097,27 @@ func (a adminAPIHandlers) AccountInfoHandler(w http.ResponseWriter, r *http.Requ
|
||||
logger.LogIf(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
lcfg, _ := globalBucketObjectLockSys.Get(bucket.Name)
|
||||
quota, _ := globalBucketQuotaSys.Get(bucket.Name)
|
||||
rcfg, _ := globalBucketMetadataSys.GetReplicationConfig(ctx, bucket.Name)
|
||||
tcfg, _ := globalBucketMetadataSys.GetTaggingConfig(bucket.Name)
|
||||
|
||||
acctInfo.Buckets = append(acctInfo.Buckets, madmin.BucketAccessInfo{
|
||||
Name: bucket.Name,
|
||||
Created: bucket.Created,
|
||||
Size: size,
|
||||
PrefixUsage: prefixUsage,
|
||||
Name: bucket.Name,
|
||||
Created: bucket.Created,
|
||||
Size: size,
|
||||
Objects: objectsCount,
|
||||
ObjectSizesHistogram: objectsHist,
|
||||
PrefixUsage: prefixUsage,
|
||||
Details: &madmin.BucketDetails{
|
||||
Versioning: globalBucketVersioningSys.Enabled(bucket.Name),
|
||||
VersioningSuspended: globalBucketVersioningSys.Suspended(bucket.Name),
|
||||
Replication: rcfg != nil,
|
||||
Locking: lcfg.LockEnabled,
|
||||
Quota: quota,
|
||||
Tagging: tcfg,
|
||||
},
|
||||
Access: madmin.AccountAccess{
|
||||
Read: rd,
|
||||
Write: wr,
|
||||
|
||||
+46
-2
@@ -925,6 +925,12 @@ func (a adminAPIHandlers) SpeedtestHandler(w http.ResponseWriter, r *http.Reques
|
||||
sizeStr := r.Form.Get(peerRESTSize)
|
||||
durationStr := r.Form.Get(peerRESTDuration)
|
||||
concurrentStr := r.Form.Get(peerRESTConcurrent)
|
||||
autotuneStr := r.Form.Get("autotune")
|
||||
|
||||
var autotune bool
|
||||
if autotuneStr != "" {
|
||||
autotune = true
|
||||
}
|
||||
|
||||
size, err := strconv.Atoi(sizeStr)
|
||||
if err != nil {
|
||||
@@ -941,9 +947,47 @@ func (a adminAPIHandlers) SpeedtestHandler(w http.ResponseWriter, r *http.Reques
|
||||
duration = time.Second * 10
|
||||
}
|
||||
|
||||
results := globalNotificationSys.Speedtest(ctx, size, concurrent, duration)
|
||||
throughputSize := size
|
||||
iopsSize := size
|
||||
|
||||
if err := json.NewEncoder(w).Encode(results); err != nil {
|
||||
if autotune {
|
||||
iopsSize = 4 * humanize.KiByte
|
||||
}
|
||||
|
||||
keepAliveTicker := time.NewTicker(500 * time.Millisecond)
|
||||
defer keepAliveTicker.Stop()
|
||||
|
||||
endBlankRepliesCh := make(chan error)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
endBlankRepliesCh <- nil
|
||||
return
|
||||
case <-keepAliveTicker.C:
|
||||
// Write a blank entry to prevent client from disconnecting
|
||||
if err := json.NewEncoder(w).Encode(madmin.SpeedTestResult{}); err != nil {
|
||||
endBlankRepliesCh <- err
|
||||
return
|
||||
}
|
||||
w.(http.Flusher).Flush()
|
||||
case endBlankRepliesCh <- nil:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
result, err := speedTest(ctx, throughputSize, iopsSize, concurrent, duration, autotune)
|
||||
if <-endBlankRepliesCh != nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(result); err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
+3
-3
@@ -1787,15 +1787,15 @@ func toAPIErrorCode(ctx context.Context, err error) (apiErr APIErrorCode) {
|
||||
|
||||
// Only return ErrClientDisconnected if the provided context is actually canceled.
|
||||
// This way downstream context.Canceled will still report ErrOperationTimedOut
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
if ctx.Err() == context.Canceled {
|
||||
return ErrClientDisconnected
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
switch err {
|
||||
case errVolumeNotFound:
|
||||
apiErr = ErrNoSuchBucket
|
||||
case errInvalidArgument:
|
||||
apiErr = ErrAdminInvalidArgument
|
||||
case errNoSuchUser:
|
||||
|
||||
+5
-5
@@ -263,7 +263,7 @@ func (o ObjectVersion) MarshalXML(e *xml.Encoder, start xml.StartElement) error
|
||||
return e.EncodeElement(objectVersionWrapper(o), start)
|
||||
}
|
||||
|
||||
// StringMap is a map[string]string.
|
||||
// StringMap is a map[string]string
|
||||
type StringMap map[string]string
|
||||
|
||||
// MarshalXML - StringMap marshals into XML.
|
||||
@@ -424,10 +424,10 @@ func generateListBucketsResponse(buckets []BucketInfo) ListBucketsResponse {
|
||||
}
|
||||
|
||||
for _, bucket := range buckets {
|
||||
var listbucket = Bucket{}
|
||||
listbucket.Name = bucket.Name
|
||||
listbucket.CreationDate = bucket.Created.UTC().Format(iso8601TimeFormat)
|
||||
listbuckets = append(listbuckets, listbucket)
|
||||
listbuckets = append(listbuckets, Bucket{
|
||||
Name: bucket.Name,
|
||||
CreationDate: bucket.Created.UTC().Format(iso8601TimeFormat),
|
||||
})
|
||||
}
|
||||
|
||||
data.Owner = owner
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ func validateAdminSignature(ctx context.Context, r *http.Request, region string)
|
||||
var owner bool
|
||||
s3Err := ErrAccessDenied
|
||||
if _, ok := r.Header[xhttp.AmzContentSha256]; ok &&
|
||||
getRequestAuthType(r) == authTypeSigned && !skipContentSha256Cksum(r) {
|
||||
getRequestAuthType(r) == authTypeSigned {
|
||||
// We only support admin credentials to access admin APIs.
|
||||
cred, owner, s3Err = getReqAccessKeyV4(r, region, serviceS3)
|
||||
if s3Err != ErrNone {
|
||||
|
||||
@@ -520,13 +520,6 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
||||
}, goi, gerr)
|
||||
replicateSync = repsync
|
||||
if replicate {
|
||||
if apiErrCode := checkRequestAuthType(ctx, r, policy.ReplicateDeleteAction, bucket, object.ObjectName); apiErrCode != ErrNone {
|
||||
if apiErrCode == ErrSignatureDoesNotMatch || apiErrCode == ErrInvalidAccessKeyID {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(apiErrCode), r.URL)
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
if object.VersionID != "" {
|
||||
object.VersionPurgeStatus = Pending
|
||||
} else {
|
||||
|
||||
@@ -123,6 +123,9 @@ func (b *BucketMetadata) Load(ctx context.Context, api ObjectLayer, name string)
|
||||
configFile := path.Join(bucketConfigPrefix, name, bucketMetadataFile)
|
||||
data, err := readConfig(ctx, api, configFile)
|
||||
if err != nil {
|
||||
if err == errConfigNotFound {
|
||||
err = errVolumeNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
if len(data) <= 4 {
|
||||
@@ -149,7 +152,7 @@ func (b *BucketMetadata) Load(ctx context.Context, api ObjectLayer, name string)
|
||||
func loadBucketMetadata(ctx context.Context, objectAPI ObjectLayer, bucket string) (BucketMetadata, error) {
|
||||
b := newBucketMetadata(bucket)
|
||||
err := b.Load(ctx, objectAPI, b.Name)
|
||||
if err != nil && !errors.Is(err, errConfigNotFound) {
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ func enforceRetentionBypassForDelete(ctx context.Context, r *http.Request, bucke
|
||||
if gerr != nil { // error from GetObjectInfo
|
||||
switch gerr.(type) {
|
||||
case MethodNotAllowed: // This happens usually for a delete marker
|
||||
if oi.DeleteMarker {
|
||||
if oi.DeleteMarker || !oi.VersionPurgeStatus.Empty() {
|
||||
// Delete marker should be present and valid.
|
||||
return ErrNone
|
||||
}
|
||||
|
||||
@@ -156,6 +156,10 @@ func (sys *BucketTargetSys) SetTarget(ctx context.Context, bucket string, tgt *m
|
||||
if !found && !update {
|
||||
newtgts = append(newtgts, *tgt)
|
||||
}
|
||||
// cancel health check for previous target client to avoid leak.
|
||||
if prevClnt, ok := sys.arnRemotesMap[tgt.Arn]; ok && prevClnt.healthCancelFn != nil {
|
||||
prevClnt.healthCancelFn()
|
||||
}
|
||||
|
||||
sys.targetsMap[bucket] = newtgts
|
||||
sys.arnRemotesMap[tgt.Arn] = clnt
|
||||
|
||||
+5
-4
@@ -144,6 +144,9 @@ func minioConfigToConsoleFeatures() {
|
||||
os.Setenv("CONSOLE_IDP_HMAC_SALT", globalDeploymentID)
|
||||
os.Setenv("CONSOLE_IDP_HMAC_PASSPHRASE", globalOpenIDConfig.ClientID)
|
||||
os.Setenv("CONSOLE_IDP_SCOPES", strings.Join(globalOpenIDConfig.DiscoveryDoc.ScopesSupported, ","))
|
||||
if globalOpenIDConfig.ClaimUserinfo {
|
||||
os.Setenv("CONSOLE_IDP_USERINFO", "on")
|
||||
}
|
||||
if globalOpenIDConfig.RedirectURI != "" {
|
||||
os.Setenv("CONSOLE_IDP_CALLBACK", globalOpenIDConfig.RedirectURI)
|
||||
} else {
|
||||
@@ -152,8 +155,8 @@ func minioConfigToConsoleFeatures() {
|
||||
}
|
||||
os.Setenv("CONSOLE_MINIO_REGION", globalServerRegion)
|
||||
os.Setenv("CONSOLE_CERT_PASSWD", env.Get("MINIO_CERT_PASSWD", ""))
|
||||
if globalSubnetLicense != "" {
|
||||
os.Setenv("CONSOLE_SUBNET_LICENSE", globalSubnetLicense)
|
||||
if globalSubnetConfig.License != "" {
|
||||
os.Setenv("CONSOLE_SUBNET_LICENSE", globalSubnetConfig.License)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,8 +602,6 @@ func handleCommonEnvVars() {
|
||||
if tiers := env.Get("_MINIO_DEBUG_REMOTE_TIERS_IMMEDIATELY", ""); tiers != "" {
|
||||
globalDebugRemoteTiersImmediately = strings.Split(tiers, ",")
|
||||
}
|
||||
|
||||
globalSubnetLicense = env.Get(config.EnvMinIOSubnetLicense, "")
|
||||
}
|
||||
|
||||
func logStartupMessage(msg string) {
|
||||
|
||||
@@ -57,7 +57,9 @@ type objectDeleter interface {
|
||||
}
|
||||
|
||||
func deleteConfig(ctx context.Context, objAPI objectDeleter, configFile string) error {
|
||||
_, err := objAPI.DeleteObject(ctx, minioMetaBucket, configFile, ObjectOptions{})
|
||||
_, err := objAPI.DeleteObject(ctx, minioMetaBucket, configFile, ObjectOptions{
|
||||
DeletePrefix: true,
|
||||
})
|
||||
if err != nil && isErrObjectNotFound(err) {
|
||||
return errConfigNotFound
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
"github.com/minio/minio/internal/config/policy/opa"
|
||||
"github.com/minio/minio/internal/config/scanner"
|
||||
"github.com/minio/minio/internal/config/storageclass"
|
||||
"github.com/minio/minio/internal/config/subnet"
|
||||
"github.com/minio/minio/internal/crypto"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
"github.com/minio/minio/internal/kms"
|
||||
@@ -65,6 +66,7 @@ func initHelp() {
|
||||
config.AuditKafkaSubSys: logger.DefaultAuditKafkaKVS,
|
||||
config.HealSubSys: heal.DefaultKVS,
|
||||
config.ScannerSubSys: scanner.DefaultKVS,
|
||||
config.SubnetSubSys: subnet.DefaultKVS,
|
||||
}
|
||||
for k, v := range notify.DefaultNotificationKVS {
|
||||
kvs[k] = v
|
||||
@@ -185,6 +187,12 @@ func initHelp() {
|
||||
Description: "publish bucket notifications to Redis datastores",
|
||||
MultipleTargets: true,
|
||||
},
|
||||
config.HelpKV{
|
||||
Key: config.SubnetSubSys,
|
||||
Type: "string",
|
||||
Description: "set subnet config for the cluster e.g. license token",
|
||||
Optional: true,
|
||||
},
|
||||
}
|
||||
|
||||
if globalIsErasure {
|
||||
@@ -223,6 +231,7 @@ func initHelp() {
|
||||
config.NotifyRedisSubSys: notify.HelpRedis,
|
||||
config.NotifyWebhookSubSys: notify.HelpWebhook,
|
||||
config.NotifyESSubSys: notify.HelpES,
|
||||
config.SubnetSubSys: subnet.HelpLicense,
|
||||
}
|
||||
|
||||
config.RegisterHelpSubSys(helpMap)
|
||||
@@ -508,6 +517,11 @@ func lookupConfigs(s config.Config, objAPI ObjectLayer) {
|
||||
logger.LogIf(ctx, fmt.Errorf("Unable to parse LDAP configuration: %w", err))
|
||||
}
|
||||
|
||||
globalSubnetConfig, err = subnet.LookupConfig(s[config.SubnetSubSys][config.Default])
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, fmt.Errorf("Unable to parse subnet configuration: %w", err))
|
||||
}
|
||||
|
||||
// Load logger targets based on user's configuration
|
||||
loggerUserAgent := getUserAgent(getMinioMode())
|
||||
|
||||
|
||||
+3
-1
@@ -96,7 +96,9 @@ func listServerConfigHistory(ctx context.Context, objAPI ObjectLayer, withData b
|
||||
|
||||
func delServerConfigHistory(ctx context.Context, objAPI ObjectLayer, uuidKV string) error {
|
||||
historyFile := pathJoin(minioConfigHistoryPrefix, uuidKV+kvPrefix)
|
||||
_, err := objAPI.DeleteObject(ctx, minioMetaBucket, historyFile, ObjectOptions{})
|
||||
_, err := objAPI.DeleteObject(ctx, minioMetaBucket, historyFile, ObjectOptions{
|
||||
DeletePrefix: true,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
+11
-6
@@ -405,11 +405,11 @@ func (f *folderScanner) scanFolder(ctx context.Context, folder cachedFolder, int
|
||||
err := readDirFn(path.Join(f.root, folder.name), func(entName string, typ os.FileMode) error {
|
||||
// Parse
|
||||
entName = pathClean(path.Join(folder.name, entName))
|
||||
if entName == "" {
|
||||
if entName == "" || entName == folder.name {
|
||||
if f.dataUsageScannerDebug {
|
||||
console.Debugf(scannerLogPrefix+" no bucket (%s,%s)\n", f.root, entName)
|
||||
console.Debugf(scannerLogPrefix+" no entity (%s,%s)\n", f.root, entName)
|
||||
}
|
||||
return errDoneForNow
|
||||
return nil
|
||||
}
|
||||
bucket, prefix := path2BucketObjectWithBasePath(f.root, entName)
|
||||
if bucket == "" {
|
||||
@@ -435,7 +435,9 @@ func (f *folderScanner) scanFolder(ctx context.Context, folder cachedFolder, int
|
||||
if typ&os.ModeDir != 0 {
|
||||
h := hashPath(entName)
|
||||
_, exists := f.oldCache.Cache[h.Key()]
|
||||
|
||||
if h == thisHash {
|
||||
return nil
|
||||
}
|
||||
this := cachedFolder{name: entName, parent: &thisHash, objectHealProbDiv: folder.objectHealProbDiv}
|
||||
delete(abandonedChildren, h.Key()) // h.Key() already accounted for.
|
||||
if exists {
|
||||
@@ -468,11 +470,14 @@ func (f *folderScanner) scanFolder(ctx context.Context, folder cachedFolder, int
|
||||
item.heal = item.heal && f.healObjectSelect > 0
|
||||
|
||||
sz, err := f.getSize(item)
|
||||
if err == errSkipFile {
|
||||
if err != nil {
|
||||
wait() // wait to proceed to next entry.
|
||||
|
||||
if err != errSkipFile && f.dataUsageScannerDebug {
|
||||
console.Debugf(scannerLogPrefix+" getSize \"%v/%v\" returned err: %v\n", bucket, item.objectPath(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// successfully read means we have a valid object.
|
||||
foundObjects = true
|
||||
// Remove filename i.e is the meta file to construct object name
|
||||
|
||||
+14
-7
@@ -893,12 +893,16 @@ func (s *erasureSets) GetObjectInfo(ctx context.Context, bucket, object string,
|
||||
}
|
||||
|
||||
func (s *erasureSets) deletePrefix(ctx context.Context, bucket string, prefix string) error {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(s.sets))
|
||||
for _, s := range s.sets {
|
||||
_, err := s.DeleteObject(ctx, bucket, prefix, ObjectOptions{DeletePrefix: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func(s *erasureObjects) {
|
||||
defer wg.Done()
|
||||
// This is a force delete, no reason to throw errors.
|
||||
s.DeleteObject(ctx, bucket, prefix, ObjectOptions{DeletePrefix: true})
|
||||
}(s)
|
||||
}
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1292,9 +1296,12 @@ func (s *erasureSets) HealFormat(ctx context.Context, dryRun bool) (res madmin.H
|
||||
if s.erasureDisks[m][n] != nil {
|
||||
s.erasureDisks[m][n].Close()
|
||||
}
|
||||
storageDisks[index].SetDiskLoc(s.poolIndex, m, n)
|
||||
s.erasureDisks[m][n] = storageDisks[index]
|
||||
s.endpointStrings[m*s.setDriveCount+n] = storageDisks[index].String()
|
||||
|
||||
if storageDisks[index] != nil {
|
||||
storageDisks[index].SetDiskLoc(s.poolIndex, m, n)
|
||||
s.erasureDisks[m][n] = storageDisks[index]
|
||||
s.endpointStrings[m*s.setDriveCount+n] = storageDisks[index].String()
|
||||
}
|
||||
}
|
||||
|
||||
// Replace reference format with what was loaded from disks.
|
||||
|
||||
+8
-1
@@ -258,6 +258,12 @@ func (fs *FSObjects) NSScanner(ctx context.Context, bf *bloomFilter, updates cha
|
||||
updates <- totalCache.dui(dataUsageRoot, buckets)
|
||||
return nil
|
||||
}
|
||||
for i, b := range buckets {
|
||||
if isReservedOrInvalidBucket(b.Name, false) {
|
||||
// Delete bucket...
|
||||
buckets = append(buckets[:i], buckets[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
totalCache.Info.BloomFilter = bf.bytes()
|
||||
|
||||
@@ -282,6 +288,7 @@ func (fs *FSObjects) NSScanner(ctx context.Context, bf *bloomFilter, updates cha
|
||||
bCache.Info.Name = b.Name
|
||||
}
|
||||
bCache.Info.BloomFilter = totalCache.Info.BloomFilter
|
||||
bCache.Info.NextCycle = wantCycle
|
||||
upds := make(chan dataUsageEntry, 1)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
@@ -290,7 +297,7 @@ func (fs *FSObjects) NSScanner(ctx context.Context, bf *bloomFilter, updates cha
|
||||
for update := range upds {
|
||||
totalCache.replace(b.Name, dataUsageRoot, update)
|
||||
if intDataUpdateTracker.debug {
|
||||
logger.Info(color.Green("NSScanner:")+" Got update:", len(totalCache.Cache))
|
||||
logger.Info(color.Green("NSScanner:")+" Got update: %v", len(totalCache.Cache))
|
||||
}
|
||||
cloned := totalCache.clone()
|
||||
updates <- cloned.dui(dataUsageRoot, buckets)
|
||||
|
||||
@@ -280,7 +280,6 @@ func StartGateway(ctx *cli.Context, gw Gateway) {
|
||||
SecretKey: globalActiveCred.SecretKey,
|
||||
})
|
||||
if err != nil {
|
||||
globalHTTPServer.Shutdown()
|
||||
logger.FatalIf(err, "Unable to initialize gateway backend")
|
||||
}
|
||||
newObject = NewGatewayLayerWithLocker(newObject)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -34,9 +35,11 @@ import (
|
||||
"github.com/minio/minio-go/v7/pkg/s3utils"
|
||||
"github.com/minio/minio-go/v7/pkg/tags"
|
||||
minio "github.com/minio/minio/cmd"
|
||||
"github.com/minio/minio/internal/config"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/pkg/bucket/policy"
|
||||
"github.com/minio/pkg/env"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -94,12 +97,16 @@ func s3GatewayMain(ctx *cli.Context) {
|
||||
logger.FatalIf(minio.ValidateGatewayArguments(serverAddr, args.First()), "Invalid argument")
|
||||
|
||||
// Start the gateway..
|
||||
minio.StartGateway(ctx, &S3{args.First()})
|
||||
minio.StartGateway(ctx, &S3{
|
||||
host: args.First(),
|
||||
debug: env.Get("_MINIO_SERVER_DEBUG", config.EnableOff) == config.EnableOn,
|
||||
})
|
||||
}
|
||||
|
||||
// S3 implements Gateway.
|
||||
type S3 struct {
|
||||
host string
|
||||
host string
|
||||
debug bool
|
||||
}
|
||||
|
||||
// Name implements Gateway interface.
|
||||
@@ -219,6 +226,10 @@ func (g *S3) NewGatewayLayer(creds madmin.Credentials) (minio.ObjectLayer, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if g.debug {
|
||||
clnt.Client.TraceOn(os.Stderr)
|
||||
}
|
||||
|
||||
probeBucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "probe-bucket-sign-")
|
||||
|
||||
// Check if the provided keys are valid.
|
||||
|
||||
+3
-2
@@ -41,6 +41,7 @@ import (
|
||||
xtls "github.com/minio/minio/internal/config/identity/tls"
|
||||
"github.com/minio/minio/internal/config/policy/opa"
|
||||
"github.com/minio/minio/internal/config/storageclass"
|
||||
"github.com/minio/minio/internal/config/subnet"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
etcd "go.etcd.io/etcd/client/v3"
|
||||
|
||||
@@ -219,8 +220,8 @@ var (
|
||||
// The name of this local node, fetched from arguments
|
||||
globalLocalNodeName string
|
||||
|
||||
// The global subnet license
|
||||
globalSubnetLicense string
|
||||
// The global subnet config
|
||||
globalSubnetConfig subnet.Config
|
||||
|
||||
globalRemoteEndpoints map[string]Endpoint
|
||||
|
||||
|
||||
+15
-22
@@ -351,10 +351,8 @@ func (er *erasureObjects) streamMetadataParts(ctx context.Context, o listPathOpt
|
||||
rpc := globalNotificationSys.restClientFromHash(o.Bucket)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return entries, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
// If many failures, check the cache state.
|
||||
@@ -424,10 +422,8 @@ func (er *erasureObjects) streamMetadataParts(ctx context.Context, o listPathOpt
|
||||
// We got a stream to start at.
|
||||
loadedPart := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return entries, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if partN != loadedPart {
|
||||
@@ -599,7 +595,7 @@ type metaCacheRPC struct {
|
||||
|
||||
func (m *metaCacheRPC) setErr(err string) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
meta := *m.meta
|
||||
if meta.status != scanStateError {
|
||||
meta.error = err
|
||||
@@ -720,26 +716,23 @@ func (er *erasureObjects) saveMetaCacheStream(ctx context.Context, mc *metaCache
|
||||
return nil
|
||||
})
|
||||
|
||||
metaMu.Lock()
|
||||
// Blocks while consuming entries or an error occurs.
|
||||
err = bw.Close()
|
||||
if err != nil {
|
||||
mc.setErr(err.Error())
|
||||
return
|
||||
}
|
||||
metaMu.Lock()
|
||||
defer metaMu.Unlock()
|
||||
if mc.meta.error != "" {
|
||||
return err
|
||||
}
|
||||
// Save success
|
||||
if mc.meta.error == "" {
|
||||
mc.meta.status = scanStateSuccess
|
||||
mc.meta.status = scanStateSuccess
|
||||
meta, err := o.updateMetacacheListing(*mc.meta, rpc)
|
||||
if err == nil {
|
||||
*mc.meta = meta
|
||||
}
|
||||
|
||||
meta := *mc.meta
|
||||
meta, _ = o.updateMetacacheListing(meta, rpc)
|
||||
*mc.meta = meta
|
||||
metaMu.Unlock()
|
||||
|
||||
if err := bw.Close(); err != nil {
|
||||
mc.setErr(err.Error())
|
||||
}
|
||||
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
type listPathRawOptions struct {
|
||||
|
||||
+16
-11
@@ -87,7 +87,7 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
|
||||
// Fast exit track to check if we are listing an object with
|
||||
// a trailing slash, this will avoid to list the object content.
|
||||
if HasSuffix(opts.BaseDir, SlashSeparator) {
|
||||
metadata, err := s.readMetadata(pathJoin(volumeDir,
|
||||
metadata, err := s.readMetadata(ctx, pathJoin(volumeDir,
|
||||
opts.BaseDir[:len(opts.BaseDir)-1]+globalDirSuffix,
|
||||
xlStorageFormatFile))
|
||||
if err == nil {
|
||||
@@ -121,6 +121,7 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
s.walkMu.Lock()
|
||||
entries, err := s.ListDir(ctx, opts.Bucket, current, -1)
|
||||
s.walkMu.Unlock()
|
||||
@@ -173,9 +174,9 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
|
||||
// If root was an object return it as such.
|
||||
if HasSuffix(entry, xlStorageFormatFile) {
|
||||
var meta metaCacheEntry
|
||||
s.walkMu.Lock()
|
||||
meta.metadata, err = s.readMetadata(pathJoin(volumeDir, current, entry))
|
||||
s.walkMu.Unlock()
|
||||
s.walkReadMu.Lock()
|
||||
meta.metadata, err = s.readMetadata(ctx, pathJoin(volumeDir, current, entry))
|
||||
s.walkReadMu.Unlock()
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
continue
|
||||
@@ -190,9 +191,9 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
|
||||
// Check legacy.
|
||||
if HasSuffix(entry, xlStorageFormatFileV1) {
|
||||
var meta metaCacheEntry
|
||||
s.walkMu.Lock()
|
||||
s.walkReadMu.Lock()
|
||||
meta.metadata, err = xioutil.ReadFile(pathJoin(volumeDir, current, entry))
|
||||
s.walkMu.Unlock()
|
||||
s.walkReadMu.Unlock()
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
continue
|
||||
@@ -248,9 +249,9 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
|
||||
meta.name = meta.name[:len(meta.name)-1] + globalDirSuffixWithSlash
|
||||
}
|
||||
|
||||
s.walkMu.Lock()
|
||||
meta.metadata, err = s.readMetadata(pathJoin(volumeDir, meta.name, xlStorageFormatFile))
|
||||
s.walkMu.Unlock()
|
||||
s.walkReadMu.Lock()
|
||||
meta.metadata, err = s.readMetadata(ctx, pathJoin(volumeDir, meta.name, xlStorageFormatFile))
|
||||
s.walkReadMu.Unlock()
|
||||
switch {
|
||||
case err == nil:
|
||||
// It was an object
|
||||
@@ -259,9 +260,7 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
|
||||
}
|
||||
out <- meta
|
||||
case osIsNotExist(err), isSysErrIsDir(err):
|
||||
s.walkMu.Lock()
|
||||
meta.metadata, err = xioutil.ReadFile(pathJoin(volumeDir, meta.name, xlStorageFormatFileV1))
|
||||
s.walkMu.Unlock()
|
||||
if err == nil {
|
||||
// It was an object
|
||||
out <- meta
|
||||
@@ -301,9 +300,15 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
|
||||
|
||||
func (p *xlStorageDiskIDCheck) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writer) error {
|
||||
defer p.updateStorageMetrics(storageMetricWalkDir, opts.Bucket, opts.BaseDir)()
|
||||
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.storage.WalkDir(ctx, opts, wr)
|
||||
}
|
||||
|
||||
|
||||
+17
-12
@@ -1505,8 +1505,13 @@ func (sys *NotificationSys) GetClusterMetrics(ctx context.Context) chan Metric {
|
||||
|
||||
// Speedtest run GET/PUT tests at input concurrency for requested object size,
|
||||
// optionally you can extend the tests longer with time.Duration.
|
||||
func (sys *NotificationSys) Speedtest(ctx context.Context, size int, concurrent int, duration time.Duration) []madmin.SpeedtestResult {
|
||||
results := make([]madmin.SpeedtestResult, len(sys.allPeerClients))
|
||||
func (sys *NotificationSys) Speedtest(ctx context.Context, size int, concurrent int, duration time.Duration) []SpeedtestResult {
|
||||
length := len(sys.allPeerClients)
|
||||
if length == 0 {
|
||||
// For single node erasure setup.
|
||||
length = 1
|
||||
}
|
||||
results := make([]SpeedtestResult, length)
|
||||
|
||||
scheme := "http"
|
||||
if globalIsTLS {
|
||||
@@ -1526,12 +1531,12 @@ func (sys *NotificationSys) Speedtest(ctx context.Context, size int, concurrent
|
||||
Scheme: scheme,
|
||||
Host: sys.peerClients[index].host.String(),
|
||||
}
|
||||
results[index].Endpoint = u.String()
|
||||
results[index].Err = err
|
||||
if err == nil {
|
||||
results[index].Uploads = r.Uploads
|
||||
results[index].Downloads = r.Downloads
|
||||
if err != nil {
|
||||
results[index].Error = err.Error()
|
||||
} else {
|
||||
results[index] = r
|
||||
}
|
||||
results[index].Endpoint = u.String()
|
||||
}(index)
|
||||
}
|
||||
|
||||
@@ -1543,12 +1548,12 @@ func (sys *NotificationSys) Speedtest(ctx context.Context, size int, concurrent
|
||||
Scheme: scheme,
|
||||
Host: globalLocalNodeName,
|
||||
}
|
||||
results[len(results)-1].Endpoint = u.String()
|
||||
results[len(results)-1].Err = err
|
||||
if err == nil {
|
||||
results[len(results)-1].Uploads = r.Uploads
|
||||
results[len(results)-1].Downloads = r.Downloads
|
||||
if err != nil {
|
||||
results[len(results)-1].Error = err.Error()
|
||||
} else {
|
||||
results[len(results)-1] = r
|
||||
}
|
||||
results[len(results)-1].Endpoint = u.String()
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
|
||||
+60
-19
@@ -916,9 +916,18 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := crypto.IsRequested(r.Header); ok && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
if _, ok := crypto.IsRequested(r.Header); ok {
|
||||
if globalIsGateway {
|
||||
if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@@ -1467,9 +1476,18 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := crypto.IsRequested(r.Header); ok && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
if _, ok := crypto.IsRequested(r.Header); ok {
|
||||
if globalIsGateway {
|
||||
if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@@ -1798,9 +1816,18 @@ func (api objectAPIHandlers) PutObjectExtractHandler(w http.ResponseWriter, r *h
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := crypto.IsRequested(r.Header); ok && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
if _, ok := crypto.IsRequested(r.Header); ok {
|
||||
if globalIsGateway {
|
||||
if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@@ -2075,9 +2102,18 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := crypto.IsRequested(r.Header); ok && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
if _, ok := crypto.IsRequested(r.Header); ok {
|
||||
if globalIsGateway {
|
||||
if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@@ -2517,8 +2553,18 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := crypto.IsRequested(r.Header); ok && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
if _, ok := crypto.IsRequested(r.Header); ok {
|
||||
if globalIsGateway {
|
||||
if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !objectAPI.IsEncryptionSupported() {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@@ -3249,11 +3295,6 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.
|
||||
|
||||
vID := opts.VersionID
|
||||
if r.Header.Get(xhttp.AmzBucketReplicationStatus) == replication.Replica.String() {
|
||||
// check if replica has permission to be deleted.
|
||||
if apiErrCode := checkRequestAuthType(ctx, r, policy.ReplicateDeleteAction, bucket, object); apiErrCode != ErrNone {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(apiErrCode), r.URL)
|
||||
return
|
||||
}
|
||||
opts.DeleteMarkerReplicationStatus = replication.Replica.String()
|
||||
if opts.VersionPurgeStatus.Empty() {
|
||||
// opts.VersionID holds delete marker version ID to replicate and not yet present on disk
|
||||
|
||||
+43
-30
@@ -1156,6 +1156,7 @@ func (s *peerRESTServer) GetPeerMetrics(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// SpeedtestResult return value of the speedtest function
|
||||
type SpeedtestResult struct {
|
||||
Endpoint string
|
||||
Uploads uint64
|
||||
Downloads uint64
|
||||
Error string
|
||||
@@ -1163,8 +1164,9 @@ type SpeedtestResult struct {
|
||||
|
||||
// SpeedtestObject implements "random-read" object reader
|
||||
type SpeedtestObject struct {
|
||||
buf []byte
|
||||
remaining int
|
||||
buf []byte
|
||||
remaining int
|
||||
totalBytesWritten *uint64
|
||||
}
|
||||
|
||||
func (bo *SpeedtestObject) Read(b []byte) (int, error) {
|
||||
@@ -1182,17 +1184,20 @@ func (bo *SpeedtestObject) Read(b []byte) (int, error) {
|
||||
}
|
||||
copy(b, bo.buf)
|
||||
bo.remaining -= len(b)
|
||||
|
||||
atomic.AddUint64(bo.totalBytesWritten, uint64(len(b)))
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// Runs the speedtest on local MinIO process.
|
||||
func selfSpeedtest(ctx context.Context, size, concurrent int, duration time.Duration) (SpeedtestResult, error) {
|
||||
var result SpeedtestResult
|
||||
objAPI := newObjectLayerFn()
|
||||
if objAPI == nil {
|
||||
return result, errServerNotInitialized
|
||||
return SpeedtestResult{}, errServerNotInitialized
|
||||
}
|
||||
|
||||
var retError string
|
||||
|
||||
bucket := minioMetaSpeedTestBucket
|
||||
|
||||
buf := make([]byte, humanize.MiByte)
|
||||
@@ -1200,15 +1205,16 @@ func selfSpeedtest(ctx context.Context, size, concurrent int, duration time.Dura
|
||||
|
||||
objCountPerThread := make([]uint64, concurrent)
|
||||
|
||||
var objUploadCount uint64
|
||||
var objDownloadCount uint64
|
||||
uploadsStopped := false
|
||||
var totalBytesWritten uint64
|
||||
uploadsCtx, uploadsCancel := context.WithCancel(context.Background())
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
doneCh1 := make(chan struct{})
|
||||
go func() {
|
||||
time.Sleep(duration)
|
||||
close(doneCh1)
|
||||
uploadsStopped = true
|
||||
uploadsCancel()
|
||||
}()
|
||||
|
||||
objNamePrefix := minioMetaSpeedTestBucketPrefix + uuid.New().String()
|
||||
@@ -1218,35 +1224,37 @@ func selfSpeedtest(ctx context.Context, size, concurrent int, duration time.Dura
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
for {
|
||||
hashReader, err := hash.NewReader(&SpeedtestObject{buf, size},
|
||||
hashReader, err := hash.NewReader(&SpeedtestObject{buf, size, &totalBytesWritten},
|
||||
int64(size), "", "", int64(size))
|
||||
if err != nil {
|
||||
retError = err.Error()
|
||||
logger.LogIf(ctx, err)
|
||||
break
|
||||
}
|
||||
reader := NewPutObjReader(hashReader)
|
||||
_, err = objAPI.PutObject(ctx, bucket, fmt.Sprintf("%s.%d.%d",
|
||||
_, err = objAPI.PutObject(uploadsCtx, bucket, fmt.Sprintf("%s.%d.%d",
|
||||
objNamePrefix, i, objCountPerThread[i]), reader, ObjectOptions{})
|
||||
if err != nil {
|
||||
if err != nil && !uploadsStopped {
|
||||
retError = err.Error()
|
||||
logger.LogIf(ctx, err)
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
objCountPerThread[i]++
|
||||
atomic.AddUint64(&objUploadCount, 1)
|
||||
select {
|
||||
case <-doneCh1:
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
doneCh2 := make(chan struct{})
|
||||
downloadsStopped := false
|
||||
var totalBytesRead uint64
|
||||
downloadsCtx, downloadsCancel := context.WithCancel(context.Background())
|
||||
|
||||
go func() {
|
||||
time.Sleep(duration)
|
||||
close(doneCh2)
|
||||
downloadsStopped = true
|
||||
downloadsCancel()
|
||||
}()
|
||||
|
||||
wg.Add(concurrent)
|
||||
@@ -1254,34 +1262,39 @@ func selfSpeedtest(ctx context.Context, size, concurrent int, duration time.Dura
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
var j uint64
|
||||
if objCountPerThread[i] == 0 {
|
||||
return
|
||||
}
|
||||
for {
|
||||
if objCountPerThread[i] == j {
|
||||
j = 0
|
||||
}
|
||||
r, err := objAPI.GetObjectNInfo(ctx, bucket, fmt.Sprintf("%s.%d.%d",
|
||||
r, err := objAPI.GetObjectNInfo(downloadsCtx, bucket, fmt.Sprintf("%s.%d.%d",
|
||||
objNamePrefix, i, j), nil, nil, noLock, ObjectOptions{})
|
||||
if err != nil {
|
||||
if err != nil && !downloadsStopped {
|
||||
retError = err.Error()
|
||||
logger.LogIf(ctx, err)
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
_, err = io.Copy(ioutil.Discard, r)
|
||||
n, err := io.Copy(ioutil.Discard, r)
|
||||
r.Close()
|
||||
if err != nil {
|
||||
|
||||
atomic.AddUint64(&totalBytesRead, uint64(n))
|
||||
if err != nil && !downloadsStopped {
|
||||
retError = err.Error()
|
||||
logger.LogIf(ctx, err)
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
j++
|
||||
atomic.AddUint64(&objDownloadCount, 1)
|
||||
select {
|
||||
case <-doneCh2:
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
return SpeedtestResult{Uploads: objUploadCount, Downloads: objDownloadCount}, nil
|
||||
return SpeedtestResult{Uploads: totalBytesWritten, Downloads: totalBytesRead, Error: retError}, nil
|
||||
}
|
||||
|
||||
func (s *peerRESTServer) SpeedtestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
+32
-11
@@ -39,15 +39,16 @@ import (
|
||||
|
||||
const (
|
||||
// STS API version.
|
||||
stsAPIVersion = "2011-06-15"
|
||||
stsVersion = "Version"
|
||||
stsAction = "Action"
|
||||
stsPolicy = "Policy"
|
||||
stsToken = "Token"
|
||||
stsWebIdentityToken = "WebIdentityToken"
|
||||
stsDurationSeconds = "DurationSeconds"
|
||||
stsLDAPUsername = "LDAPUsername"
|
||||
stsLDAPPassword = "LDAPPassword"
|
||||
stsAPIVersion = "2011-06-15"
|
||||
stsVersion = "Version"
|
||||
stsAction = "Action"
|
||||
stsPolicy = "Policy"
|
||||
stsToken = "Token"
|
||||
stsWebIdentityToken = "WebIdentityToken"
|
||||
stsWebIdentityAccessToken = "WebIdentityAccessToken" // only valid if UserInfo is enabled.
|
||||
stsDurationSeconds = "DurationSeconds"
|
||||
stsLDAPUsername = "LDAPUsername"
|
||||
stsLDAPPassword = "LDAPPassword"
|
||||
|
||||
// STS API action constants
|
||||
clientGrants = "AssumeRoleWithClientGrants"
|
||||
@@ -336,7 +337,9 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
|
||||
token = r.Form.Get(stsWebIdentityToken)
|
||||
}
|
||||
|
||||
m, err := v.Validate(token, r.Form.Get(stsDurationSeconds))
|
||||
accessToken := r.Form.Get(stsWebIdentityAccessToken)
|
||||
|
||||
m, err := v.Validate(token, accessToken, r.Form.Get(stsDurationSeconds))
|
||||
if err != nil {
|
||||
switch err {
|
||||
case openid.ErrTokenExpired:
|
||||
@@ -680,6 +683,24 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
|
||||
writeSTSErrorResponse(ctx, w, true, ErrSTSInsecureConnection, errors.New("No TLS connection attempt"))
|
||||
return
|
||||
}
|
||||
|
||||
// A client may send a certificate chain such that we end up
|
||||
// with multiple peer certificates. However, we can only accept
|
||||
// a single client certificate. Otherwise, the certificate to
|
||||
// policy mapping would be ambigious.
|
||||
// However, we can filter all CA certificates and only check
|
||||
// whether they client has sent exactly one (non-CA) leaf certificate.
|
||||
var peerCertificates = make([]*x509.Certificate, 0, len(r.TLS.PeerCertificates))
|
||||
for _, cert := range r.TLS.PeerCertificates {
|
||||
if cert.IsCA {
|
||||
continue
|
||||
}
|
||||
peerCertificates = append(peerCertificates, cert)
|
||||
}
|
||||
r.TLS.PeerCertificates = peerCertificates
|
||||
|
||||
// Now, we have to check that the client has provided exactly one leaf
|
||||
// certificate that we can map to a policy.
|
||||
if len(r.TLS.PeerCertificates) == 0 {
|
||||
writeSTSErrorResponse(ctx, w, true, ErrSTSMissingParameter, errors.New("No client certificate provided"))
|
||||
return
|
||||
@@ -690,7 +711,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
|
||||
}
|
||||
|
||||
var certificate = r.TLS.PeerCertificates[0]
|
||||
if !globalSTSTLSConfig.InsecureSkipVerify {
|
||||
if !globalSTSTLSConfig.InsecureSkipVerify { // Verify whether the client certificate has been issued by a trusted CA.
|
||||
_, err := certificate.Verify(x509.VerifyOptions{
|
||||
KeyUsages: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
|
||||
+161
@@ -37,6 +37,7 @@ import (
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"runtime/trace"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -970,3 +971,163 @@ func auditLogInternal(ctx context.Context, bucket, object string, opts AuditLogO
|
||||
ctx = logger.SetAuditEntry(ctx, &entry)
|
||||
logger.AuditLog(ctx, nil, nil, nil)
|
||||
}
|
||||
|
||||
// Get the max throughput and iops numbers.
|
||||
func speedTest(ctx context.Context, throughputSize, iopsSize int, concurrencyStart int, duration time.Duration, autotune bool) (madmin.SpeedTestResult, error) {
|
||||
var result madmin.SpeedTestResult
|
||||
|
||||
objAPI := newObjectLayerFn()
|
||||
if objAPI == nil {
|
||||
return result, errServerNotInitialized
|
||||
}
|
||||
|
||||
concurrency := concurrencyStart
|
||||
|
||||
throughputHighestGet := uint64(0)
|
||||
throughputHighestPut := uint64(0)
|
||||
var throughputHighestPutResults []SpeedtestResult
|
||||
var throughputHighestGetResults []SpeedtestResult
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// If the client got disconnected stop the speedtest.
|
||||
return result, errUnexpected
|
||||
default:
|
||||
}
|
||||
|
||||
results := globalNotificationSys.Speedtest(ctx, throughputSize, concurrency, duration)
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Endpoint < results[j].Endpoint
|
||||
})
|
||||
totalPut := uint64(0)
|
||||
totalGet := uint64(0)
|
||||
for _, result := range results {
|
||||
totalPut += result.Uploads
|
||||
totalGet += result.Downloads
|
||||
}
|
||||
if totalPut < throughputHighestPut && totalGet < throughputHighestGet {
|
||||
break
|
||||
}
|
||||
|
||||
if totalPut > throughputHighestPut {
|
||||
throughputHighestPut = totalPut
|
||||
throughputHighestPutResults = results
|
||||
}
|
||||
if totalGet > throughputHighestGet {
|
||||
throughputHighestGet = totalGet
|
||||
throughputHighestGetResults = results
|
||||
}
|
||||
if !autotune {
|
||||
break
|
||||
}
|
||||
// Try with a higher concurrency to see if we get better throughput
|
||||
concurrency += (concurrency + 1) / 2
|
||||
}
|
||||
|
||||
concurrency = concurrencyStart
|
||||
iopsHighestPut := uint64(0)
|
||||
iopsHighestGet := uint64(0)
|
||||
var iopsHighestPutResults []SpeedtestResult
|
||||
var iopsHighestGetResults []SpeedtestResult
|
||||
|
||||
if autotune {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// If the client got disconnected stop the speedtest.
|
||||
return result, errUnexpected
|
||||
default:
|
||||
}
|
||||
results := globalNotificationSys.Speedtest(ctx, iopsSize, concurrency, duration)
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Endpoint < results[j].Endpoint
|
||||
})
|
||||
totalPut := uint64(0)
|
||||
totalGet := uint64(0)
|
||||
for _, result := range results {
|
||||
totalPut += result.Uploads
|
||||
totalGet += result.Downloads
|
||||
}
|
||||
if totalPut < iopsHighestPut && totalGet < iopsHighestGet {
|
||||
break
|
||||
}
|
||||
if totalPut > iopsHighestPut {
|
||||
iopsHighestPut = totalPut
|
||||
iopsHighestPutResults = results
|
||||
}
|
||||
if totalGet > iopsHighestGet {
|
||||
iopsHighestGet = totalGet
|
||||
iopsHighestGetResults = results
|
||||
}
|
||||
if !autotune {
|
||||
break
|
||||
}
|
||||
// Try with a higher concurrency to see if we get better throughput
|
||||
concurrency += (concurrency + 1) / 2
|
||||
}
|
||||
} else {
|
||||
iopsHighestPut = throughputHighestPut
|
||||
iopsHighestGet = throughputHighestGet
|
||||
iopsHighestPutResults = throughputHighestPutResults
|
||||
iopsHighestGetResults = throughputHighestGetResults
|
||||
}
|
||||
|
||||
if len(throughputHighestPutResults) != len(iopsHighestPutResults) {
|
||||
return result, errors.New("throughput and iops differ in number of nodes")
|
||||
}
|
||||
|
||||
if len(throughputHighestGetResults) != len(iopsHighestGetResults) {
|
||||
return result, errors.New("throughput and iops differ in number of nodes")
|
||||
}
|
||||
|
||||
durationSecs := duration.Seconds()
|
||||
|
||||
result.PUTStats.ThroughputPerSec = throughputHighestPut / uint64(durationSecs)
|
||||
result.PUTStats.ObjectsPerSec = iopsHighestPut / uint64(iopsSize) / uint64(durationSecs)
|
||||
for i := 0; i < len(throughputHighestPutResults); i++ {
|
||||
errStr := ""
|
||||
if throughputHighestPutResults[i].Error != "" {
|
||||
errStr = throughputHighestPutResults[i].Error
|
||||
}
|
||||
if iopsHighestPutResults[i].Error != "" {
|
||||
errStr = iopsHighestPutResults[i].Error
|
||||
}
|
||||
result.PUTStats.Servers = append(result.PUTStats.Servers, madmin.SpeedTestStatServer{
|
||||
Endpoint: throughputHighestPutResults[i].Endpoint,
|
||||
ThroughputPerSec: throughputHighestPutResults[i].Uploads / uint64(durationSecs),
|
||||
ObjectsPerSec: iopsHighestPutResults[i].Uploads / uint64(iopsSize) / uint64(durationSecs),
|
||||
Err: errStr,
|
||||
})
|
||||
}
|
||||
|
||||
result.GETStats.ThroughputPerSec = throughputHighestGet / uint64(durationSecs)
|
||||
result.GETStats.ObjectsPerSec = iopsHighestGet / uint64(iopsSize) / uint64(durationSecs)
|
||||
for i := 0; i < len(throughputHighestGetResults); i++ {
|
||||
errStr := ""
|
||||
if throughputHighestGetResults[i].Error != "" {
|
||||
errStr = throughputHighestGetResults[i].Error
|
||||
}
|
||||
if iopsHighestGetResults[i].Error != "" {
|
||||
errStr = iopsHighestGetResults[i].Error
|
||||
}
|
||||
result.GETStats.Servers = append(result.GETStats.Servers, madmin.SpeedTestStatServer{
|
||||
Endpoint: throughputHighestGetResults[i].Endpoint,
|
||||
ThroughputPerSec: throughputHighestGetResults[i].Downloads / uint64(durationSecs),
|
||||
ObjectsPerSec: iopsHighestGetResults[i].Downloads / uint64(iopsSize) / uint64(durationSecs),
|
||||
Err: errStr,
|
||||
})
|
||||
}
|
||||
|
||||
numDisks := 0
|
||||
if pools, ok := objAPI.(*erasureServerPools); ok {
|
||||
for _, set := range pools.serverPools {
|
||||
numDisks = set.setCount * set.setDriveCount
|
||||
}
|
||||
}
|
||||
result.Disks = numDisks
|
||||
result.Servers = len(globalNotificationSys.peerClients) + 1
|
||||
result.Version = Version
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -159,10 +159,8 @@ func (p *xlStorageDiskIDCheck) Healing() *healingTracker {
|
||||
}
|
||||
|
||||
func (p *xlStorageDiskIDCheck) NSScanner(ctx context.Context, cache dataUsageCache, updates chan<- dataUsageEntry) (dataUsageCache, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return dataUsageCache{}, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -210,10 +208,8 @@ func (p *xlStorageDiskIDCheck) checkDiskStale() error {
|
||||
}
|
||||
|
||||
func (p *xlStorageDiskIDCheck) DiskInfo(ctx context.Context) (info DiskInfo, err error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return DiskInfo{}, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
info, err = p.storage.DiskInfo(ctx)
|
||||
@@ -235,10 +231,8 @@ func (p *xlStorageDiskIDCheck) DiskInfo(ctx context.Context) (info DiskInfo, err
|
||||
func (p *xlStorageDiskIDCheck) MakeVolBulk(ctx context.Context, volumes ...string) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricMakeVolBulk, volumes...)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -250,10 +244,8 @@ func (p *xlStorageDiskIDCheck) MakeVolBulk(ctx context.Context, volumes ...strin
|
||||
func (p *xlStorageDiskIDCheck) MakeVol(ctx context.Context, volume string) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricMakeVol, volume)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -265,10 +257,8 @@ func (p *xlStorageDiskIDCheck) MakeVol(ctx context.Context, volume string) (err
|
||||
func (p *xlStorageDiskIDCheck) ListVols(ctx context.Context) ([]VolInfo, error) {
|
||||
defer p.updateStorageMetrics(storageMetricListVols, "/")()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -280,10 +270,8 @@ func (p *xlStorageDiskIDCheck) ListVols(ctx context.Context) ([]VolInfo, error)
|
||||
func (p *xlStorageDiskIDCheck) StatVol(ctx context.Context, volume string) (vol VolInfo, err error) {
|
||||
defer p.updateStorageMetrics(storageMetricStatVol, volume)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return VolInfo{}, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -295,10 +283,8 @@ func (p *xlStorageDiskIDCheck) StatVol(ctx context.Context, volume string) (vol
|
||||
func (p *xlStorageDiskIDCheck) DeleteVol(ctx context.Context, volume string, forceDelete bool) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricDeleteVol, volume)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -310,10 +296,8 @@ func (p *xlStorageDiskIDCheck) DeleteVol(ctx context.Context, volume string, for
|
||||
func (p *xlStorageDiskIDCheck) ListDir(ctx context.Context, volume, dirPath string, count int) ([]string, error) {
|
||||
defer p.updateStorageMetrics(storageMetricListDir, volume, dirPath)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -326,10 +310,8 @@ func (p *xlStorageDiskIDCheck) ListDir(ctx context.Context, volume, dirPath stri
|
||||
func (p *xlStorageDiskIDCheck) ReadFile(ctx context.Context, volume string, path string, offset int64, buf []byte, verifier *BitrotVerifier) (n int64, err error) {
|
||||
defer p.updateStorageMetrics(storageMetricReadFile, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return 0, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -342,10 +324,8 @@ func (p *xlStorageDiskIDCheck) ReadFile(ctx context.Context, volume string, path
|
||||
func (p *xlStorageDiskIDCheck) AppendFile(ctx context.Context, volume string, path string, buf []byte) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricAppendFile, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -358,10 +338,8 @@ func (p *xlStorageDiskIDCheck) AppendFile(ctx context.Context, volume string, pa
|
||||
func (p *xlStorageDiskIDCheck) CreateFile(ctx context.Context, volume, path string, size int64, reader io.Reader) error {
|
||||
defer p.updateStorageMetrics(storageMetricCreateFile, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -374,10 +352,8 @@ func (p *xlStorageDiskIDCheck) CreateFile(ctx context.Context, volume, path stri
|
||||
func (p *xlStorageDiskIDCheck) ReadFileStream(ctx context.Context, volume, path string, offset, length int64) (io.ReadCloser, error) {
|
||||
defer p.updateStorageMetrics(storageMetricReadFileStream, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -390,10 +366,8 @@ func (p *xlStorageDiskIDCheck) ReadFileStream(ctx context.Context, volume, path
|
||||
func (p *xlStorageDiskIDCheck) RenameFile(ctx context.Context, srcVolume, srcPath, dstVolume, dstPath string) error {
|
||||
defer p.updateStorageMetrics(storageMetricRenameFile, srcVolume, srcPath, dstVolume, dstPath)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -406,10 +380,8 @@ func (p *xlStorageDiskIDCheck) RenameFile(ctx context.Context, srcVolume, srcPat
|
||||
func (p *xlStorageDiskIDCheck) RenameData(ctx context.Context, srcVolume, srcPath string, fi FileInfo, dstVolume, dstPath string) error {
|
||||
defer p.updateStorageMetrics(storageMetricRenameData, srcPath, fi.DataDir, dstVolume, dstPath)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -422,10 +394,8 @@ func (p *xlStorageDiskIDCheck) RenameData(ctx context.Context, srcVolume, srcPat
|
||||
func (p *xlStorageDiskIDCheck) CheckParts(ctx context.Context, volume string, path string, fi FileInfo) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricCheckParts, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -438,10 +408,8 @@ func (p *xlStorageDiskIDCheck) CheckParts(ctx context.Context, volume string, pa
|
||||
func (p *xlStorageDiskIDCheck) Delete(ctx context.Context, volume string, path string, recursive bool) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricDelete, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -464,13 +432,11 @@ func (p *xlStorageDiskIDCheck) DeleteVersions(ctx context.Context, volume string
|
||||
|
||||
errs = make([]error, len(versions))
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
for i := range errs {
|
||||
errs[i] = ctx.Err()
|
||||
}
|
||||
return errs
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -486,10 +452,8 @@ func (p *xlStorageDiskIDCheck) DeleteVersions(ctx context.Context, volume string
|
||||
func (p *xlStorageDiskIDCheck) VerifyFile(ctx context.Context, volume, path string, fi FileInfo) error {
|
||||
defer p.updateStorageMetrics(storageMetricVerifyFile, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err := p.checkDiskStale(); err != nil {
|
||||
@@ -502,10 +466,8 @@ func (p *xlStorageDiskIDCheck) VerifyFile(ctx context.Context, volume, path stri
|
||||
func (p *xlStorageDiskIDCheck) WriteAll(ctx context.Context, volume string, path string, b []byte) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricWriteAll, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -518,10 +480,8 @@ func (p *xlStorageDiskIDCheck) WriteAll(ctx context.Context, volume string, path
|
||||
func (p *xlStorageDiskIDCheck) DeleteVersion(ctx context.Context, volume, path string, fi FileInfo, forceDelMarker bool) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricDeleteVersion, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -534,10 +494,8 @@ func (p *xlStorageDiskIDCheck) DeleteVersion(ctx context.Context, volume, path s
|
||||
func (p *xlStorageDiskIDCheck) UpdateMetadata(ctx context.Context, volume, path string, fi FileInfo) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricUpdateMetadata, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -550,10 +508,8 @@ func (p *xlStorageDiskIDCheck) UpdateMetadata(ctx context.Context, volume, path
|
||||
func (p *xlStorageDiskIDCheck) WriteMetadata(ctx context.Context, volume, path string, fi FileInfo) (err error) {
|
||||
defer p.updateStorageMetrics(storageMetricWriteMetadata, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -566,10 +522,8 @@ func (p *xlStorageDiskIDCheck) WriteMetadata(ctx context.Context, volume, path s
|
||||
func (p *xlStorageDiskIDCheck) ReadVersion(ctx context.Context, volume, path, versionID string, readData bool) (fi FileInfo, err error) {
|
||||
defer p.updateStorageMetrics(storageMetricReadVersion, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return fi, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -582,10 +536,8 @@ func (p *xlStorageDiskIDCheck) ReadVersion(ctx context.Context, volume, path, ve
|
||||
func (p *xlStorageDiskIDCheck) ReadAll(ctx context.Context, volume string, path string) (buf []byte, err error) {
|
||||
defer p.updateStorageMetrics(storageMetricReadAll, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
@@ -598,10 +550,8 @@ func (p *xlStorageDiskIDCheck) ReadAll(ctx context.Context, volume string, path
|
||||
func (p *xlStorageDiskIDCheck) StatInfoFile(ctx context.Context, volume, path string) (stat StatInfo, err error) {
|
||||
defer p.updateStorageMetrics(storageStatInfoFile, volume, path)()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if contextCanceled(ctx) {
|
||||
return StatInfo{}, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
if err = p.checkDiskStale(); err != nil {
|
||||
|
||||
+31
-25
@@ -142,7 +142,8 @@ type xlStorage struct {
|
||||
sync.RWMutex
|
||||
|
||||
// mutex to prevent concurrent read operations overloading walks.
|
||||
walkMu sync.Mutex
|
||||
walkMu sync.Mutex
|
||||
walkReadMu sync.Mutex
|
||||
}
|
||||
|
||||
// checkPathLength - returns error if given path name length more than 255
|
||||
@@ -396,7 +397,11 @@ func (s *xlStorage) Healing() *healingTracker {
|
||||
return &h
|
||||
}
|
||||
|
||||
func (s *xlStorage) readMetadata(itemPath string) ([]byte, error) {
|
||||
func (s *xlStorage) readMetadata(ctx context.Context, itemPath string) ([]byte, error) {
|
||||
if contextCanceled(ctx) {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
if err := checkPathLength(itemPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -467,7 +472,7 @@ func (s *xlStorage) NSScanner(ctx context.Context, cache dataUsageCache, updates
|
||||
return sizeSummary{}, errSkipFile
|
||||
}
|
||||
|
||||
buf, err := s.readMetadata(item.Path)
|
||||
buf, err := s.readMetadata(ctx, item.Path)
|
||||
if err != nil {
|
||||
if intDataUpdateTracker.debug {
|
||||
console.Debugf(color.Green("scannerBucket:")+" object path missing: %v: %w\n", item.Path, err)
|
||||
@@ -790,6 +795,10 @@ func (s *xlStorage) DeleteVol(ctx context.Context, volume string, forceDelete bo
|
||||
// ListDir - return all the entries at the given directory path.
|
||||
// If an entry is a directory it will be returned with a trailing SlashSeparator.
|
||||
func (s *xlStorage) ListDir(ctx context.Context, volume, dirPath string, count int) (entries []string, err error) {
|
||||
if contextCanceled(ctx) {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
// Verify if volume is valid and it exists.
|
||||
volumeDir, err := s.getVolDir(volume)
|
||||
if err != nil {
|
||||
@@ -848,10 +857,13 @@ func (s *xlStorage) DeleteVersion(ctx context.Context, volume, path string, fi F
|
||||
// Create a new xl.meta with a delete marker in it
|
||||
return s.WriteMetadata(ctx, volume, path, fi)
|
||||
}
|
||||
if fi.VersionID != "" {
|
||||
return errFileVersionNotFound
|
||||
buf, err = s.ReadAll(ctx, volume, pathJoin(path, xlStorageFormatFileV1))
|
||||
if err != nil {
|
||||
if err == errFileNotFound && fi.VersionID != "" {
|
||||
return errFileVersionNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
return errFileNotFound
|
||||
}
|
||||
|
||||
if len(buf) == 0 {
|
||||
@@ -991,6 +1003,7 @@ func (s *xlStorage) WriteMetadata(ctx context.Context, volume, path string, fi F
|
||||
|
||||
var xlMeta xlMetaV2
|
||||
if !isXL2V1Format(buf) {
|
||||
// This is both legacy and without proper version.
|
||||
err = xlMeta.AddVersion(fi)
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
@@ -1006,7 +1019,8 @@ func (s *xlStorage) WriteMetadata(ctx context.Context, volume, path string, fi F
|
||||
} else {
|
||||
if err = xlMeta.Load(buf); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
return err
|
||||
// Corrupted data, reset and write.
|
||||
xlMeta = xlMetaV2{}
|
||||
}
|
||||
|
||||
if err = xlMeta.AddVersion(fi); err != nil {
|
||||
@@ -1087,7 +1101,7 @@ func (s *xlStorage) ReadVersion(ctx context.Context, volume, path, versionID str
|
||||
if readData {
|
||||
buf, err = s.ReadAll(ctx, volume, pathJoin(path, xlStorageFormatFile))
|
||||
} else {
|
||||
buf, err = s.readMetadata(pathJoin(volumeDir, path, xlStorageFormatFile))
|
||||
buf, err = s.readMetadata(ctx, pathJoin(volumeDir, path, xlStorageFormatFile))
|
||||
if err != nil {
|
||||
if osIsNotExist(err) {
|
||||
if err = Access(volumeDir); err != nil && osIsNotExist(err) {
|
||||
@@ -1100,16 +1114,7 @@ func (s *xlStorage) ReadVersion(ctx context.Context, volume, path, versionID str
|
||||
|
||||
if err != nil {
|
||||
if err == errFileNotFound {
|
||||
if err = s.renameLegacyMetadata(volumeDir, path); err != nil {
|
||||
if err == errFileNotFound {
|
||||
if versionID != "" {
|
||||
return fi, errFileVersionNotFound
|
||||
}
|
||||
return fi, errFileNotFound
|
||||
}
|
||||
return fi, err
|
||||
}
|
||||
buf, err = s.ReadAll(ctx, volume, pathJoin(path, xlStorageFormatFile))
|
||||
buf, err = s.ReadAll(ctx, volume, pathJoin(path, xlStorageFormatFileV1))
|
||||
if err != nil {
|
||||
if err == errFileNotFound {
|
||||
if versionID != "" {
|
||||
@@ -1982,7 +1987,8 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f
|
||||
if isXL2V1Format(dstBuf) {
|
||||
if err = xlMeta.Load(dstBuf); err != nil {
|
||||
logger.LogIf(s.ctx, err)
|
||||
return err
|
||||
// Data appears corrupt. Drop data.
|
||||
xlMeta = xlMetaV2{}
|
||||
}
|
||||
} else {
|
||||
// This code-path is to preserve the legacy data.
|
||||
@@ -1990,13 +1996,13 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
if err := json.Unmarshal(dstBuf, xlMetaLegacy); err != nil {
|
||||
logger.LogIf(s.ctx, err)
|
||||
return errFileCorrupt
|
||||
// Data appears corrupt. Drop data.
|
||||
} else {
|
||||
if err = xlMeta.AddLegacy(xlMetaLegacy); err != nil {
|
||||
logger.LogIf(s.ctx, err)
|
||||
}
|
||||
legacyPreserved = true
|
||||
}
|
||||
if err = xlMeta.AddLegacy(xlMetaLegacy); err != nil {
|
||||
logger.LogIf(s.ctx, err)
|
||||
return errFileCorrupt
|
||||
}
|
||||
legacyPreserved = true
|
||||
}
|
||||
} else {
|
||||
s.RLock()
|
||||
|
||||
@@ -1834,7 +1834,7 @@ func TestXLStorageReadMetadata(t *testing.T) {
|
||||
}
|
||||
|
||||
disk.MakeVol(context.Background(), volume)
|
||||
if _, err := disk.readMetadata(pathJoin(tmpDir, volume, object)); err != errFileNameTooLong {
|
||||
if _, err := disk.readMetadata(context.Background(), pathJoin(tmpDir, volume, object)); err != errFileNameTooLong {
|
||||
t.Fatalf("Unexpected error from readMetadata - expect %v: got %v", errFileNameTooLong, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
set -e
|
||||
|
||||
if [ ! -x "/usr/bin/minio" ]; then
|
||||
if [ ! -x "/opt/bin/minio" ]; then
|
||||
echo "minio executable binary not found refusing to proceed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
verify_sha256sum() {
|
||||
echo "verifying binary checksum"
|
||||
echo "$(awk '{print $1}' /usr/bin/minio.sha256sum) /usr/bin/minio" | sha256sum -c
|
||||
echo "$(awk '{print $1}' /opt/bin/minio.sha256sum) /opt/bin/minio" | sha256sum -c
|
||||
}
|
||||
|
||||
verify_signature() {
|
||||
@@ -19,7 +19,7 @@ verify_signature() {
|
||||
return
|
||||
fi
|
||||
echo "verifying binary signature"
|
||||
minisign -VQm /usr/bin/minio -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
|
||||
minisign -VQm /opt/bin/minio -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
@@ -1539,7 +1539,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "sum by (server,api) (rate(minio_s3_requests_total{job=\"$scrape_jobs\"}[$__rate_interval]))",
|
||||
"expr": "sum by (server,api) (increase(minio_s3_requests_total{job=\"$scrape_jobs\"}[$__rate_interval]))",
|
||||
"interval": "1m",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{server,api}}",
|
||||
@@ -1635,7 +1635,7 @@
|
||||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "rate(minio_s3_requests_errors_total{job=\"$scrape_jobs\"}[$__rate_interval])",
|
||||
"expr": "sum by (server,api) (increase(minio_s3_requests_errors_total{job=\"$scrape_jobs\"}[$__rate_interval]))",
|
||||
"interval": "1m",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{server,api}}",
|
||||
@@ -2671,4 +2671,4 @@
|
||||
"title": "MinIO Overview",
|
||||
"uid": "TgmJnqnnk",
|
||||
"version": 18
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3.7'
|
||||
|
||||
# Settings and configurations that are common for all containers
|
||||
x-minio-common: &minio-common
|
||||
image: quay.io/minio/minio:RELEASE.2021-09-03T03-56-13Z
|
||||
image: quay.io/minio/minio:RELEASE.2021-09-15T04-54-25Z
|
||||
command: server --console-address ":9001" http://minio{1...4}/data{1...2}
|
||||
expose:
|
||||
- "9000"
|
||||
|
||||
@@ -16,6 +16,14 @@ The OAuth 2.0 id_token that is provided by the web identity provider. Applicatio
|
||||
| *Length Constraints* | *Minimum length of 4. Maximum length of 2048.* |
|
||||
| *Required* | *Yes* |
|
||||
|
||||
### WebIdentityAccessToken (MinIO Extension)
|
||||
There are situations when identity provider does not provide user claims in `id_token` instead it needs to be retrieved from UserInfo endpoint, this extension is only useful in this scenario. This is rare so use it accordingly depending on your Identity provider implementation. `access_token` is available as part of the OIDC authentication flow similar to `id_token`.
|
||||
|
||||
| Params | Value |
|
||||
| :-- | :-- |
|
||||
| *Type* | *String* |
|
||||
| *Required* | *No* |
|
||||
|
||||
### Version
|
||||
Indicates STS API version information, the only supported value is '2011-06-15'. This value is borrowed from AWS STS API documentation for compatibility reasons.
|
||||
|
||||
|
||||
@@ -41,14 +41,14 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/miekg/dns v1.1.35
|
||||
github.com/minio/cli v1.22.0
|
||||
github.com/minio/console v0.9.8
|
||||
github.com/minio/console v0.10.0
|
||||
github.com/minio/csvparser v1.0.0
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/minio/kes v0.14.0
|
||||
github.com/minio/madmin-go v1.1.0
|
||||
github.com/minio/minio-go/v7 v7.0.14-0.20210908194250-617d530ffac5
|
||||
github.com/minio/madmin-go v1.1.6-0.20210917204419-f12dc0d0a8bd
|
||||
github.com/minio/minio-go/v7 v7.0.15-0.20210917235750-a16dfb14e6f6
|
||||
github.com/minio/parquet-go v1.0.0
|
||||
github.com/minio/pkg v1.1.2
|
||||
github.com/minio/pkg v1.1.3
|
||||
github.com/minio/selfupdate v0.3.1
|
||||
github.com/minio/sha256-simd v1.0.0
|
||||
github.com/minio/simdjson-go v0.2.1
|
||||
@@ -68,7 +68,7 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.8.0
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/prometheus/procfs v0.6.0
|
||||
github.com/prometheus/procfs v0.7.3
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/secure-io/sio-go v0.3.1
|
||||
github.com/shirou/gopsutil/v3 v3.21.7
|
||||
|
||||
@@ -235,8 +235,6 @@ github.com/cockroachdb/cockroach-go/v2 v2.0.3 h1:ZA346ACHIZctef6trOTwBAEvPVm1k0u
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.0.3/go.mod h1:hAuDgiVgDVkfirP9JnhXEfcXEPRKBpYdGz+l7mvYSzw=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
|
||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||
github.com/colinmarc/hdfs/v2 v2.2.0 h1:4AaIlTq+/sWmeqYhI0dX8bD4YrMQM990tRjm636FkGM=
|
||||
github.com/colinmarc/hdfs/v2 v2.2.0/go.mod h1:Wss6n3mtaZyRwWaqtSH+6ge01qT0rw9dJJmvoUnIQ/E=
|
||||
github.com/container-storage-interface/spec v1.1.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
|
||||
@@ -1009,8 +1007,8 @@ github.com/minio/cli v1.22.0 h1:VTQm7lmXm3quxO917X3p+el1l0Ca5X3S4PM2ruUYO68=
|
||||
github.com/minio/cli v1.22.0/go.mod h1:bYxnK0uS629N3Bq+AOZZ+6lwF77Sodk4+UL9vNuXhOY=
|
||||
github.com/minio/colorjson v1.0.1 h1:+hvfP8C1iMB95AT+ZFDRE+Knn9QPd9lg0CRJY9DRpos=
|
||||
github.com/minio/colorjson v1.0.1/go.mod h1:oPM3zQQY8Gz9NGtgvuBEjQ+gPZLKAGc7T+kjMlwtOgs=
|
||||
github.com/minio/console v0.9.8 h1:a3qrusK5EEAdL2o+fqOTECgSn2gf7QADatnpa+5IcAs=
|
||||
github.com/minio/console v0.9.8/go.mod h1:OWT3/G+s2/Umrvz4+DjUoyChdf4PjDwkVmJ93RezRG4=
|
||||
github.com/minio/console v0.10.0 h1:P1uxtmdIUAnLTlXJQtUFf/sGcKHlKNjFw1JGgt+8wZE=
|
||||
github.com/minio/console v0.10.0/go.mod h1:RO83E/L1fC/Cb8i+M/RZabBz5/m/AF5RJylKWlyk/Kw=
|
||||
github.com/minio/csvparser v1.0.0 h1:xJEHcYK8ZAjeW4hNV9Zu30u+/2o4UyPnYgyjWp8b7ZU=
|
||||
github.com/minio/csvparser v1.0.0/go.mod h1:lKXskSLzPgC5WQyzP7maKH7Sl1cqvANXo9YCto8zbtM=
|
||||
github.com/minio/direct-csi v1.3.5-0.20210601185811-f7776f7961bf h1:wylCc/PdvdTIqYqVNEU9LJAZBanvfGY1TwTnjM3zQaA=
|
||||
@@ -1024,9 +1022,9 @@ github.com/minio/kes v0.11.0/go.mod h1:mTF1Bv8YVEtQqF/B7Felp4tLee44Pp+dgI0rhCvgN
|
||||
github.com/minio/kes v0.14.0 h1:plCGm4LwR++T1P1sXsJbyFRX54CE1WRuo9PAPj6MC3Q=
|
||||
github.com/minio/kes v0.14.0/go.mod h1:OUensXz2BpgMfiogslKxv7Anyx/wj+6bFC6qA7BQcfA=
|
||||
github.com/minio/madmin-go v1.0.12/go.mod h1:BK+z4XRx7Y1v8SFWXsuLNqQqnq5BO/axJ8IDJfgyvfs=
|
||||
github.com/minio/madmin-go v1.0.17/go.mod h1:4nl9hvLWFnwCjkLfZSsZXEHgDODa2XSG6xGlIZyQ2oA=
|
||||
github.com/minio/madmin-go v1.1.0 h1:Y7YOPQafIVBpW0kwYzlt7FGi0GV23dlr/u3jRRrB4cw=
|
||||
github.com/minio/madmin-go v1.1.0/go.mod h1:4nl9hvLWFnwCjkLfZSsZXEHgDODa2XSG6xGlIZyQ2oA=
|
||||
github.com/minio/madmin-go v1.1.5/go.mod h1:xIPJHUbyYhNDgeD9Wov5Fz5/p7DIW0u+q6Rs/+Xu2TM=
|
||||
github.com/minio/madmin-go v1.1.6-0.20210917204419-f12dc0d0a8bd h1:NRQh43NGG+GThP26HufDWUp6pNhR1anfG7phaUDxYMk=
|
||||
github.com/minio/madmin-go v1.1.6-0.20210917204419-f12dc0d0a8bd/go.mod h1:vw+c3/u+DeVKqReEavo///Cl2OO8nt5s4ee843hJeLs=
|
||||
github.com/minio/mc v0.0.0-20210626002108-cebf3318546f h1:hyFvo5hSFw2K417YvDr/vAKlgCG69uTuhZW/5LNdL0U=
|
||||
github.com/minio/mc v0.0.0-20210626002108-cebf3318546f/go.mod h1:tuaonkPjVApCXkbtKENHBtsqUf7YTV33qmFrC+Pgp5g=
|
||||
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
|
||||
@@ -1035,9 +1033,9 @@ github.com/minio/md5-simd v1.1.1/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77Z
|
||||
github.com/minio/minio-go/v7 v7.0.10/go.mod h1:td4gW1ldOsj1PbSNS+WYK43j+P1XVhX/8W8awaYlBFo=
|
||||
github.com/minio/minio-go/v7 v7.0.11-0.20210302210017-6ae69c73ce78/go.mod h1:mTh2uJuAbEqdhMVl6CMIIZLUeiMiWtJR4JB8/5g2skw=
|
||||
github.com/minio/minio-go/v7 v7.0.11-0.20210607181445-e162fdb8e584/go.mod h1:WoyW+ySKAKjY98B9+7ZbI8z8S3jaxaisdcvj9TGlazA=
|
||||
github.com/minio/minio-go/v7 v7.0.13-0.20210715203016-9e713532886e/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs=
|
||||
github.com/minio/minio-go/v7 v7.0.14-0.20210908194250-617d530ffac5 h1:c6okzYcdOLPP9tHoOE/JxiWi5qSQpvFC6VqbA4FB/Iw=
|
||||
github.com/minio/minio-go/v7 v7.0.14-0.20210908194250-617d530ffac5/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs=
|
||||
github.com/minio/minio-go/v7 v7.0.14/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs=
|
||||
github.com/minio/minio-go/v7 v7.0.15-0.20210917235750-a16dfb14e6f6 h1:vkarc8wO5ozZavEJilw4O3gzhPRJFEkHxCzZU8f+PiE=
|
||||
github.com/minio/minio-go/v7 v7.0.15-0.20210917235750-a16dfb14e6f6/go.mod h1:X6NObIqnx2xvri7kLQSDB3GD1Nt0vtF9WG5oMVEKhLc=
|
||||
github.com/minio/operator v0.0.0-20210812082324-26350f153661 h1:dGAJHpfmhNukFg0M0wDqH+G1OB2YPgZCcT6uv4n9YQk=
|
||||
github.com/minio/operator v0.0.0-20210812082324-26350f153661/go.mod h1:zQqn6VGT46xlSpVXh1I/VZRv+eSgHtVu6URdg71YKX8=
|
||||
github.com/minio/operator/logsearchapi v0.0.0-20210812082324-26350f153661 h1:tJw15hS3b1dVTf5PwA4roXZ/oRNnHyZ/8Y+yNTmQ5rA=
|
||||
@@ -1047,8 +1045,8 @@ github.com/minio/parquet-go v1.0.0/go.mod h1:aQlkSOfOq2AtQKkuou3mosNVMwNokd+faTa
|
||||
github.com/minio/pkg v1.0.3/go.mod h1:obU54TZ9QlMv0TRaDgQ/JTzf11ZSXxnSfLrm4tMtBP8=
|
||||
github.com/minio/pkg v1.0.4/go.mod h1:obU54TZ9QlMv0TRaDgQ/JTzf11ZSXxnSfLrm4tMtBP8=
|
||||
github.com/minio/pkg v1.0.8/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
|
||||
github.com/minio/pkg v1.1.2 h1:A7zSlVIQCf71DPYM1kqBpybq6fmsRY3RuTMD0ZNcqZA=
|
||||
github.com/minio/pkg v1.1.2/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
|
||||
github.com/minio/pkg v1.1.3 h1:J4vGnlNSxc/o9gDOQMZ3k0L3koA7ZgBQ7GRMrUpt/OY=
|
||||
github.com/minio/pkg v1.1.3/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
|
||||
github.com/minio/selfupdate v0.3.1 h1:BWEFSNnrZVMUWXbXIgLDNDjbejkmpAmZvy/nCz1HlEs=
|
||||
github.com/minio/selfupdate v0.3.1/go.mod h1:b8ThJzzH7u2MkF6PcIra7KaXO9Khf6alWPvMSyTDCFM=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
@@ -1256,8 +1254,9 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
|
||||
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k=
|
||||
@@ -1423,10 +1422,12 @@ github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4A
|
||||
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
|
||||
github.com/unrolled/secure v1.0.7 h1:BcQHp3iKZyZCKj5gRqwQG+5urnGBF00wGgoPPwtheVQ=
|
||||
github.com/unrolled/secure v1.0.7/go.mod h1:uGc1OcRF8gCVBA+ANksKmvM85Hka6SZtQIbrKc3sHS4=
|
||||
github.com/unrolled/secure v1.0.9 h1:BWRuEb1vDrBFFDdbCnKkof3gZ35I/bnHGyt0LB0TNyQ=
|
||||
github.com/unrolled/secure v1.0.9/go.mod h1:fO+mEan+FLB0CdEnHf6Q4ZZVNqG+5fuLFnP8p0BXDPI=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
|
||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||
github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,8 +1,8 @@
|
||||
apiVersion: v1
|
||||
description: Multi-Cloud Object Storage
|
||||
name: minio
|
||||
version: 3.0.2
|
||||
appVersion: RELEASE.2021-09-03T03-56-13Z
|
||||
version: 3.1.3
|
||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||
keywords:
|
||||
- minio
|
||||
- storage
|
||||
|
||||
@@ -91,6 +91,10 @@ spec:
|
||||
secretKeyRef:
|
||||
name: {{ template "minio.secretName" . }}
|
||||
key: rootPassword
|
||||
{{- if .Values.metrics.serviceMonitor.public }}
|
||||
- name: MINIO_PROMETHEUS_AUTH_TYPE
|
||||
value: "public"
|
||||
{{- end}}
|
||||
{{- range $key, $val := .Values.environment }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $val | quote }}
|
||||
|
||||
@@ -91,6 +91,10 @@ spec:
|
||||
secretKeyRef:
|
||||
name: {{ template "minio.secretName" . }}
|
||||
key: rootPassword
|
||||
{{- if .Values.metrics.serviceMonitor.public }}
|
||||
- name: MINIO_PROMETHEUS_AUTH_TYPE
|
||||
value: "public"
|
||||
{{- end}}
|
||||
{{- range $key, $val := .Values.environment }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $val | quote }}
|
||||
|
||||
@@ -32,13 +32,13 @@ spec:
|
||||
{{- include "minio.imagePullSecrets" . | indent 6 }}
|
||||
{{- if .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.nodeSelector | indent 8 }}
|
||||
{{ toYaml .Values.makeBucketJob.nodeSelector | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
{{- with .Values.makeBucketJob.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
{{- with .Values.makeBucketJob.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -32,13 +32,13 @@ spec:
|
||||
{{- include "minio.imagePullSecrets" . | indent 6 }}
|
||||
{{- if .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.nodeSelector | indent 8 }}
|
||||
{{ toYaml .Values.makeUserJob.nodeSelector | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
{{- with .Values.makeUserJob.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
{{- with .Values.makeUserJob.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -11,6 +11,7 @@ metadata:
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
monitoring: true
|
||||
{{- if .Values.service.annotations }}
|
||||
annotations:
|
||||
{{ toYaml .Values.service.annotations | indent 4 }}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .Values.serviceAccount.name | quote }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,44 @@
|
||||
{{- if .Values.metrics.serviceMonitor.enabled }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
{{- if .Values.metrics.serviceMonitor.namespace }}
|
||||
namespace: {{ .Values.metrics.serviceMonitor.namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.metrics.serviceMonitor.additionalLabels }}
|
||||
{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
endpoints:
|
||||
{{- if .Values.tls.enabled }}
|
||||
- port: https
|
||||
{{ else }}
|
||||
- port: http
|
||||
{{- end }}
|
||||
path: /minio/v2/metrics/cluster
|
||||
{{- if .Values.metrics.serviceMonitor.interval }}
|
||||
interval: {{ .Values.metrics.serviceMonitor.interval }}
|
||||
{{- end }}
|
||||
{{- if .Values.metrics.serviceMonitor.scrapeTimeout }}
|
||||
scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }}
|
||||
{{- end }}
|
||||
{{- if not .Values.metrics.serviceMonitor.public }}
|
||||
bearerTokenSecret:
|
||||
name: {{ template "minio.fullname" . }}-prometheus
|
||||
key: token
|
||||
{{- end }}
|
||||
namespaceSelector:
|
||||
matchNames:
|
||||
- {{ .Release.Namespace | quote }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ include "minio.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
monitoring: true
|
||||
{{- end }}
|
||||
@@ -127,6 +127,10 @@ spec:
|
||||
secretKeyRef:
|
||||
name: {{ template "minio.secretName" . }}
|
||||
key: rootPassword
|
||||
{{- if .Values.metrics.serviceMonitor.public }}
|
||||
- name: MINIO_PROMETHEUS_AUTH_TYPE
|
||||
value: "public"
|
||||
{{- end}}
|
||||
{{- range $key, $val := .Values.environment }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $val | quote }}
|
||||
|
||||
+25
-2
@@ -14,7 +14,7 @@ clusterDomain: cluster.local
|
||||
##
|
||||
image:
|
||||
repository: quay.io/minio/minio
|
||||
tag: RELEASE.2021-08-31T05-46-54Z
|
||||
tag: RELEASE.2021-09-09T21-37-07Z
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
imagePullSecrets: []
|
||||
@@ -25,7 +25,7 @@ imagePullSecrets: []
|
||||
##
|
||||
mcImage:
|
||||
repository: quay.io/minio/mc
|
||||
tag: RELEASE.2021-07-27T06-46-19Z
|
||||
tag: RELEASE.2021-09-02T09-21-27Z
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
## minio mode, i.e. standalone or distributed or gateway (nas)
|
||||
@@ -269,6 +269,9 @@ makeUserJob:
|
||||
resources:
|
||||
requests:
|
||||
memory: 128Mi
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
## List of buckets to be created after minio install
|
||||
##
|
||||
@@ -300,6 +303,9 @@ makeBucketJob:
|
||||
resources:
|
||||
requests:
|
||||
memory: 128Mi
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
## Use this field to add environment variables relevant to MinIO server. These fields will be passed on to MinIO container(s)
|
||||
## when Chart is deployed
|
||||
@@ -318,3 +324,20 @@ networkPolicy:
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
maxUnavailable: 1
|
||||
|
||||
## Specify the service account to use for the Minio pods. If 'create' is set to 'false'
|
||||
## and 'name' is left unspecified, the account 'default' will be used.
|
||||
serviceAccount:
|
||||
create: true
|
||||
## The name of the service account to use. If 'create' is 'true', a service account with that name
|
||||
## will be created.
|
||||
name: "minio-sa"
|
||||
|
||||
metrics:
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
additionalLabels: {}
|
||||
public: true
|
||||
# namespace: monitoring
|
||||
# interval: 30s
|
||||
# scrapeTimeout: 10s
|
||||
|
||||
+100
-12
@@ -1,9 +1,97 @@
|
||||
apiVersion: v1
|
||||
entries:
|
||||
minio:
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||
created: "2021-09-18T11:09:19.784517792-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: e2eb34d31560b012ef6581f0ff6004ea4376c968cbe0daed2d8f3a614a892afb
|
||||
home: https://min.io
|
||||
icon: https://min.io/resources/img/logo/MINIO_wordmark.png
|
||||
keywords:
|
||||
- minio
|
||||
- storage
|
||||
- object-storage
|
||||
- s3
|
||||
- cluster
|
||||
maintainers:
|
||||
- email: dev@minio.io
|
||||
name: MinIO, Inc
|
||||
name: minio
|
||||
sources:
|
||||
- https://github.com/minio/minio
|
||||
urls:
|
||||
- https://charts.min.io/helm-releases/minio-3.1.3.tgz
|
||||
version: 3.1.3
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||
created: "2021-09-18T11:09:19.783159245-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: 8d7e0cc46b3583abd71b97dc0c071f98321101f90eca17348f1e9e0831be64cd
|
||||
home: https://min.io
|
||||
icon: https://min.io/resources/img/logo/MINIO_wordmark.png
|
||||
keywords:
|
||||
- minio
|
||||
- storage
|
||||
- object-storage
|
||||
- s3
|
||||
- cluster
|
||||
maintainers:
|
||||
- email: dev@minio.io
|
||||
name: MinIO, Inc
|
||||
name: minio
|
||||
sources:
|
||||
- https://github.com/minio/minio
|
||||
urls:
|
||||
- https://charts.min.io/helm-releases/minio-3.1.2.tgz
|
||||
version: 3.1.2
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||
created: "2021-09-18T11:09:19.781808732-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: 50dcbf366b1b21f4a6fc429d0b884c0c7ff481d0fb95c5e9b3ae157c348dd124
|
||||
home: https://min.io
|
||||
icon: https://min.io/resources/img/logo/MINIO_wordmark.png
|
||||
keywords:
|
||||
- minio
|
||||
- storage
|
||||
- object-storage
|
||||
- s3
|
||||
- cluster
|
||||
maintainers:
|
||||
- email: dev@minio.io
|
||||
name: MinIO, Inc
|
||||
name: minio
|
||||
sources:
|
||||
- https://github.com/minio/minio
|
||||
urls:
|
||||
- https://charts.min.io/helm-releases/minio-3.1.1.tgz
|
||||
version: 3.1.1
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||
created: "2021-09-18T11:09:19.780480041-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: 6c01af55d2e2e5f716eabf6fef3a92a8464d0674529e9bacab292e5478a73b7a
|
||||
home: https://min.io
|
||||
icon: https://min.io/resources/img/logo/MINIO_wordmark.png
|
||||
keywords:
|
||||
- minio
|
||||
- storage
|
||||
- object-storage
|
||||
- s3
|
||||
- cluster
|
||||
maintainers:
|
||||
- email: dev@minio.io
|
||||
name: MinIO, Inc
|
||||
name: minio
|
||||
sources:
|
||||
- https://github.com/minio/minio
|
||||
urls:
|
||||
- https://charts.min.io/helm-releases/minio-3.1.0.tgz
|
||||
version: 3.1.0
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-09-03T03-56-13Z
|
||||
created: "2021-09-03T01:09:29.388403323-07:00"
|
||||
created: "2021-09-18T11:09:19.779152969-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: 18e10be4d0458bc590ca9abf753227e0c70f60511495387b8d4fb15a4daf932e
|
||||
home: https://min.io
|
||||
@@ -25,7 +113,7 @@ entries:
|
||||
version: 3.0.2
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-31T05-46-54Z
|
||||
created: "2021-09-03T01:09:29.387118116-07:00"
|
||||
created: "2021-09-18T11:09:19.777829583-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: f5b6e7f6272a9e71aef3b75555f6f756a39eef65cb78873f26451dba79b19906
|
||||
home: https://min.io
|
||||
@@ -47,7 +135,7 @@ entries:
|
||||
version: 3.0.1
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-31T05-46-54Z
|
||||
created: "2021-09-03T01:09:29.385781377-07:00"
|
||||
created: "2021-09-18T11:09:19.776560129-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: 6d2ee1336c412affaaf209fdb80215be2a6ebb23ab2443adbaffef9e7df13fab
|
||||
home: https://min.io
|
||||
@@ -69,7 +157,7 @@ entries:
|
||||
version: 3.0.0
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-31T05-46-54Z
|
||||
created: "2021-09-03T01:09:29.384488334-07:00"
|
||||
created: "2021-09-18T11:09:19.775292754-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: 0a004aaf5bb61deed6a5c88256d1695ebe2f9ff1553874a93e4acfd75e8d339b
|
||||
home: https://min.io
|
||||
@@ -89,7 +177,7 @@ entries:
|
||||
version: 2.0.1
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-25T00-41-18Z
|
||||
created: "2021-09-03T01:09:29.383253644-07:00"
|
||||
created: "2021-09-18T11:09:19.774019915-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: fcd944e837ee481307de6aa3d387ea18c234f995a84c15abb211aab4a4054afc
|
||||
home: https://min.io
|
||||
@@ -109,7 +197,7 @@ entries:
|
||||
version: 2.0.0
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-25T00-41-18Z
|
||||
created: "2021-09-03T01:09:29.381940948-07:00"
|
||||
created: "2021-09-18T11:09:19.77274584-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: 7b6c033d43a856479eb493ab8ca05b230f77c3e42e209e8f298fac6af1a9796f
|
||||
home: https://min.io
|
||||
@@ -129,7 +217,7 @@ entries:
|
||||
version: 1.0.5
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-25T00-41-18Z
|
||||
created: "2021-09-03T01:09:29.380699554-07:00"
|
||||
created: "2021-09-18T11:09:19.771503286-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: abd221245ace16c8e0c6c851cf262d1474a5219dcbf25c4b2e7b77142f9c59ed
|
||||
home: https://min.io
|
||||
@@ -149,7 +237,7 @@ entries:
|
||||
version: 1.0.4
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-20T18-32-01Z
|
||||
created: "2021-09-03T01:09:29.379449808-07:00"
|
||||
created: "2021-09-18T11:09:19.770181318-07:00"
|
||||
description: Multi-Cloud Object Storage
|
||||
digest: 922a333f5413d1042f7aa81929f43767f6ffca9b260c46713f04ce1dda86d57d
|
||||
home: https://min.io
|
||||
@@ -169,7 +257,7 @@ entries:
|
||||
version: 1.0.3
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-20T18-32-01Z
|
||||
created: "2021-09-03T01:09:29.378188621-07:00"
|
||||
created: "2021-09-18T11:09:19.768938823-07:00"
|
||||
description: High Performance, Kubernetes Native Object Storage
|
||||
digest: 10e22773506bbfb1c66442937956534cf4057b94f06a977db78b8cd223588388
|
||||
home: https://min.io
|
||||
@@ -189,7 +277,7 @@ entries:
|
||||
version: 1.0.2
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-20T18-32-01Z
|
||||
created: "2021-09-03T01:09:29.376910712-07:00"
|
||||
created: "2021-09-18T11:09:19.767654948-07:00"
|
||||
description: High Performance, Kubernetes Native Object Storage
|
||||
digest: ef86ab6df23d6942705da9ef70991b649638c51bc310587d37a425268ba4a06c
|
||||
home: https://min.io
|
||||
@@ -209,7 +297,7 @@ entries:
|
||||
version: 1.0.1
|
||||
- apiVersion: v1
|
||||
appVersion: RELEASE.2021-08-17T20-53-08Z
|
||||
created: "2021-09-03T01:09:29.375397146-07:00"
|
||||
created: "2021-09-18T11:09:19.766373493-07:00"
|
||||
description: High Performance, Kubernetes Native Object Storage
|
||||
digest: 1add7608692cbf39aaf9b1252530e566f7b2f306a14e390b0f49b97a20f2b188
|
||||
home: https://min.io
|
||||
@@ -227,4 +315,4 @@ entries:
|
||||
urls:
|
||||
- https://charts.min.io/helm-releases/minio-1.0.0.tgz
|
||||
version: 1.0.0
|
||||
generated: "2021-09-03T01:09:28.813520489-07:00"
|
||||
generated: "2021-09-18T11:09:18.610084677-07:00"
|
||||
|
||||
@@ -58,6 +58,7 @@ const (
|
||||
RegionName = "name"
|
||||
AccessKey = "access_key"
|
||||
SecretKey = "secret_key"
|
||||
License = "license"
|
||||
)
|
||||
|
||||
// Top level config constants.
|
||||
@@ -79,6 +80,7 @@ const (
|
||||
HealSubSys = "heal"
|
||||
ScannerSubSys = "scanner"
|
||||
CrawlerSubSys = "crawler"
|
||||
SubnetSubSys = "subnet"
|
||||
|
||||
// Add new constants here if you add new fields to config.
|
||||
)
|
||||
@@ -127,6 +129,7 @@ var SubSystems = set.CreateStringSet(
|
||||
NotifyPostgresSubSys,
|
||||
NotifyRedisSubSys,
|
||||
NotifyWebhookSubSys,
|
||||
SubnetSubSys,
|
||||
)
|
||||
|
||||
// SubSystemsDynamic - all sub-systems that have dynamic config.
|
||||
@@ -135,6 +138,7 @@ var SubSystemsDynamic = set.CreateStringSet(
|
||||
CompressionSubSys,
|
||||
ScannerSubSys,
|
||||
HealSubSys,
|
||||
SubnetSubSys,
|
||||
)
|
||||
|
||||
// SubSystemsSingleTargets - subsystems which only support single target.
|
||||
|
||||
@@ -44,15 +44,21 @@ var (
|
||||
Optional: true,
|
||||
Type: "string",
|
||||
},
|
||||
config.HelpKV{
|
||||
Key: ClaimUserinfo,
|
||||
Description: `Enable fetching claims from UserInfo Endpoint for authenticated user`,
|
||||
Optional: true,
|
||||
Type: "on|off",
|
||||
},
|
||||
config.HelpKV{
|
||||
Key: ClaimPrefix,
|
||||
Description: `JWT claim namespace prefix e.g. "customer1/"`,
|
||||
Description: `[DEPRECATED use 'claim_name'] JWT claim namespace prefix e.g. "customer1/"`,
|
||||
Optional: true,
|
||||
Type: "string",
|
||||
},
|
||||
config.HelpKV{
|
||||
Key: RedirectURI,
|
||||
Description: `Configure custom redirect_uri for OpenID login flow callback`,
|
||||
Description: `[DEPRECATED use env 'MINIO_BROWSER_REDIRECT_URL'] Configure custom redirect_uri for OpenID login flow callback`,
|
||||
Optional: true,
|
||||
Type: "string",
|
||||
},
|
||||
|
||||
@@ -47,13 +47,14 @@ type Config struct {
|
||||
JWKS struct {
|
||||
URL *xnet.URL `json:"url"`
|
||||
} `json:"jwks"`
|
||||
URL *xnet.URL `json:"url,omitempty"`
|
||||
ClaimPrefix string `json:"claimPrefix,omitempty"`
|
||||
ClaimName string `json:"claimName,omitempty"`
|
||||
RedirectURI string `json:"redirectURI,omitempty"`
|
||||
DiscoveryDoc DiscoveryDoc
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
URL *xnet.URL `json:"url,omitempty"`
|
||||
ClaimPrefix string `json:"claimPrefix,omitempty"`
|
||||
ClaimName string `json:"claimName,omitempty"`
|
||||
ClaimUserinfo bool `json:"claimUserInfo,omitempty"`
|
||||
RedirectURI string `json:"redirectURI,omitempty"`
|
||||
DiscoveryDoc DiscoveryDoc
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
|
||||
provider provider.Provider
|
||||
publicKeys map[string]crypto.PublicKey
|
||||
@@ -61,6 +62,63 @@ type Config struct {
|
||||
closeRespFn func(io.ReadCloser)
|
||||
}
|
||||
|
||||
// UserInfo returns claims for authenticated user from userInfo endpoint.
|
||||
//
|
||||
// Some OIDC implementations such as GitLab do not support
|
||||
// claims as part of the normal oauth2 flow, instead rely
|
||||
// on service providers making calls to IDP to fetch additional
|
||||
// claims available from the UserInfo endpoint
|
||||
func (r *Config) UserInfo(accessToken string) (map[string]interface{}, error) {
|
||||
if r.JWKS.URL == nil || r.JWKS.URL.String() == "" {
|
||||
return nil, errors.New("openid not configured")
|
||||
}
|
||||
transport := http.DefaultTransport
|
||||
if r.transport != nil {
|
||||
transport = r.transport
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, r.DiscoveryDoc.UserInfoEndpoint, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if accessToken != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+accessToken)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer r.closeRespFn(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
// uncomment this for debugging when needed.
|
||||
// reqBytes, _ := httputil.DumpRequest(req, false)
|
||||
// fmt.Println(string(reqBytes))
|
||||
// respBytes, _ := httputil.DumpResponse(resp, true)
|
||||
// fmt.Println(string(respBytes))
|
||||
return nil, errors.New(resp.Status)
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(resp.Body)
|
||||
var claims = map[string]interface{}{}
|
||||
|
||||
if err = dec.Decode(&claims); err != nil {
|
||||
// uncomment this for debugging when needed.
|
||||
// reqBytes, _ := httputil.DumpRequest(req, false)
|
||||
// fmt.Println(string(reqBytes))
|
||||
// respBytes, _ := httputil.DumpResponse(resp, true)
|
||||
// fmt.Println(string(respBytes))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
// LookupUser lookup userid for the provider
|
||||
func (r Config) LookupUser(userid string) (provider.User, error) {
|
||||
if r.provider != nil {
|
||||
@@ -122,9 +180,6 @@ func (r *Config) InitializeKeycloakProvider(adminURL, realm string) error {
|
||||
|
||||
// PopulatePublicKey - populates a new publickey from the JWKS URL.
|
||||
func (r *Config) PopulatePublicKey() error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if r.JWKS.URL == nil || r.JWKS.URL.String() == "" {
|
||||
return nil
|
||||
}
|
||||
@@ -135,6 +190,10 @@ func (r *Config) PopulatePublicKey() error {
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
resp, err := client.Get(r.JWKS.URL.String())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -234,7 +293,7 @@ func updateClaimsExpiry(dsecs string, claims map[string]interface{}) error {
|
||||
}
|
||||
|
||||
// Validate - validates the id_token.
|
||||
func (r *Config) Validate(token, dsecs string) (map[string]interface{}, error) {
|
||||
func (r *Config) Validate(token, accessToken, dsecs string) (map[string]interface{}, error) {
|
||||
jp := new(jwtgo.Parser)
|
||||
jp.ValidMethods = []string{
|
||||
"RS256", "RS384", "RS512", "ES256", "ES384", "ES512",
|
||||
@@ -273,6 +332,23 @@ func (r *Config) Validate(token, dsecs string) (map[string]interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If claim user info is enabled, get claims from userInfo
|
||||
// and overwrite them with the claims from JWT.
|
||||
if r.ClaimUserinfo {
|
||||
if accessToken == "" {
|
||||
return nil, errors.New("access_token is mandatory if user_info claim is enabled")
|
||||
}
|
||||
uclaims, err := r.UserInfo(accessToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range uclaims {
|
||||
if _, ok := claims[k]; !ok { // only add to claims not update it.
|
||||
claims[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
@@ -283,29 +359,32 @@ func (Config) ID() ID {
|
||||
|
||||
// OpenID keys and envs.
|
||||
const (
|
||||
JwksURL = "jwks_url"
|
||||
ConfigURL = "config_url"
|
||||
ClaimName = "claim_name"
|
||||
ClaimPrefix = "claim_prefix"
|
||||
ClientID = "client_id"
|
||||
ClientSecret = "client_secret"
|
||||
Vendor = "vendor"
|
||||
Scopes = "scopes"
|
||||
RedirectURI = "redirect_uri"
|
||||
JwksURL = "jwks_url"
|
||||
ConfigURL = "config_url"
|
||||
ClaimName = "claim_name"
|
||||
ClaimUserinfo = "claim_userinfo"
|
||||
ClaimPrefix = "claim_prefix"
|
||||
ClientID = "client_id"
|
||||
ClientSecret = "client_secret"
|
||||
|
||||
Vendor = "vendor"
|
||||
Scopes = "scopes"
|
||||
RedirectURI = "redirect_uri"
|
||||
|
||||
// Vendor specific ENV only enabled if the Vendor matches == "vendor"
|
||||
KeyCloakRealm = "keycloak_realm"
|
||||
KeyCloakAdminURL = "keycloak_admin_url"
|
||||
|
||||
EnvIdentityOpenIDVendor = "MINIO_IDENTITY_OPENID_VENDOR"
|
||||
EnvIdentityOpenIDClientID = "MINIO_IDENTITY_OPENID_CLIENT_ID"
|
||||
EnvIdentityOpenIDClientSecret = "MINIO_IDENTITY_OPENID_CLIENT_SECRET"
|
||||
EnvIdentityOpenIDJWKSURL = "MINIO_IDENTITY_OPENID_JWKS_URL"
|
||||
EnvIdentityOpenIDURL = "MINIO_IDENTITY_OPENID_CONFIG_URL"
|
||||
EnvIdentityOpenIDClaimName = "MINIO_IDENTITY_OPENID_CLAIM_NAME"
|
||||
EnvIdentityOpenIDClaimPrefix = "MINIO_IDENTITY_OPENID_CLAIM_PREFIX"
|
||||
EnvIdentityOpenIDRedirectURI = "MINIO_IDENTITY_OPENID_REDIRECT_URI"
|
||||
EnvIdentityOpenIDScopes = "MINIO_IDENTITY_OPENID_SCOPES"
|
||||
EnvIdentityOpenIDVendor = "MINIO_IDENTITY_OPENID_VENDOR"
|
||||
EnvIdentityOpenIDClientID = "MINIO_IDENTITY_OPENID_CLIENT_ID"
|
||||
EnvIdentityOpenIDClientSecret = "MINIO_IDENTITY_OPENID_CLIENT_SECRET"
|
||||
EnvIdentityOpenIDJWKSURL = "MINIO_IDENTITY_OPENID_JWKS_URL"
|
||||
EnvIdentityOpenIDURL = "MINIO_IDENTITY_OPENID_CONFIG_URL"
|
||||
EnvIdentityOpenIDClaimName = "MINIO_IDENTITY_OPENID_CLAIM_NAME"
|
||||
EnvIdentityOpenIDClaimUserInfo = "MINIO_IDENTITY_OPENID_CLAIM_USERINFO"
|
||||
EnvIdentityOpenIDClaimPrefix = "MINIO_IDENTITY_OPENID_CLAIM_PREFIX"
|
||||
EnvIdentityOpenIDRedirectURI = "MINIO_IDENTITY_OPENID_REDIRECT_URI"
|
||||
EnvIdentityOpenIDScopes = "MINIO_IDENTITY_OPENID_SCOPES"
|
||||
|
||||
// Vendor specific ENVs only enabled if the Vendor matches == "vendor"
|
||||
EnvIdentityOpenIDKeyCloakRealm = "MINIO_IDENTITY_OPENID_KEYCLOAK_REALM"
|
||||
@@ -374,6 +453,10 @@ var (
|
||||
Key: ClaimName,
|
||||
Value: iampolicy.PolicyName,
|
||||
},
|
||||
config.KV{
|
||||
Key: ClaimUserinfo,
|
||||
Value: "",
|
||||
},
|
||||
config.KV{
|
||||
Key: ClaimPrefix,
|
||||
Value: "",
|
||||
@@ -410,15 +493,16 @@ func LookupConfig(kvs config.KVS, transport *http.Transport, closeRespFn func(io
|
||||
}
|
||||
|
||||
c = Config{
|
||||
RWMutex: &sync.RWMutex{},
|
||||
ClaimName: env.Get(EnvIdentityOpenIDClaimName, kvs.Get(ClaimName)),
|
||||
ClaimPrefix: env.Get(EnvIdentityOpenIDClaimPrefix, kvs.Get(ClaimPrefix)),
|
||||
RedirectURI: env.Get(EnvIdentityOpenIDRedirectURI, kvs.Get(RedirectURI)),
|
||||
publicKeys: make(map[string]crypto.PublicKey),
|
||||
ClientID: env.Get(EnvIdentityOpenIDClientID, kvs.Get(ClientID)),
|
||||
ClientSecret: env.Get(EnvIdentityOpenIDClientSecret, kvs.Get(ClientSecret)),
|
||||
transport: transport,
|
||||
closeRespFn: closeRespFn,
|
||||
RWMutex: &sync.RWMutex{},
|
||||
ClaimName: env.Get(EnvIdentityOpenIDClaimName, kvs.Get(ClaimName)),
|
||||
ClaimUserinfo: env.Get(EnvIdentityOpenIDClaimUserInfo, kvs.Get(ClaimUserinfo)) == config.EnableOn,
|
||||
ClaimPrefix: env.Get(EnvIdentityOpenIDClaimPrefix, kvs.Get(ClaimPrefix)),
|
||||
RedirectURI: env.Get(EnvIdentityOpenIDRedirectURI, kvs.Get(RedirectURI)),
|
||||
publicKeys: make(map[string]crypto.PublicKey),
|
||||
ClientID: env.Get(EnvIdentityOpenIDClientID, kvs.Get(ClientID)),
|
||||
ClientSecret: env.Get(EnvIdentityOpenIDClientSecret, kvs.Get(ClientSecret)),
|
||||
transport: transport,
|
||||
closeRespFn: closeRespFn,
|
||||
}
|
||||
|
||||
configURL := env.Get(EnvIdentityOpenIDURL, kvs.Get(ConfigURL))
|
||||
@@ -433,6 +517,10 @@ func LookupConfig(kvs config.KVS, transport *http.Transport, closeRespFn func(io
|
||||
}
|
||||
}
|
||||
|
||||
if c.ClaimUserinfo && configURL == "" {
|
||||
return c, errors.New("please specify config_url to enable fetching claims from UserInfo endpoint")
|
||||
}
|
||||
|
||||
if scopeList := env.Get(EnvIdentityOpenIDScopes, kvs.Get(Scopes)); scopeList != "" {
|
||||
var scopes []string
|
||||
for _, scope := range strings.Split(scopeList, ",") {
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestJWTAzureFail(t *testing.T) {
|
||||
t.Fatalf("Unexpected id %s for the validator", cfg.ID())
|
||||
}
|
||||
|
||||
if _, err := cfg.Validate(jwtToken, ""); err == nil {
|
||||
if _, err := cfg.Validate(jwtToken, "", ""); err == nil {
|
||||
// Azure should fail due to non OIDC compliant JWT
|
||||
// generated by Azure AD
|
||||
t.Fatal(err)
|
||||
@@ -154,7 +154,7 @@ func TestJWT(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := cfg.Validate(u.Query().Get("Token"), ""); err == nil {
|
||||
if _, err := cfg.Validate(u.Query().Get("Token"), "", ""); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ type ID string
|
||||
type Validator interface {
|
||||
// Validate is a custom validator function for this provider,
|
||||
// each validation is authenticationType or provider specific.
|
||||
Validate(token string, duration string) (map[string]interface{}, error)
|
||||
Validate(idToken, accessToken, duration string) (map[string]interface{}, error)
|
||||
|
||||
// ID returns provider name of this provider.
|
||||
ID() ID
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
|
||||
type errorValidator struct{}
|
||||
|
||||
func (e errorValidator) Validate(token, dsecs string) (map[string]interface{}, error) {
|
||||
func (e errorValidator) Validate(idToken, accessToken, dsecs string) (map[string]interface{}, error) {
|
||||
return nil, ErrTokenExpired
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func TestValidators(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err = v.Validate("", ""); err != ErrTokenExpired {
|
||||
if _, err = v.Validate("", "", ""); err != ErrTokenExpired {
|
||||
t.Fatalf("Expected error %s, got %s", ErrTokenExpired, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2015-2021 MinIO, Inc.
|
||||
//
|
||||
// This file is part of MinIO Object Storage stack
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package subnet
|
||||
|
||||
import (
|
||||
jwtgo "github.com/golang-jwt/jwt"
|
||||
"github.com/minio/minio/internal/config"
|
||||
"github.com/minio/pkg/env"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultKVS - default KV config for subnet settings
|
||||
DefaultKVS = config.KVS{
|
||||
config.KV{
|
||||
Key: config.License,
|
||||
Value: "",
|
||||
},
|
||||
}
|
||||
|
||||
// HelpLicense - provides help for license config
|
||||
HelpLicense = config.HelpKVS{
|
||||
config.HelpKV{
|
||||
Key: config.License,
|
||||
Type: "string",
|
||||
Description: "Subnet license token for the cluster",
|
||||
Optional: true,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Config represents the subnet related configuration
|
||||
type Config struct {
|
||||
// The subnet license token
|
||||
License string `json:"license"`
|
||||
}
|
||||
|
||||
func validateLicenseFormat(lic string) error {
|
||||
if len(lic) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Only verifying that the string is a parseable JWT token as of now
|
||||
_, _, err := new(jwtgo.Parser).ParseUnverified(lic, jwtgo.MapClaims{})
|
||||
return err
|
||||
}
|
||||
|
||||
// LookupConfig - lookup config and override with valid environment settings if any.
|
||||
func LookupConfig(kvs config.KVS) (cfg Config, err error) {
|
||||
if err = config.CheckValidKeys(config.SubnetSubSys, kvs, DefaultKVS); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
cfg.License = env.Get(config.EnvMinIOSubnetLicense, kvs.Get(config.License))
|
||||
|
||||
return cfg, validateLicenseFormat(cfg.License)
|
||||
}
|
||||
@@ -210,8 +210,8 @@ func (ssekms) ParseMetadata(metadata map[string]string) (keyID string, kmsKey []
|
||||
return keyID, kmsKey, sealedKey, ctx, Errorf("The internal KMS context is not base64-encoded")
|
||||
}
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
if err = json.Unmarshal(b, ctx); err != nil {
|
||||
return keyID, kmsKey, sealedKey, ctx, Errorf("The internal sealed KMS context is invalid")
|
||||
if err = json.Unmarshal(b, &ctx); err != nil {
|
||||
return keyID, kmsKey, sealedKey, ctx, Errorf("The internal sealed KMS context is invalid %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ func (h *Target) Init() error {
|
||||
// Drain any response.
|
||||
xhttp.DrainBody(resp.Body)
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if !acceptedResponseStatusCode(resp.StatusCode) {
|
||||
switch resp.StatusCode {
|
||||
case http.StatusForbidden:
|
||||
return fmt.Errorf("%s returned '%s', please check if your auth token is correctly set",
|
||||
@@ -112,6 +112,13 @@ func (h *Target) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Accepted HTTP Status Codes
|
||||
var acceptedStatusCodeMap = map[int]bool{http.StatusOK: true, http.StatusCreated: true, http.StatusAccepted: true, http.StatusNoContent: true}
|
||||
|
||||
func acceptedResponseStatusCode(code int) bool {
|
||||
return acceptedStatusCodeMap[code]
|
||||
}
|
||||
|
||||
func (h *Target) startHTTPLogger() {
|
||||
// Create a routine which sends json logs received
|
||||
// from an internal channel.
|
||||
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bcicen/jstream"
|
||||
csv "github.com/minio/csvparser"
|
||||
@@ -43,6 +45,20 @@ type Record struct {
|
||||
func (r *Record) Get(name string) (*sql.Value, error) {
|
||||
index, found := r.nameIndexMap[name]
|
||||
if !found {
|
||||
// Check if index.
|
||||
if strings.HasPrefix(name, "_") {
|
||||
idx, err := strconv.Atoi(strings.TrimPrefix(name, "_"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("column %v not found", name)
|
||||
}
|
||||
// The position count starts at 1.
|
||||
idx--
|
||||
if idx >= len(r.csvRecord) || idx < 0 {
|
||||
// If field index > number of columns, return null
|
||||
return sql.FromNull(), nil
|
||||
}
|
||||
return sql.FromBytes([]byte(r.csvRecord[idx])), nil
|
||||
}
|
||||
return nil, fmt.Errorf("column %v not found", name)
|
||||
}
|
||||
|
||||
|
||||
@@ -675,6 +675,11 @@ func TestCSVQueries2(t *testing.T) {
|
||||
query: `SELECT num2 from s3object s WHERE num2 = 0.765111`,
|
||||
wantResult: `{"num2":" 0.765111"}`,
|
||||
},
|
||||
{
|
||||
name: "select-non_exiting_values",
|
||||
query: `SELECT _1 as first, s._100 from s3object s LIMIT 1`,
|
||||
wantResult: `{"first":"1","_100":null}`,
|
||||
},
|
||||
}
|
||||
|
||||
defRequest := `<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
Reference in New Issue
Block a user