mirror of
https://github.com/pgsty/minio.git
synced 2026-11-09 09:11:51 +03:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 849a27ee61 | |||
| 062f3ea43a | |||
| 5cfedcfe33 | |||
| 4d2fc530d0 | |||
| 3970204009 | |||
| f046f557fa | |||
| 401958938d | |||
| 566cffe53d | |||
| 028bc2f9be | |||
| 813d9bc316 | |||
| 79ba458051 | |||
| cf220be9b5 | |||
| c433572585 | |||
| a42b576382 | |||
| fb9b53026d | |||
| 2ac54e5a7b | |||
| 8eecdc6d1f | |||
| 50577e2bd2 | |||
| 7bc1f986e8 | |||
| d796621ccc | |||
| 751e9fb7be |
@@ -21,9 +21,10 @@ jobs:
|
|||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
check-latest: true
|
||||||
- name: Build on ${{ matrix.os }}
|
- name: Build on ${{ matrix.os }}
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ jobs:
|
|||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
check-latest: true
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ jobs:
|
|||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
check-latest: true
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ jobs:
|
|||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
check-latest: true
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -65,9 +65,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
check-latest: true
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
check-latest: true
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
check-latest: true
|
||||||
- name: Start upgrade tests
|
- name: Start upgrade tests
|
||||||
run: |
|
run: |
|
||||||
make test-upgrade
|
make test-upgrade
|
||||||
|
|||||||
+24
-5
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2015-2021 MinIO, Inc.
|
// Copyright (c) 2015-2022 MinIO, Inc.
|
||||||
//
|
//
|
||||||
// This file is part of MinIO Object Storage stack
|
// This file is part of MinIO Object Storage stack
|
||||||
//
|
//
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
@@ -1684,7 +1685,10 @@ func (a adminAPIHandlers) HealthInfoHandler(w http.ResponseWriter, r *http.Reque
|
|||||||
logger.LogIf(ctx, enc.Encode(healthInfo))
|
logger.LogIf(ctx, enc.Encode(healthInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
deadline := 1 * time.Hour
|
deadline := 10 * time.Second // Default deadline is 10secs for health diagnostics.
|
||||||
|
if query.Get("perfnet") != "" || query.Get("perfdrive") != "" {
|
||||||
|
deadline = 1 * time.Hour
|
||||||
|
}
|
||||||
if dstr := r.Form.Get("deadline"); dstr != "" {
|
if dstr := r.Form.Get("deadline"); dstr != "" {
|
||||||
var err error
|
var err error
|
||||||
deadline, err = time.ParseDuration(dstr)
|
deadline, err = time.ParseDuration(dstr)
|
||||||
@@ -2426,8 +2430,7 @@ func (a adminAPIHandlers) InspectDataHandler(w http.ResponseWriter, r *http.Requ
|
|||||||
// of profiling data of all nodes
|
// of profiling data of all nodes
|
||||||
zipWriter := zip.NewWriter(encw)
|
zipWriter := zip.NewWriter(encw)
|
||||||
defer zipWriter.Close()
|
defer zipWriter.Close()
|
||||||
|
rawDataFn := func(r io.Reader, host, disk, filename string, si StatInfo) error {
|
||||||
err = o.GetRawData(ctx, volume, file, func(r io.Reader, host, disk, filename string, si StatInfo) error {
|
|
||||||
// Prefix host+disk
|
// Prefix host+disk
|
||||||
filename = path.Join(host, disk, filename)
|
filename = path.Join(host, disk, filename)
|
||||||
if si.Dir {
|
if si.Dir {
|
||||||
@@ -2460,10 +2463,26 @@ func (a adminAPIHandlers) InspectDataHandler(w http.ResponseWriter, r *http.Requ
|
|||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}
|
||||||
|
err = o.GetRawData(ctx, volume, file, rawDataFn)
|
||||||
if !errors.Is(err, errFileNotFound) {
|
if !errors.Is(err, errFileNotFound) {
|
||||||
logger.LogIf(ctx, err)
|
logger.LogIf(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// save the format.json as part of inspect by default
|
||||||
|
if volume != minioMetaBucket && file != formatConfigFile {
|
||||||
|
err = o.GetRawData(ctx, minioMetaBucket, formatConfigFile, rawDataFn)
|
||||||
|
}
|
||||||
|
if !errors.Is(err, errFileNotFound) {
|
||||||
|
logger.LogIf(ctx, err)
|
||||||
|
}
|
||||||
|
// save args passed to inspect command
|
||||||
|
inspectArgs := fmt.Sprintf("inspect path: %s%s%s\n", volume, slashSeparator, file)
|
||||||
|
if err = rawDataFn(bytes.NewReader([]byte(inspectArgs)), "", "", "inspect-input.txt", StatInfo{
|
||||||
|
Size: int64(len(inspectArgs)),
|
||||||
|
}); err != nil {
|
||||||
|
logger.LogIf(ctx, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createHostAnonymizerForFSMode() map[string]string {
|
func createHostAnonymizerForFSMode() map[string]string {
|
||||||
|
|||||||
@@ -24,28 +24,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/minio/minio/internal/kms"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
|
|
||||||
"github.com/minio/minio/internal/sync/errgroup"
|
|
||||||
"github.com/minio/pkg/bucket/policy"
|
"github.com/minio/pkg/bucket/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func concurrentDecryptETag(ctx context.Context, objects []ObjectInfo) {
|
|
||||||
g := errgroup.WithNErrs(len(objects)).WithConcurrency(500)
|
|
||||||
for index := range objects {
|
|
||||||
index := index
|
|
||||||
g.Go(func() error {
|
|
||||||
size, err := objects[index].GetActualSize()
|
|
||||||
if err == nil {
|
|
||||||
objects[index].Size = size
|
|
||||||
}
|
|
||||||
objects[index].ETag = objects[index].GetActualETag(nil)
|
|
||||||
return nil
|
|
||||||
}, index)
|
|
||||||
}
|
|
||||||
g.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate all the ListObjects query arguments, returns an APIErrorCode
|
// Validate all the ListObjects query arguments, returns an APIErrorCode
|
||||||
// if one of the args do not meet the required conditions.
|
// if one of the args do not meet the required conditions.
|
||||||
// Special conditions required by MinIO server are as below
|
// Special conditions required by MinIO server are as below
|
||||||
@@ -116,7 +100,10 @@ func (api objectAPIHandlers) ListObjectVersionsHandler(w http.ResponseWriter, r
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
concurrentDecryptETag(ctx, listObjectVersionsInfo.Objects)
|
if err = DecryptETags(ctx, GlobalKMS, listObjectVersionsInfo.Objects, kms.BatchSize()); err != nil {
|
||||||
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response := generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType, maxkeys, listObjectVersionsInfo)
|
response := generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType, maxkeys, listObjectVersionsInfo)
|
||||||
|
|
||||||
@@ -178,7 +165,10 @@ func (api objectAPIHandlers) ListObjectsV2MHandler(w http.ResponseWriter, r *htt
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
concurrentDecryptETag(ctx, listObjectsV2Info.Objects)
|
if err = DecryptETags(ctx, GlobalKMS, listObjectsV2Info.Objects, kms.BatchSize()); err != nil {
|
||||||
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// The next continuation token has id@node_index format to optimize paginated listing
|
// The next continuation token has id@node_index format to optimize paginated listing
|
||||||
nextContinuationToken := listObjectsV2Info.NextContinuationToken
|
nextContinuationToken := listObjectsV2Info.NextContinuationToken
|
||||||
@@ -253,7 +243,10 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
concurrentDecryptETag(ctx, listObjectsV2Info.Objects)
|
if err = DecryptETags(ctx, GlobalKMS, listObjectsV2Info.Objects, kms.BatchSize()); err != nil {
|
||||||
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response := generateListObjectsV2Response(bucket, prefix, token, listObjectsV2Info.NextContinuationToken, startAfter,
|
response := generateListObjectsV2Response(bucket, prefix, token, listObjectsV2Info.NextContinuationToken, startAfter,
|
||||||
delimiter, encodingType, fetchOwner, listObjectsV2Info.IsTruncated,
|
delimiter, encodingType, fetchOwner, listObjectsV2Info.IsTruncated,
|
||||||
@@ -350,7 +343,10 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
concurrentDecryptETag(ctx, listObjectsInfo.Objects)
|
if err = DecryptETags(ctx, GlobalKMS, listObjectsInfo.Objects, kms.BatchSize()); err != nil {
|
||||||
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
response := generateListObjectsV1Response(bucket, prefix, marker, delimiter, encodingType, maxKeys, listObjectsInfo)
|
response := generateListObjectsV1Response(bucket, prefix, marker, delimiter, encodingType, maxKeys, listObjectsInfo)
|
||||||
|
|
||||||
|
|||||||
+91
-2
@@ -19,6 +19,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
@@ -35,6 +36,7 @@ import (
|
|||||||
|
|
||||||
"github.com/minio/kes"
|
"github.com/minio/kes"
|
||||||
"github.com/minio/minio/internal/crypto"
|
"github.com/minio/minio/internal/crypto"
|
||||||
|
"github.com/minio/minio/internal/etag"
|
||||||
"github.com/minio/minio/internal/fips"
|
"github.com/minio/minio/internal/fips"
|
||||||
xhttp "github.com/minio/minio/internal/http"
|
xhttp "github.com/minio/minio/internal/http"
|
||||||
"github.com/minio/minio/internal/kms"
|
"github.com/minio/minio/internal/kms"
|
||||||
@@ -80,6 +82,7 @@ func (o *MultipartInfo) KMSKeyID() string { return kmsKeyIDFromMetadata(o.UserDe
|
|||||||
// metadata, if any. It returns an empty ID if no key ID is
|
// metadata, if any. It returns an empty ID if no key ID is
|
||||||
// present.
|
// present.
|
||||||
func kmsKeyIDFromMetadata(metadata map[string]string) string {
|
func kmsKeyIDFromMetadata(metadata map[string]string) string {
|
||||||
|
const ARNPrefix = "arn:aws:kms:"
|
||||||
if len(metadata) == 0 {
|
if len(metadata) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -87,10 +90,96 @@ func kmsKeyIDFromMetadata(metadata map[string]string) string {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(kmsID, "arn:aws:kms:") {
|
if strings.HasPrefix(kmsID, ARNPrefix) {
|
||||||
return kmsID
|
return kmsID
|
||||||
}
|
}
|
||||||
return "arn:aws:kms:" + kmsID
|
return ARNPrefix + kmsID
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptETags dectypts all ObjectInfo ETags, if encrypted, using the KMS.
|
||||||
|
func DecryptETags(ctx context.Context, KMS kms.KMS, objects []ObjectInfo, batchSize int) error {
|
||||||
|
var (
|
||||||
|
metadata []map[string]string
|
||||||
|
buckets []string
|
||||||
|
names []string
|
||||||
|
)
|
||||||
|
for len(objects) > 0 {
|
||||||
|
var N int
|
||||||
|
if len(objects) < batchSize {
|
||||||
|
N = len(objects)
|
||||||
|
} else {
|
||||||
|
N = batchSize
|
||||||
|
}
|
||||||
|
|
||||||
|
SSES3Batch := true
|
||||||
|
for _, object := range objects[:N] {
|
||||||
|
if kind, ok := crypto.IsEncrypted(object.UserDefined); !ok || kind != crypto.S3 {
|
||||||
|
SSES3Batch = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !SSES3Batch {
|
||||||
|
for i := range objects[:N] {
|
||||||
|
size, err := objects[i].GetActualSize()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
objects[i].Size = size
|
||||||
|
objects[i].ETag = objects[i].GetActualETag(nil)
|
||||||
|
}
|
||||||
|
objects = objects[N:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, decrypt all ETags using the a specialized bulk decryption API, if available.
|
||||||
|
// We check the cap of all slices first, to avoid allocating them over and over again.
|
||||||
|
if cap(metadata) >= N {
|
||||||
|
metadata = metadata[:0:N]
|
||||||
|
} else {
|
||||||
|
metadata = make([]map[string]string, 0, N)
|
||||||
|
}
|
||||||
|
if cap(buckets) >= N {
|
||||||
|
buckets = buckets[:0:N]
|
||||||
|
} else {
|
||||||
|
buckets = make([]string, 0, N)
|
||||||
|
}
|
||||||
|
if cap(names) >= N {
|
||||||
|
names = names[:0:N]
|
||||||
|
} else {
|
||||||
|
names = make([]string, 0, N)
|
||||||
|
}
|
||||||
|
for _, object := range objects[:N] {
|
||||||
|
metadata = append(metadata, object.UserDefined)
|
||||||
|
buckets = append(buckets, object.Bucket)
|
||||||
|
names = append(names, object.Name)
|
||||||
|
}
|
||||||
|
keys, err := crypto.S3.UnsealObjectKeys(KMS, metadata, buckets, names)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range objects[:N] {
|
||||||
|
size, err := objects[i].GetActualSize()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ETag, err := etag.Parse(objects[i].ETag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ETag.IsEncrypted() {
|
||||||
|
tag, err := keys[i].UnsealETag(ETag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ETag = etag.ETag(tag)
|
||||||
|
objects[i].Size = size
|
||||||
|
objects[i].ETag = ETag.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objects = objects[N:]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isMultipart returns true if the current object is
|
// isMultipart returns true if the current object is
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import (
|
|||||||
"github.com/minio/madmin-go"
|
"github.com/minio/madmin-go"
|
||||||
"github.com/minio/minio-go/v7/pkg/set"
|
"github.com/minio/minio-go/v7/pkg/set"
|
||||||
"github.com/minio/minio-go/v7/pkg/tags"
|
"github.com/minio/minio-go/v7/pkg/tags"
|
||||||
|
"github.com/minio/minio/internal/bucket/lifecycle"
|
||||||
"github.com/minio/minio/internal/config/storageclass"
|
"github.com/minio/minio/internal/config/storageclass"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
"github.com/minio/minio/internal/sync/errgroup"
|
"github.com/minio/minio/internal/sync/errgroup"
|
||||||
@@ -1152,6 +1153,14 @@ func maxKeysPlusOne(maxKeys int, addOne bool) int {
|
|||||||
func (z *erasureServerPools) ListObjects(ctx context.Context, bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, error) {
|
func (z *erasureServerPools) ListObjects(ctx context.Context, bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, error) {
|
||||||
var loi ListObjectsInfo
|
var loi ListObjectsInfo
|
||||||
|
|
||||||
|
// Automatically remove the object/version is an expiry lifecycle rule can be applied
|
||||||
|
lc, _ := globalLifecycleSys.Get(bucket)
|
||||||
|
if lc != nil {
|
||||||
|
if !lc.HasActiveRules(prefix, true) {
|
||||||
|
lc = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(prefix) > 0 && maxKeys == 1 && delimiter == "" && marker == "" {
|
if len(prefix) > 0 && maxKeys == 1 && delimiter == "" && marker == "" {
|
||||||
// Optimization for certain applications like
|
// Optimization for certain applications like
|
||||||
// - Cohesity
|
// - Cohesity
|
||||||
@@ -1162,6 +1171,13 @@ func (z *erasureServerPools) ListObjects(ctx context.Context, bucket, prefix, ma
|
|||||||
// to avoid the need for ListObjects().
|
// to avoid the need for ListObjects().
|
||||||
objInfo, err := z.GetObjectInfo(ctx, bucket, prefix, ObjectOptions{NoLock: true})
|
objInfo, err := z.GetObjectInfo(ctx, bucket, prefix, ObjectOptions{NoLock: true})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
if lc != nil {
|
||||||
|
action := evalActionFromLifecycle(ctx, *lc, objInfo, false)
|
||||||
|
switch action {
|
||||||
|
case lifecycle.DeleteVersionAction, lifecycle.DeleteAction:
|
||||||
|
return loi, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
loi.Objects = append(loi.Objects, objInfo)
|
loi.Objects = append(loi.Objects, objInfo)
|
||||||
return loi, nil
|
return loi, nil
|
||||||
}
|
}
|
||||||
@@ -1176,6 +1192,7 @@ func (z *erasureServerPools) ListObjects(ctx context.Context, bucket, prefix, ma
|
|||||||
InclDeleted: false,
|
InclDeleted: false,
|
||||||
AskDisks: globalAPIConfig.getListQuorum(),
|
AskDisks: globalAPIConfig.getListQuorum(),
|
||||||
}
|
}
|
||||||
|
|
||||||
merged, err := z.listPath(ctx, &opts)
|
merged, err := z.listPath(ctx, &opts)
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
if !isErrBucketNotFound(err) {
|
if !isErrBucketNotFound(err) {
|
||||||
|
|||||||
+1
-1
@@ -190,7 +190,7 @@ var (
|
|||||||
globalBucketTargetSys *BucketTargetSys
|
globalBucketTargetSys *BucketTargetSys
|
||||||
// globalAPIConfig controls S3 API requests throttling,
|
// globalAPIConfig controls S3 API requests throttling,
|
||||||
// healthcheck readiness deadlines and cors settings.
|
// healthcheck readiness deadlines and cors settings.
|
||||||
globalAPIConfig = apiConfig{listQuorum: -1}
|
globalAPIConfig = apiConfig{listQuorum: "strict"}
|
||||||
|
|
||||||
globalStorageClass storageclass.Config
|
globalStorageClass storageclass.Config
|
||||||
globalLDAPConfig xldap.Config
|
globalLDAPConfig xldap.Config
|
||||||
|
|||||||
+4
-4
@@ -38,7 +38,7 @@ type apiConfig struct {
|
|||||||
requestsDeadline time.Duration
|
requestsDeadline time.Duration
|
||||||
requestsPool chan struct{}
|
requestsPool chan struct{}
|
||||||
clusterDeadline time.Duration
|
clusterDeadline time.Duration
|
||||||
listQuorum int
|
listQuorum string
|
||||||
corsAllowOrigins []string
|
corsAllowOrigins []string
|
||||||
// total drives per erasure set across pools.
|
// total drives per erasure set across pools.
|
||||||
totalDriveCount int
|
totalDriveCount int
|
||||||
@@ -127,7 +127,7 @@ func (t *apiConfig) init(cfg api.Config, setDriveCounts []int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cap(t.requestsPool) < apiRequestsMaxPerNode {
|
if cap(t.requestsPool) != apiRequestsMaxPerNode {
|
||||||
// Only replace if needed.
|
// Only replace if needed.
|
||||||
// Existing requests will use the previous limit,
|
// Existing requests will use the previous limit,
|
||||||
// but new requests will use the new limit.
|
// but new requests will use the new limit.
|
||||||
@@ -136,7 +136,7 @@ func (t *apiConfig) init(cfg api.Config, setDriveCounts []int) {
|
|||||||
t.requestsPool = make(chan struct{}, apiRequestsMaxPerNode)
|
t.requestsPool = make(chan struct{}, apiRequestsMaxPerNode)
|
||||||
}
|
}
|
||||||
t.requestsDeadline = cfg.RequestsDeadline
|
t.requestsDeadline = cfg.RequestsDeadline
|
||||||
t.listQuorum = cfg.GetListQuorum()
|
t.listQuorum = cfg.ListQuorum
|
||||||
if globalReplicationPool != nil &&
|
if globalReplicationPool != nil &&
|
||||||
cfg.ReplicationWorkers != t.replicationWorkers {
|
cfg.ReplicationWorkers != t.replicationWorkers {
|
||||||
globalReplicationPool.ResizeFailedWorkers(cfg.ReplicationFailedWorkers)
|
globalReplicationPool.ResizeFailedWorkers(cfg.ReplicationFailedWorkers)
|
||||||
@@ -170,7 +170,7 @@ func (t *apiConfig) shouldGzipObjects() bool {
|
|||||||
return t.gzipObjects
|
return t.gzipObjects
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *apiConfig) getListQuorum() int {
|
func (t *apiConfig) getListQuorum() string {
|
||||||
t.mu.RLock()
|
t.mu.RLock()
|
||||||
defer t.mu.RUnlock()
|
defer t.mu.RUnlock()
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func Benchmark_bucketMetacache_findCache(b *testing.B) {
|
|||||||
FilterPrefix: "",
|
FilterPrefix: "",
|
||||||
Marker: "",
|
Marker: "",
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
AskDisks: 0,
|
AskDisks: "strict",
|
||||||
Recursive: false,
|
Recursive: false,
|
||||||
Separator: slashSeparator,
|
Separator: slashSeparator,
|
||||||
Create: true,
|
Create: true,
|
||||||
@@ -59,7 +59,7 @@ func Benchmark_bucketMetacache_findCache(b *testing.B) {
|
|||||||
FilterPrefix: "",
|
FilterPrefix: "",
|
||||||
Marker: "",
|
Marker: "",
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
AskDisks: 0,
|
AskDisks: "strict",
|
||||||
Recursive: false,
|
Recursive: false,
|
||||||
Separator: slashSeparator,
|
Separator: slashSeparator,
|
||||||
Create: true,
|
Create: true,
|
||||||
|
|||||||
@@ -281,10 +281,16 @@ func (m metaCacheEntries) shallowClone() metaCacheEntries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type metadataResolutionParams struct {
|
type metadataResolutionParams struct {
|
||||||
dirQuorum int // Number if disks needed for a directory to 'exist'.
|
dirQuorum int // Number if disks needed for a directory to 'exist'.
|
||||||
objQuorum int // Number of disks needed for an object to 'exist'.
|
objQuorum int // Number of disks needed for an object to 'exist'.
|
||||||
bucket string // Name of the bucket. Used for generating cached fileinfo.
|
|
||||||
strict bool // Versions must match exactly, including all metadata.
|
// An optimization request only an 'n' amount of versions from xl.meta
|
||||||
|
// to avoid resolving all versions to figure out the latest 'version'
|
||||||
|
// for ListObjects, ListObjectsV2
|
||||||
|
requestedVersions int
|
||||||
|
|
||||||
|
bucket string // Name of the bucket. Used for generating cached fileinfo.
|
||||||
|
strict bool // Versions must match exactly, including all metadata.
|
||||||
|
|
||||||
// Reusable slice for resolution
|
// Reusable slice for resolution
|
||||||
candidates [][]xlMetaV2ShallowVersion
|
candidates [][]xlMetaV2ShallowVersion
|
||||||
@@ -372,7 +378,7 @@ func (m metaCacheEntries) resolve(r *metadataResolutionParams) (selected *metaCa
|
|||||||
reusable: true,
|
reusable: true,
|
||||||
cached: &xlMetaV2{metaV: selected.cached.metaV},
|
cached: &xlMetaV2{metaV: selected.cached.metaV},
|
||||||
}
|
}
|
||||||
selected.cached.versions = mergeXLV2Versions(r.objQuorum, r.strict, r.candidates...)
|
selected.cached.versions = mergeXLV2Versions(r.objQuorum, r.strict, r.requestedVersions, r.candidates...)
|
||||||
if len(selected.cached.versions) == 0 {
|
if len(selected.cached.versions) == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -498,7 +504,7 @@ func (m *metaCacheEntriesSorted) fileInfoVersions(bucket, prefix, delimiter, aft
|
|||||||
return versions
|
return versions
|
||||||
}
|
}
|
||||||
|
|
||||||
// fileInfoVersions converts the metadata to FileInfoVersions where possible.
|
// fileInfos converts the metadata to ObjectInfo where possible.
|
||||||
// Metadata that cannot be decoded is skipped.
|
// Metadata that cannot be decoded is skipped.
|
||||||
func (m *metaCacheEntriesSorted) fileInfos(bucket, prefix, delimiter string) (objects []ObjectInfo) {
|
func (m *metaCacheEntriesSorted) fileInfos(bucket, prefix, delimiter string) (objects []ObjectInfo) {
|
||||||
objects = make([]ObjectInfo, 0, m.len())
|
objects = make([]ObjectInfo, 0, m.len())
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/minio/minio/internal/bucket/lifecycle"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ func (z *erasureServerPools) listPath(ctx context.Context, o *listPathOptions) (
|
|||||||
// If we don't have a list id we must ask the server if it has a cache or create a new.
|
// If we don't have a list id we must ask the server if it has a cache or create a new.
|
||||||
if o.ID != "" && !o.Transient {
|
if o.ID != "" && !o.Transient {
|
||||||
// Create or ping with handout...
|
// Create or ping with handout...
|
||||||
rpc := globalNotificationSys.restClientFromHash(o.Bucket)
|
rpc := globalNotificationSys.restClientFromHash(pathJoin(o.Bucket, o.Prefix))
|
||||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
var c *metacache
|
var c *metacache
|
||||||
@@ -198,7 +199,7 @@ func (z *erasureServerPools) listPath(ctx context.Context, o *listPathOptions) (
|
|||||||
}
|
}
|
||||||
entries.truncate(0)
|
entries.truncate(0)
|
||||||
go func() {
|
go func() {
|
||||||
rpc := globalNotificationSys.restClientFromHash(o.Bucket)
|
rpc := globalNotificationSys.restClientFromHash(pathJoin(o.Bucket, o.Prefix))
|
||||||
if rpc != nil {
|
if rpc != nil {
|
||||||
ctx, cancel := context.WithTimeout(GlobalContext, 5*time.Second)
|
ctx, cancel := context.WithTimeout(GlobalContext, 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -289,6 +290,14 @@ func (z *erasureServerPools) listMerged(ctx context.Context, o listPathOptions,
|
|||||||
}
|
}
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
|
|
||||||
|
// Do lifecycle filtering.
|
||||||
|
if o.lcFilter != nil {
|
||||||
|
filterIn := make(chan metaCacheEntry, 10)
|
||||||
|
go filterLifeCycle(ctx, o.Bucket, o.lcFilter, filterIn, results)
|
||||||
|
// Replace results.
|
||||||
|
results = filterIn
|
||||||
|
}
|
||||||
|
|
||||||
// Gather results to a single channel.
|
// Gather results to a single channel.
|
||||||
err := mergeEntryChannels(ctx, inputs, results, func(existing, other *metaCacheEntry) (replace bool) {
|
err := mergeEntryChannels(ctx, inputs, results, func(existing, other *metaCacheEntry) (replace bool) {
|
||||||
// Pick object over directory
|
// Pick object over directory
|
||||||
@@ -298,21 +307,20 @@ func (z *erasureServerPools) listMerged(ctx context.Context, o listPathOptions,
|
|||||||
if !existing.isDir() && other.isDir() {
|
if !existing.isDir() && other.isDir() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
eMeta, err := existing.xlmeta()
|
||||||
eFIV, err := existing.fileInfo(o.Bucket)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
oFIV, err := other.fileInfo(o.Bucket)
|
oMeta, err := other.xlmeta()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Replace if modtime is newer
|
// Replace if modtime is newer
|
||||||
if !oFIV.ModTime.Equal(eFIV.ModTime) {
|
if !oMeta.latestModtime().Equal(oMeta.latestModtime()) {
|
||||||
return oFIV.ModTime.After(eFIV.ModTime)
|
return oMeta.latestModtime().After(eMeta.latestModtime())
|
||||||
}
|
}
|
||||||
// Use NumVersions as a final tiebreaker.
|
// Use NumVersions as a final tiebreaker.
|
||||||
return oFIV.NumVersions > eFIV.NumVersions
|
return len(oMeta.versions) > len(eMeta.versions)
|
||||||
})
|
})
|
||||||
|
|
||||||
cancelList()
|
cancelList()
|
||||||
@@ -346,6 +354,44 @@ func (z *erasureServerPools) listMerged(ctx context.Context, o listPathOptions,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filterLifeCycle will filter out objects if the most recent
|
||||||
|
// version should be deleted by lifecycle.
|
||||||
|
// out will be closed when there are no more results.
|
||||||
|
// When 'in' is closed or the context is canceled the
|
||||||
|
// function closes 'out' and exits.
|
||||||
|
func filterLifeCycle(ctx context.Context, bucket string, lc *lifecycle.Lifecycle, in <-chan metaCacheEntry, out chan<- metaCacheEntry) {
|
||||||
|
defer close(out)
|
||||||
|
for {
|
||||||
|
var obj metaCacheEntry
|
||||||
|
var ok bool
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case obj, ok = <-in:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := obj.fileInfo(bucket)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
objInfo := fi.ToObjectInfo(bucket, obj.name)
|
||||||
|
action := evalActionFromLifecycle(ctx, *lc, objInfo, false)
|
||||||
|
switch action {
|
||||||
|
case lifecycle.DeleteVersionAction, lifecycle.DeleteAction:
|
||||||
|
// Skip this entry.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case out <- obj:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (z *erasureServerPools) listAndSave(ctx context.Context, o *listPathOptions) (entries metaCacheEntriesSorted, err error) {
|
func (z *erasureServerPools) listAndSave(ctx context.Context, o *listPathOptions) (entries metaCacheEntriesSorted, err error) {
|
||||||
// Use ID as the object name...
|
// Use ID as the object name...
|
||||||
o.pool = z.getAvailablePoolIdx(ctx, minioMetaBucket, o.ID, 10<<20)
|
o.pool = z.getAvailablePoolIdx(ctx, minioMetaBucket, o.ID, 10<<20)
|
||||||
@@ -369,7 +415,7 @@ func (z *erasureServerPools) listAndSave(ctx context.Context, o *listPathOptions
|
|||||||
filteredResults := o.gatherResults(ctx, outCh)
|
filteredResults := o.gatherResults(ctx, outCh)
|
||||||
|
|
||||||
mc := o.newMetacache()
|
mc := o.newMetacache()
|
||||||
meta := metaCacheRPC{meta: &mc, cancel: cancel, rpc: globalNotificationSys.restClientFromHash(o.Bucket), o: *o}
|
meta := metaCacheRPC{meta: &mc, cancel: cancel, rpc: globalNotificationSys.restClientFromHash(pathJoin(o.Bucket, o.Prefix)), o: *o}
|
||||||
|
|
||||||
// Save listing...
|
// Save listing...
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
+45
-11
@@ -32,6 +32,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"github.com/minio/minio/internal/bucket/lifecycle"
|
||||||
"github.com/minio/minio/internal/color"
|
"github.com/minio/minio/internal/color"
|
||||||
"github.com/minio/minio/internal/hash"
|
"github.com/minio/minio/internal/hash"
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
@@ -64,10 +65,8 @@ type listPathOptions struct {
|
|||||||
// Limit the number of results.
|
// Limit the number of results.
|
||||||
Limit int
|
Limit int
|
||||||
|
|
||||||
// The number of disks to ask. Special values:
|
// The number of disks to ask.
|
||||||
// 0 uses default number of disks.
|
AskDisks string
|
||||||
// -1 use at least 50% of disks or at least the default number.
|
|
||||||
AskDisks int
|
|
||||||
|
|
||||||
// InclDeleted will keep all entries where latest version is a delete marker.
|
// InclDeleted will keep all entries where latest version is a delete marker.
|
||||||
InclDeleted bool
|
InclDeleted bool
|
||||||
@@ -96,6 +95,11 @@ type listPathOptions struct {
|
|||||||
|
|
||||||
// pool and set of where the cache is located.
|
// pool and set of where the cache is located.
|
||||||
pool, set int
|
pool, set int
|
||||||
|
|
||||||
|
// lcFilter performs filtering based on lifecycle.
|
||||||
|
// This will filter out objects if the most recent version should be deleted by lifecycle.
|
||||||
|
// Is not transferred across request calls.
|
||||||
|
lcFilter *lifecycle.Lifecycle
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -189,7 +193,11 @@ func (o *listPathOptions) gatherResults(ctx context.Context, in <-chan metaCache
|
|||||||
}
|
}
|
||||||
if resCh != nil {
|
if resCh != nil {
|
||||||
resErr = io.EOF
|
resErr = io.EOF
|
||||||
resCh <- results
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
// Nobody wants it.
|
||||||
|
case resCh <- results:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return func() (metaCacheEntriesSorted, error) {
|
return func() (metaCacheEntriesSorted, error) {
|
||||||
@@ -351,7 +359,7 @@ func (r *metacacheReader) filter(o listPathOptions) (entries metaCacheEntriesSor
|
|||||||
|
|
||||||
func (er *erasureObjects) streamMetadataParts(ctx context.Context, o listPathOptions) (entries metaCacheEntriesSorted, err error) {
|
func (er *erasureObjects) streamMetadataParts(ctx context.Context, o listPathOptions) (entries metaCacheEntriesSorted, err error) {
|
||||||
retries := 0
|
retries := 0
|
||||||
rpc := globalNotificationSys.restClientFromHash(o.Bucket)
|
rpc := globalNotificationSys.restClientFromHash(pathJoin(o.Bucket, o.Prefix))
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if contextCanceled(ctx) {
|
if contextCanceled(ctx) {
|
||||||
@@ -531,20 +539,39 @@ func (er *erasureObjects) streamMetadataParts(ctx context.Context, o listPathOpt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getListQuorum interprets list quorum values and returns appropriate
|
||||||
|
// acceptable quorum expected for list operations
|
||||||
|
func getListQuorum(quorum string, driveCount int) int {
|
||||||
|
switch quorum {
|
||||||
|
case "disk":
|
||||||
|
// smallest possible value, generally meant for testing.
|
||||||
|
return 1
|
||||||
|
case "reduced":
|
||||||
|
return 2
|
||||||
|
case "strict":
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
// Defaults to (driveCount+1)/2 drives per set, defaults to "optimal" value
|
||||||
|
if driveCount > 0 {
|
||||||
|
return (driveCount + 1) / 2
|
||||||
|
} // "3" otherwise.
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
// Will return io.EOF if continuing would not yield more results.
|
// Will return io.EOF if continuing would not yield more results.
|
||||||
func (er *erasureObjects) listPath(ctx context.Context, o listPathOptions, results chan<- metaCacheEntry) (err error) {
|
func (er *erasureObjects) listPath(ctx context.Context, o listPathOptions, results chan<- metaCacheEntry) (err error) {
|
||||||
defer close(results)
|
defer close(results)
|
||||||
o.debugf(color.Green("listPath:")+" with options: %#v", o)
|
o.debugf(color.Green("listPath:")+" with options: %#v", o)
|
||||||
|
|
||||||
askDisks := o.AskDisks
|
askDisks := getListQuorum(o.AskDisks, er.setDriveCount)
|
||||||
listingQuorum := o.AskDisks - 1
|
listingQuorum := askDisks - 1
|
||||||
disks := er.getDisks()
|
disks := er.getDisks()
|
||||||
var fallbackDisks []StorageAPI
|
var fallbackDisks []StorageAPI
|
||||||
|
|
||||||
// Special case: ask all disks if the drive count is 4
|
// Special case: ask all disks if the drive count is 4
|
||||||
if askDisks <= 0 || er.setDriveCount == 4 {
|
if askDisks <= 0 || er.setDriveCount == 4 {
|
||||||
askDisks = len(disks) // with 'strict' quorum list on all online disks.
|
askDisks = len(disks) // with 'strict' quorum list on all drives.
|
||||||
listingQuorum = len(disks) / 2 // keep this such that we can list all objects with different quorum ratio.
|
listingQuorum = (len(disks) + 1) / 2 // keep this such that we can list all objects with different quorum ratio.
|
||||||
}
|
}
|
||||||
if askDisks > 0 && len(disks) > askDisks {
|
if askDisks > 0 && len(disks) > askDisks {
|
||||||
rand.Shuffle(len(disks), func(i, j int) {
|
rand.Shuffle(len(disks), func(i, j int) {
|
||||||
@@ -561,6 +588,13 @@ func (er *erasureObjects) listPath(ctx context.Context, o listPathOptions, resul
|
|||||||
bucket: o.Bucket,
|
bucket: o.Bucket,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maximum versions requested for "latest" object
|
||||||
|
// resolution on versioned buckets, this is to be only
|
||||||
|
// used when o.Versioned is false
|
||||||
|
if !o.Versioned {
|
||||||
|
resolver.requestedVersions = 1
|
||||||
|
}
|
||||||
|
|
||||||
ctxDone := ctx.Done()
|
ctxDone := ctx.Done()
|
||||||
return listPathRaw(ctx, listPathRawOptions{
|
return listPathRaw(ctx, listPathRawOptions{
|
||||||
disks: disks,
|
disks: disks,
|
||||||
@@ -805,7 +839,7 @@ func listPathRaw(ctx context.Context, opts listPathRawOptions) (err error) {
|
|||||||
for _, fd := range fdsCopy {
|
for _, fd := range fdsCopy {
|
||||||
// Grab a fallback disk
|
// Grab a fallback disk
|
||||||
fds = fds[1:]
|
fds = fds[1:]
|
||||||
if fd != nil {
|
if fd != nil && fd.IsOnline() {
|
||||||
return fd
|
return fd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -300,6 +300,8 @@ func configRetriableErrors(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initServer(ctx context.Context, newObject ObjectLayer) error {
|
func initServer(ctx context.Context, newObject ObjectLayer) error {
|
||||||
|
t1 := time.Now()
|
||||||
|
|
||||||
// Once the config is fully loaded, initialize the new object layer.
|
// Once the config is fully loaded, initialize the new object layer.
|
||||||
setObjectLayer(newObject)
|
setObjectLayer(newObject)
|
||||||
|
|
||||||
@@ -352,7 +354,7 @@ func initServer(ctx context.Context, newObject ObjectLayer) error {
|
|||||||
// All successful return.
|
// All successful return.
|
||||||
if globalIsDistErasure {
|
if globalIsDistErasure {
|
||||||
// These messages only meant primarily for distributed setup, so only log during distributed setup.
|
// These messages only meant primarily for distributed setup, so only log during distributed setup.
|
||||||
logger.Info("All MinIO sub-systems initialized successfully")
|
logger.Info("All MinIO sub-systems initialized successfully in %s", time.Since(t1))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ const (
|
|||||||
|
|
||||||
// diskMaxConcurrent is the maximum number of running concurrent operations
|
// diskMaxConcurrent is the maximum number of running concurrent operations
|
||||||
// for local and (incoming) remote disk ops respectively.
|
// for local and (incoming) remote disk ops respectively.
|
||||||
var diskMaxConcurrent = 50
|
var diskMaxConcurrent = 512
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if s, ok := os.LookupEnv("_MINIO_DISK_MAX_CONCURRENT"); ok && s != "" {
|
if s, ok := os.LookupEnv("_MINIO_DISK_MAX_CONCURRENT"); ok && s != "" {
|
||||||
|
|||||||
@@ -1691,7 +1691,7 @@ func (x xlMetaV2) ListVersions(volume, path string) ([]FileInfo, error) {
|
|||||||
// Quorum must be the minimum number of matching metadata files.
|
// Quorum must be the minimum number of matching metadata files.
|
||||||
// Quorum should be > 1 and <= len(versions).
|
// Quorum should be > 1 and <= len(versions).
|
||||||
// If strict is set to false, entries that match type
|
// If strict is set to false, entries that match type
|
||||||
func mergeXLV2Versions(quorum int, strict bool, versions ...[]xlMetaV2ShallowVersion) (merged []xlMetaV2ShallowVersion) {
|
func mergeXLV2Versions(quorum int, strict bool, requestedVersions int, versions ...[]xlMetaV2ShallowVersion) (merged []xlMetaV2ShallowVersion) {
|
||||||
if quorum <= 0 {
|
if quorum <= 0 {
|
||||||
quorum = 1
|
quorum = 1
|
||||||
}
|
}
|
||||||
@@ -1708,6 +1708,8 @@ func mergeXLV2Versions(quorum int, strict bool, versions ...[]xlMetaV2ShallowVer
|
|||||||
// Shallow copy input
|
// Shallow copy input
|
||||||
versions = append(make([][]xlMetaV2ShallowVersion, 0, len(versions)), versions...)
|
versions = append(make([][]xlMetaV2ShallowVersion, 0, len(versions)), versions...)
|
||||||
|
|
||||||
|
var nVersions int // captures all non-free versions
|
||||||
|
|
||||||
// Our result
|
// Our result
|
||||||
merged = make([]xlMetaV2ShallowVersion, 0, len(versions[0]))
|
merged = make([]xlMetaV2ShallowVersion, 0, len(versions[0]))
|
||||||
tops := make([]xlMetaV2ShallowVersion, len(versions))
|
tops := make([]xlMetaV2ShallowVersion, len(versions))
|
||||||
@@ -1744,6 +1746,12 @@ func mergeXLV2Versions(quorum int, strict bool, versions ...[]xlMetaV2ShallowVer
|
|||||||
latest = tops[0]
|
latest = tops[0]
|
||||||
latestCount = len(tops)
|
latestCount = len(tops)
|
||||||
merged = append(merged, latest)
|
merged = append(merged, latest)
|
||||||
|
|
||||||
|
// Calculate latest 'n' non-free versions.
|
||||||
|
if !latest.header.FreeVersion() {
|
||||||
|
nVersions++
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Find latest.
|
// Find latest.
|
||||||
for i, ver := range tops {
|
for i, ver := range tops {
|
||||||
@@ -1807,6 +1815,11 @@ func mergeXLV2Versions(quorum int, strict bool, versions ...[]xlMetaV2ShallowVer
|
|||||||
}
|
}
|
||||||
if latestCount >= quorum {
|
if latestCount >= quorum {
|
||||||
merged = append(merged, latest)
|
merged = append(merged, latest)
|
||||||
|
|
||||||
|
// Calculate latest 'n' non-free versions.
|
||||||
|
if !latest.header.FreeVersion() {
|
||||||
|
nVersions++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1840,7 +1853,13 @@ func mergeXLV2Versions(quorum int, strict bool, versions ...[]xlMetaV2ShallowVer
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if requestedVersions > 0 && requestedVersions == nVersions {
|
||||||
|
merged = append(merged, versions[0]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check. Enable if duplicates show up.
|
// Sanity check. Enable if duplicates show up.
|
||||||
if false {
|
if false {
|
||||||
found := make(map[[16]byte]struct{})
|
found := make(map[[16]byte]struct{})
|
||||||
|
|||||||
@@ -401,6 +401,55 @@ func TestDeleteVersionWithSharedDataDir(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_mergeXLV2Versions(b *testing.B) {
|
||||||
|
data, err := ioutil.ReadFile("testdata/xl.meta-v1.2.zst")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
dec, _ := zstd.NewReader(nil)
|
||||||
|
data, err = dec.DecodeAll(data, nil)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xl xlMetaV2
|
||||||
|
if err = xl.LoadOrConvert(data); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vers := make([][]xlMetaV2ShallowVersion, 16)
|
||||||
|
for i := range vers {
|
||||||
|
vers[i] = xl.versions
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run("requested-none", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
b.SetBytes(855) // number of versions...
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
mergeXLV2Versions(8, false, 0, vers...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("requested-v1", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
b.SetBytes(855) // number of versions...
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
mergeXLV2Versions(8, false, 1, vers...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("requested-v2", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
b.SetBytes(855) // number of versions...
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
mergeXLV2Versions(8, false, 1, vers...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func Benchmark_xlMetaV2Shallow_Load(b *testing.B) {
|
func Benchmark_xlMetaV2Shallow_Load(b *testing.B) {
|
||||||
data, err := ioutil.ReadFile("testdata/xl.meta-v1.2.zst")
|
data, err := ioutil.ReadFile("testdata/xl.meta-v1.2.zst")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -424,6 +473,7 @@ func Benchmark_xlMetaV2Shallow_Load(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
b.Run("indexed", func(b *testing.B) {
|
b.Run("indexed", func(b *testing.B) {
|
||||||
var xl xlMetaV2
|
var xl xlMetaV2
|
||||||
err = xl.Load(data)
|
err = xl.Load(data)
|
||||||
@@ -550,7 +600,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
|
|
||||||
for i := range vers {
|
for i := range vers {
|
||||||
t.Run(fmt.Sprintf("non-strict-q%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("non-strict-q%d", i), func(t *testing.T) {
|
||||||
merged := mergeXLV2Versions(i, false, vers...)
|
merged := mergeXLV2Versions(i, false, 0, vers...)
|
||||||
if len(merged) == 0 {
|
if len(merged) == 0 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -562,7 +612,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run(fmt.Sprintf("strict-q%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("strict-q%d", i), func(t *testing.T) {
|
||||||
merged := mergeXLV2Versions(i, true, vers...)
|
merged := mergeXLV2Versions(i, true, 0, vers...)
|
||||||
if len(merged) == 0 {
|
if len(merged) == 0 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -584,7 +634,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vMod = append(vMod, newVers)
|
vMod = append(vMod, newVers)
|
||||||
}
|
}
|
||||||
merged := mergeXLV2Versions(i, false, vMod...)
|
merged := mergeXLV2Versions(i, false, 0, vMod...)
|
||||||
if len(merged) == 0 {
|
if len(merged) == 0 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -606,7 +656,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vMod = append(vMod, newVers)
|
vMod = append(vMod, newVers)
|
||||||
}
|
}
|
||||||
merged := mergeXLV2Versions(i, false, vMod...)
|
merged := mergeXLV2Versions(i, false, 0, vMod...)
|
||||||
if len(merged) == 0 && i < 2 {
|
if len(merged) == 0 && i < 2 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -632,7 +682,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vMod = append(vMod, newVers)
|
vMod = append(vMod, newVers)
|
||||||
}
|
}
|
||||||
merged := mergeXLV2Versions(i, false, vMod...)
|
merged := mergeXLV2Versions(i, false, 0, vMod...)
|
||||||
if len(merged) == 0 {
|
if len(merged) == 0 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -654,7 +704,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vMod = append(vMod, newVers)
|
vMod = append(vMod, newVers)
|
||||||
}
|
}
|
||||||
merged := mergeXLV2Versions(i, false, vMod...)
|
merged := mergeXLV2Versions(i, false, 0, vMod...)
|
||||||
if len(merged) == 0 && i < 2 {
|
if len(merged) == 0 && i < 2 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -680,7 +730,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vMod = append(vMod, newVers)
|
vMod = append(vMod, newVers)
|
||||||
}
|
}
|
||||||
merged := mergeXLV2Versions(i, true, vMod...)
|
merged := mergeXLV2Versions(i, true, 0, vMod...)
|
||||||
if len(merged) == 0 && i < 2 {
|
if len(merged) == 0 && i < 2 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -706,7 +756,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vMod = append(vMod, newVers)
|
vMod = append(vMod, newVers)
|
||||||
}
|
}
|
||||||
merged := mergeXLV2Versions(i, true, vMod...)
|
merged := mergeXLV2Versions(i, true, 0, vMod...)
|
||||||
if len(merged) == 0 && i < 2 {
|
if len(merged) == 0 && i < 2 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -732,7 +782,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vMod = append(vMod, newVers)
|
vMod = append(vMod, newVers)
|
||||||
}
|
}
|
||||||
merged := mergeXLV2Versions(i, true, vMod...)
|
merged := mergeXLV2Versions(i, true, 0, vMod...)
|
||||||
if len(merged) == 0 && i < 2 {
|
if len(merged) == 0 && i < 2 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
@@ -758,7 +808,7 @@ func Test_mergeXLV2Versions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
vMod = append(vMod, newVers)
|
vMod = append(vMod, newVers)
|
||||||
}
|
}
|
||||||
merged := mergeXLV2Versions(i, true, vMod...)
|
merged := mergeXLV2Versions(i, true, 0, vMod...)
|
||||||
if len(merged) == 0 && i < 2 {
|
if len(merged) == 0 && i < 2 {
|
||||||
t.Error("Did not get any results")
|
t.Error("Did not get any results")
|
||||||
return
|
return
|
||||||
|
|||||||
+6
-6
@@ -88,9 +88,9 @@ Date: Mon Nov 8 08:41:27 2021 -0800
|
|||||||
λ git cherry-pick 4f3317effea38c203c358af9cb5ce3c0e4173976
|
λ git cherry-pick 4f3317effea38c203c358af9cb5ce3c0e4173976
|
||||||
```
|
```
|
||||||
|
|
||||||
*A self contained **patch** usually applies fine on the hotfix branch during backports as long it is self contained. There are situations however this may lead to conflicts and the patch will not cleanly apply. Conflicts might be trivial which can be resolved easily, when conflicts seem to be non-trivial or touches the part of the code-base the developer is not aware of - to get additional clarity reaching out of #hack on MinIOHQ slack channel is advised.*
|
*A self contained **patch** usually applies fine on the hotfix branch during backports as long it is self contained. There are situations however this may lead to conflicts and the patch will not cleanly apply. Conflicts might be trivial which can be resolved easily, when conflicts seem to be non-trivial or touches the part of the code-base the developer is not confident - to get additional clarity reach out to #hack on MinIOHQ slack channel. Hasty changes must be avoided, minor fixes and logs may be added to hotfix branches but this should not be followed as practice.*
|
||||||
|
|
||||||
Once the **patch** is successfully applied, developer must run tests to alidate the fix that was backported by running following tests, locally.
|
Once the **patch** is successfully applied, developer must run tests to validate the fix that was backported by running following tests, locally.
|
||||||
|
|
||||||
Unit tests
|
Unit tests
|
||||||
|
|
||||||
@@ -116,16 +116,16 @@ At this point in time the backport is ready to be submitted as a pull request to
|
|||||||
|
|
||||||
To add a hotfix tag to the binary version and embed the relevant `commit-id` following build helpers are available
|
To add a hotfix tag to the binary version and embed the relevant `commit-id` following build helpers are available
|
||||||
|
|
||||||
#### Builds the hotfix binary
|
#### Builds the hotfix binary and uploads to https;//dl.min.io
|
||||||
|
|
||||||
```
|
```
|
||||||
λ CRED_DIR=/media/builder/minio make hotfix
|
λ CRED_DIR=/media/builder/minio make hotfix-push
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Builds the hotfix container
|
#### Builds the hotfix container and pushes to docker.io/minio/minio
|
||||||
|
|
||||||
```
|
```
|
||||||
λ CRED_DIR=/media/builder/minio make docker-hotfix
|
λ CRED_DIR=/media/builder/minio make docker-hotfix-push
|
||||||
```
|
```
|
||||||
|
|
||||||
Once this has been provided to the customer relevant binary will be uploaded from our *release server* securely, directly to <https://dl.minio.io/server/minio/hotfixes/archive/>
|
Once this has been provided to the customer relevant binary will be uploaded from our *release server* securely, directly to <https://dl.minio.io/server/minio/hotfixes/archive/>
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
# The address:port of the kes server - i.e. on the local machine.
|
|
||||||
address = "127.0.0.1:7373"
|
|
||||||
|
|
||||||
[tls]
|
|
||||||
key = "./kes-tls.key"
|
|
||||||
cert = "./kes-tls.crt"
|
|
||||||
|
|
||||||
[policy.minio]
|
|
||||||
paths = [
|
|
||||||
"/v1/key/create/minio-*",
|
|
||||||
"/v1/key/generate/minio-*",
|
|
||||||
"/v1/key/decrypt/minio-*"
|
|
||||||
]
|
|
||||||
identities = [ "dd46485bedc9ad2909d2e8f9017216eec4413bc5c64b236d992f7ec19c843c5f" ]
|
|
||||||
|
|
||||||
[cache.expiry]
|
|
||||||
all = "5m"
|
|
||||||
unused = "20s"
|
|
||||||
|
|
||||||
[keystore.vault]
|
|
||||||
address = "https://127.0.0.1:8200" # The Vault endpoint - i.e. https://127.0.0.1:8200
|
|
||||||
name = "minio" # The domain resp. prefix at Vault's K/V backend
|
|
||||||
|
|
||||||
[keystore.vault.approle]
|
|
||||||
id = "" # Your AppRole Role ID
|
|
||||||
secret = "" # Your AppRole Secret ID
|
|
||||||
retry = "15s" # Duration until the server tries to re-authenticate after connection loss.
|
|
||||||
|
|
||||||
[keystore.vault.tls]
|
|
||||||
ca = "./vault-tls.crt" # Since we use self-signed certificates
|
|
||||||
|
|
||||||
[keystore.vault.status]
|
|
||||||
ping = "10s"
|
|
||||||
@@ -2,7 +2,7 @@ version: '3.7'
|
|||||||
|
|
||||||
# Settings and configurations that are common for all containers
|
# Settings and configurations that are common for all containers
|
||||||
x-minio-common: &minio-common
|
x-minio-common: &minio-common
|
||||||
image: quay.io/minio/minio:RELEASE.2022-03-17T06-34-49Z
|
image: quay.io/minio/minio:RELEASE.2022-03-24T00-43-44Z
|
||||||
command: server --console-address ":9001" http://minio{1...4}/data{1...2}
|
command: server --console-address ":9001" http://minio{1...4}/data{1...2}
|
||||||
expose:
|
expose:
|
||||||
- "9000"
|
- "9000"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module github.com/minio/minio
|
module github.com/minio/minio
|
||||||
|
|
||||||
go 1.17
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/storage v1.10.0
|
cloud.google.com/go/storage v1.10.0
|
||||||
@@ -45,11 +45,11 @@ require (
|
|||||||
github.com/lib/pq v1.10.4
|
github.com/lib/pq v1.10.4
|
||||||
github.com/miekg/dns v1.1.46
|
github.com/miekg/dns v1.1.46
|
||||||
github.com/minio/cli v1.22.0
|
github.com/minio/cli v1.22.0
|
||||||
github.com/minio/console v0.15.4
|
github.com/minio/console v0.15.6
|
||||||
github.com/minio/csvparser v1.0.0
|
github.com/minio/csvparser v1.0.0
|
||||||
github.com/minio/dperf v0.3.4
|
github.com/minio/dperf v0.3.4
|
||||||
github.com/minio/highwayhash v1.0.2
|
github.com/minio/highwayhash v1.0.2
|
||||||
github.com/minio/kes v0.18.0
|
github.com/minio/kes v0.19.0
|
||||||
github.com/minio/madmin-go v1.3.5
|
github.com/minio/madmin-go v1.3.5
|
||||||
github.com/minio/minio-go/v7 v7.0.23
|
github.com/minio/minio-go/v7 v7.0.23
|
||||||
github.com/minio/parquet-go v1.1.0
|
github.com/minio/parquet-go v1.1.0
|
||||||
@@ -95,136 +95,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.100.2 // indirect
|
|
||||||
cloud.google.com/go/compute v0.1.0 // indirect
|
|
||||||
cloud.google.com/go/iam v0.2.0 // indirect
|
cloud.google.com/go/iam v0.2.0 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
|
|
||||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
|
||||||
github.com/apache/thrift v0.15.0 // indirect
|
|
||||||
github.com/armon/go-metrics v0.3.3 // indirect
|
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
|
||||||
github.com/bits-and-blooms/bitset v1.2.0 // indirect
|
|
||||||
github.com/charmbracelet/bubbles v0.10.3 // indirect
|
|
||||||
github.com/charmbracelet/bubbletea v0.20.0 // indirect
|
|
||||||
github.com/charmbracelet/lipgloss v0.5.0 // indirect
|
|
||||||
github.com/containerd/console v1.0.3 // indirect
|
|
||||||
github.com/coreos/go-semver v0.3.0 // indirect
|
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
|
||||||
github.com/eapache/go-resiliency v1.2.0 // indirect
|
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
|
|
||||||
github.com/eapache/queue v1.1.0 // indirect
|
|
||||||
github.com/fatih/structs v1.1.0 // indirect
|
|
||||||
github.com/frankban/quicktest v1.14.0 // indirect
|
|
||||||
github.com/gdamore/encoding v1.0.0 // indirect
|
|
||||||
github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1 // indirect
|
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.1 // indirect
|
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
|
||||||
github.com/go-openapi/analysis v0.21.2 // indirect
|
|
||||||
github.com/go-openapi/errors v0.20.2 // indirect
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
|
||||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
|
||||||
github.com/go-openapi/runtime v0.23.1 // indirect
|
|
||||||
github.com/go-openapi/spec v0.20.4 // indirect
|
|
||||||
github.com/go-openapi/strfmt v0.21.2 // indirect
|
|
||||||
github.com/go-openapi/swag v0.21.1 // indirect
|
|
||||||
github.com/go-openapi/validate v0.21.0 // indirect
|
|
||||||
github.com/go-stack/stack v1.8.1 // indirect
|
|
||||||
github.com/goccy/go-json v0.9.4 // indirect
|
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
|
||||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
|
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
|
||||||
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
|
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
|
||||||
github.com/hashicorp/go-immutable-radix v1.1.0 // indirect
|
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
|
||||||
github.com/hashicorp/go-uuid v1.0.2 // indirect
|
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
|
|
||||||
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
|
|
||||||
github.com/jcmturner/gofork v1.0.0 // indirect
|
|
||||||
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
|
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
|
||||||
github.com/jessevdk/go-flags v1.5.0 // indirect
|
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
|
||||||
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
|
|
||||||
github.com/lestrrat-go/blackmagic v1.0.0 // indirect
|
|
||||||
github.com/lestrrat-go/httpcc v1.0.0 // indirect
|
|
||||||
github.com/lestrrat-go/iter v1.0.1 // indirect
|
|
||||||
github.com/lestrrat-go/jwx v1.2.19 // indirect
|
|
||||||
github.com/lestrrat-go/option v1.0.0 // indirect
|
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
|
||||||
github.com/mattn/go-ieproxy v0.0.1 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
|
||||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
|
||||||
github.com/minio/argon2 v1.0.0 // indirect
|
|
||||||
github.com/minio/colorjson v1.0.1 // indirect
|
|
||||||
github.com/minio/filepath v1.0.0 // indirect
|
|
||||||
github.com/minio/mc v0.0.0-20220302011226-f13defa54577 // indirect
|
|
||||||
github.com/minio/md5-simd v1.1.2 // indirect
|
|
||||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
|
||||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
|
|
||||||
github.com/muesli/reflow v0.3.0 // indirect
|
|
||||||
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 // indirect
|
|
||||||
github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 // indirect
|
|
||||||
github.com/nats-io/nats-streaming-server v0.24.1 // indirect
|
github.com/nats-io/nats-streaming-server v0.24.1 // indirect
|
||||||
github.com/nats-io/nkeys v0.3.0 // indirect
|
|
||||||
github.com/nats-io/nuid v1.0.1 // indirect
|
|
||||||
github.com/navidys/tvxwidgets v0.1.0 // indirect
|
|
||||||
github.com/oklog/ulid v1.3.1 // indirect
|
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
|
||||||
github.com/pkg/xattr v0.4.5 // indirect
|
|
||||||
github.com/posener/complete v1.2.3 // indirect
|
|
||||||
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect
|
|
||||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 // indirect
|
|
||||||
github.com/prometheus/common v0.32.1 // indirect
|
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
|
||||||
github.com/rivo/tview v0.0.0-20220216162559-96063d6082f3 // indirect
|
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
|
||||||
github.com/rjeczalik/notify v0.9.2 // indirect
|
|
||||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
|
||||||
github.com/rs/xid v1.3.0 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
|
||||||
github.com/tidwall/gjson v1.14.0 // indirect
|
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
|
||||||
github.com/tidwall/pretty v1.2.0 // indirect
|
|
||||||
github.com/tidwall/sjson v1.2.3 // indirect
|
|
||||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
|
||||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
|
||||||
github.com/unrolled/secure v1.10.0 // indirect
|
|
||||||
github.com/xdg/stringprep v1.0.0 // indirect
|
github.com/xdg/stringprep v1.0.0 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.2 // indirect
|
|
||||||
go.mongodb.org/mongo-driver v1.8.4 // indirect
|
|
||||||
go.opencensus.io v0.23.0 // indirect
|
|
||||||
go.uber.org/multierr v1.8.0 // indirect
|
|
||||||
golang.org/x/mod v0.5.1 // indirect
|
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
|
||||||
golang.org/x/text v0.3.7 // indirect
|
|
||||||
golang.org/x/tools v0.1.8 // indirect
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
|
||||||
google.golang.org/genproto v0.0.0-20220302033224-9aa15565e42a // indirect
|
|
||||||
google.golang.org/grpc v1.44.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
|
||||||
gopkg.in/h2non/filetype.v1 v1.0.5 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
|
||||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
|
||||||
maze.io/x/duration v0.0.0-20160924141736-faac084b6075 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
Binary file not shown.
@@ -1,8 +1,8 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
name: minio
|
name: minio
|
||||||
version: 3.6.2
|
version: 3.6.3
|
||||||
appVersion: RELEASE.2022-03-17T06-34-49Z
|
appVersion: RELEASE.2022-03-24T00-43-44Z
|
||||||
keywords:
|
keywords:
|
||||||
- minio
|
- minio
|
||||||
- storage
|
- storage
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ clusterDomain: cluster.local
|
|||||||
##
|
##
|
||||||
image:
|
image:
|
||||||
repository: quay.io/minio/minio
|
repository: quay.io/minio/minio
|
||||||
tag: RELEASE.2022-03-17T06-34-49Z
|
tag: RELEASE.2022-03-24T00-43-44Z
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
@@ -25,7 +25,7 @@ imagePullSecrets: []
|
|||||||
##
|
##
|
||||||
mcImage:
|
mcImage:
|
||||||
repository: quay.io/minio/mc
|
repository: quay.io/minio/mc
|
||||||
tag: RELEASE.2022-03-17T07-21-29Z
|
tag: RELEASE.2022-03-17T20-25-06Z
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
## minio mode, i.e. standalone or distributed or gateway.
|
## minio mode, i.e. standalone or distributed or gateway.
|
||||||
|
|||||||
+72
-50
@@ -1,9 +1,31 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
entries:
|
entries:
|
||||||
minio:
|
minio:
|
||||||
|
- apiVersion: v1
|
||||||
|
appVersion: RELEASE.2022-03-24T00-43-44Z
|
||||||
|
created: "2022-03-23T21:06:44.793706115-07:00"
|
||||||
|
description: Multi-Cloud Object Storage
|
||||||
|
digest: 99508b20eb0083a567dcccaf9a6c237e09575ed1d70cd2e8333f89c472d13d75
|
||||||
|
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.6.3.tgz
|
||||||
|
version: 3.6.3
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-03-17T06-34-49Z
|
appVersion: RELEASE.2022-03-17T06-34-49Z
|
||||||
created: "2022-03-17T11:30:33.757280715-07:00"
|
created: "2022-03-23T21:06:44.792478365-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: b4cd25611ca322b1d23d23112fdfa6b068fd91eefe0b0663b88ff87ea4282495
|
digest: b4cd25611ca322b1d23d23112fdfa6b068fd91eefe0b0663b88ff87ea4282495
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -25,7 +47,7 @@ entries:
|
|||||||
version: 3.6.2
|
version: 3.6.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-03-14T18-25-24Z
|
appVersion: RELEASE.2022-03-14T18-25-24Z
|
||||||
created: "2022-03-17T11:30:33.756066239-07:00"
|
created: "2022-03-23T21:06:44.790639016-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: d75b88162bfe54740a233bcecf87328bba2ae23d170bec3a35c828bc6fdc224c
|
digest: d75b88162bfe54740a233bcecf87328bba2ae23d170bec3a35c828bc6fdc224c
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -47,7 +69,7 @@ entries:
|
|||||||
version: 3.6.1
|
version: 3.6.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-03-11T23-57-45Z
|
appVersion: RELEASE.2022-03-11T23-57-45Z
|
||||||
created: "2022-03-17T11:30:33.754919744-07:00"
|
created: "2022-03-23T21:06:44.789351564-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 22e53a1184a21a679bc7d8b94e955777f3506340fc29da5ab0cb6d729bdbde8d
|
digest: 22e53a1184a21a679bc7d8b94e955777f3506340fc29da5ab0cb6d729bdbde8d
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -69,7 +91,7 @@ entries:
|
|||||||
version: 3.6.0
|
version: 3.6.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-03-03T21-21-16Z
|
appVersion: RELEASE.2022-03-03T21-21-16Z
|
||||||
created: "2022-03-17T11:30:33.75375483-07:00"
|
created: "2022-03-23T21:06:44.788117819-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 6fda968d3fdfd60470c0055a4e1a3bd8e5aee9ad0af5ba2fb7b7b926fdc9e4a0
|
digest: 6fda968d3fdfd60470c0055a4e1a3bd8e5aee9ad0af5ba2fb7b7b926fdc9e4a0
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -91,7 +113,7 @@ entries:
|
|||||||
version: 3.5.9
|
version: 3.5.9
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-26T02-54-46Z
|
appVersion: RELEASE.2022-02-26T02-54-46Z
|
||||||
created: "2022-03-17T11:30:33.752191366-07:00"
|
created: "2022-03-23T21:06:44.786549387-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 8e015369048a3a82bbd53ad36696786f18561c6b25d14eee9e2c93a7336cef46
|
digest: 8e015369048a3a82bbd53ad36696786f18561c6b25d14eee9e2c93a7336cef46
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -113,7 +135,7 @@ entries:
|
|||||||
version: 3.5.8
|
version: 3.5.8
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-18T01-50-10Z
|
appVersion: RELEASE.2022-02-18T01-50-10Z
|
||||||
created: "2022-03-17T11:30:33.750997867-07:00"
|
created: "2022-03-23T21:06:44.785265725-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: cb3543fe748e5f0d59b3ccf4ab9af8e10b731405ae445d1f5715e30013632373
|
digest: cb3543fe748e5f0d59b3ccf4ab9af8e10b731405ae445d1f5715e30013632373
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -135,7 +157,7 @@ entries:
|
|||||||
version: 3.5.7
|
version: 3.5.7
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-18T01-50-10Z
|
appVersion: RELEASE.2022-02-18T01-50-10Z
|
||||||
created: "2022-03-17T11:30:33.749693279-07:00"
|
created: "2022-03-23T21:06:44.783518199-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: f2e359fa5eefffc59abb3d14a8fa94b11ddeaa99f6cd8dd5f40f4e04121000d6
|
digest: f2e359fa5eefffc59abb3d14a8fa94b11ddeaa99f6cd8dd5f40f4e04121000d6
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -157,7 +179,7 @@ entries:
|
|||||||
version: 3.5.6
|
version: 3.5.6
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-16T00-35-27Z
|
appVersion: RELEASE.2022-02-16T00-35-27Z
|
||||||
created: "2022-03-17T11:30:33.748559583-07:00"
|
created: "2022-03-23T21:06:44.782211855-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 529d56cca9d83a3d0e5672e63b6e87b5bcbe10a6b45f7a55ba998cceb32f9c81
|
digest: 529d56cca9d83a3d0e5672e63b6e87b5bcbe10a6b45f7a55ba998cceb32f9c81
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -179,7 +201,7 @@ entries:
|
|||||||
version: 3.5.5
|
version: 3.5.5
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-12T00-51-25Z
|
appVersion: RELEASE.2022-02-12T00-51-25Z
|
||||||
created: "2022-03-17T11:30:33.747490381-07:00"
|
created: "2022-03-23T21:06:44.780903215-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 3d530598f8ece67bec5b7f990d206584893987c713502f9228e4ee24b5535414
|
digest: 3d530598f8ece67bec5b7f990d206584893987c713502f9228e4ee24b5535414
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -201,7 +223,7 @@ entries:
|
|||||||
version: 3.5.4
|
version: 3.5.4
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-12T00-51-25Z
|
appVersion: RELEASE.2022-02-12T00-51-25Z
|
||||||
created: "2022-03-17T11:30:33.746356502-07:00"
|
created: "2022-03-23T21:06:44.779556381-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 53937031348b29615f07fc4869b2d668391d8ba9084630a497abd7a7dea9dfb0
|
digest: 53937031348b29615f07fc4869b2d668391d8ba9084630a497abd7a7dea9dfb0
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -223,7 +245,7 @@ entries:
|
|||||||
version: 3.5.3
|
version: 3.5.3
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-07T08-17-33Z
|
appVersion: RELEASE.2022-02-07T08-17-33Z
|
||||||
created: "2022-03-17T11:30:33.744779034-07:00"
|
created: "2022-03-23T21:06:44.778364019-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 68d643414ff0d565716c5715034fcbf1af262e041915a5c02eb51ec1a65c1ea0
|
digest: 68d643414ff0d565716c5715034fcbf1af262e041915a5c02eb51ec1a65c1ea0
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -245,7 +267,7 @@ entries:
|
|||||||
version: 3.5.2
|
version: 3.5.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-01T18-00-14Z
|
appVersion: RELEASE.2022-02-01T18-00-14Z
|
||||||
created: "2022-03-17T11:30:33.743778208-07:00"
|
created: "2022-03-23T21:06:44.777066403-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: a3e855ed0f31233b989fffd775a29d6fbfa0590089010ff16783fd7f142ef6e7
|
digest: a3e855ed0f31233b989fffd775a29d6fbfa0590089010ff16783fd7f142ef6e7
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -267,7 +289,7 @@ entries:
|
|||||||
version: 3.5.1
|
version: 3.5.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-02-01T18-00-14Z
|
appVersion: RELEASE.2022-02-01T18-00-14Z
|
||||||
created: "2022-03-17T11:30:33.742329869-07:00"
|
created: "2022-03-23T21:06:44.77532758-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: b1b0ae3c54b4260a698753e11d7781bb8ddc67b7e3fbf0af82796e4cd4ef92a3
|
digest: b1b0ae3c54b4260a698753e11d7781bb8ddc67b7e3fbf0af82796e4cd4ef92a3
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -289,7 +311,7 @@ entries:
|
|||||||
version: 3.5.0
|
version: 3.5.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-01-28T02-28-16Z
|
appVersion: RELEASE.2022-01-28T02-28-16Z
|
||||||
created: "2022-03-17T11:30:33.74099405-07:00"
|
created: "2022-03-23T21:06:44.77418347-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: fecf25d2d3fb208c6f894fed642a60780a570b7f6d0adddde846af7236dc80aa
|
digest: fecf25d2d3fb208c6f894fed642a60780a570b7f6d0adddde846af7236dc80aa
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -311,7 +333,7 @@ entries:
|
|||||||
version: 3.4.8
|
version: 3.4.8
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-01-25T19-56-04Z
|
appVersion: RELEASE.2022-01-25T19-56-04Z
|
||||||
created: "2022-03-17T11:30:33.739899902-07:00"
|
created: "2022-03-23T21:06:44.773013848-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: c78008caa5ce98f64c887630f59d0cbd481cb3f19a7d4e9d3e81bf4e1e45cadc
|
digest: c78008caa5ce98f64c887630f59d0cbd481cb3f19a7d4e9d3e81bf4e1e45cadc
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -333,7 +355,7 @@ entries:
|
|||||||
version: 3.4.7
|
version: 3.4.7
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-01-08T03-11-54Z
|
appVersion: RELEASE.2022-01-08T03-11-54Z
|
||||||
created: "2022-03-17T11:30:33.738917811-07:00"
|
created: "2022-03-23T21:06:44.771918434-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 8f2e2691bf897f74ff094dd370ec56ba9d417e5e8926710c14c2ba346330238d
|
digest: 8f2e2691bf897f74ff094dd370ec56ba9d417e5e8926710c14c2ba346330238d
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -355,7 +377,7 @@ entries:
|
|||||||
version: 3.4.6
|
version: 3.4.6
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2022-01-04T07-41-07Z
|
appVersion: RELEASE.2022-01-04T07-41-07Z
|
||||||
created: "2022-03-17T11:30:33.737896781-07:00"
|
created: "2022-03-23T21:06:44.770733259-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: bacd140f0016fab35f516bde787da6449b3a960c071fad9e4b6563118033ac84
|
digest: bacd140f0016fab35f516bde787da6449b3a960c071fad9e4b6563118033ac84
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -377,7 +399,7 @@ entries:
|
|||||||
version: 3.4.5
|
version: 3.4.5
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-12-29T06-49-06Z
|
appVersion: RELEASE.2021-12-29T06-49-06Z
|
||||||
created: "2022-03-17T11:30:33.736403111-07:00"
|
created: "2022-03-23T21:06:44.769538258-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 48a453ea5ffeef25933904caefd9470bfb26224dfc2d1096bd0031467ba53007
|
digest: 48a453ea5ffeef25933904caefd9470bfb26224dfc2d1096bd0031467ba53007
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -399,7 +421,7 @@ entries:
|
|||||||
version: 3.4.4
|
version: 3.4.4
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-12-20T22-07-16Z
|
appVersion: RELEASE.2021-12-20T22-07-16Z
|
||||||
created: "2022-03-17T11:30:33.734491816-07:00"
|
created: "2022-03-23T21:06:44.7676082-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 47ef4a930713b98f9438ceca913c6e700f85bb25dba5624b056486254b5f0c60
|
digest: 47ef4a930713b98f9438ceca913c6e700f85bb25dba5624b056486254b5f0c60
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -421,7 +443,7 @@ entries:
|
|||||||
version: 3.4.3
|
version: 3.4.3
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-12-20T22-07-16Z
|
appVersion: RELEASE.2021-12-20T22-07-16Z
|
||||||
created: "2022-03-17T11:30:33.733388694-07:00"
|
created: "2022-03-23T21:06:44.766512145-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: d6763f7e2ea66810bd55eb225579a9c3b968f9ae1256f45fd469362e55d846ff
|
digest: d6763f7e2ea66810bd55eb225579a9c3b968f9ae1256f45fd469362e55d846ff
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -443,7 +465,7 @@ entries:
|
|||||||
version: 3.4.2
|
version: 3.4.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-12-10T23-03-39Z
|
appVersion: RELEASE.2021-12-10T23-03-39Z
|
||||||
created: "2022-03-17T11:30:33.732316283-07:00"
|
created: "2022-03-23T21:06:44.765594753-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 2fb822c87216ba3fc2ae51a54a0a3e239aa560d86542991504a841cc2a2b9a37
|
digest: 2fb822c87216ba3fc2ae51a54a0a3e239aa560d86542991504a841cc2a2b9a37
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -465,7 +487,7 @@ entries:
|
|||||||
version: 3.4.1
|
version: 3.4.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-12-18T04-42-33Z
|
appVersion: RELEASE.2021-12-18T04-42-33Z
|
||||||
created: "2022-03-17T11:30:33.731309428-07:00"
|
created: "2022-03-23T21:06:44.76437481-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: fa8ba1aeb1a15316c6be8403416a5e6b5e6139b7166592087e7bddc9e6db5453
|
digest: fa8ba1aeb1a15316c6be8403416a5e6b5e6139b7166592087e7bddc9e6db5453
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -487,7 +509,7 @@ entries:
|
|||||||
version: 3.4.0
|
version: 3.4.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-12-10T23-03-39Z
|
appVersion: RELEASE.2021-12-10T23-03-39Z
|
||||||
created: "2022-03-17T11:30:33.730285634-07:00"
|
created: "2022-03-23T21:06:44.763226393-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: b9b0af9ca50b8d00868e1f1b989dca275829d9110af6de91bb9b3a398341e894
|
digest: b9b0af9ca50b8d00868e1f1b989dca275829d9110af6de91bb9b3a398341e894
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -509,7 +531,7 @@ entries:
|
|||||||
version: 3.3.4
|
version: 3.3.4
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-12-10T23-03-39Z
|
appVersion: RELEASE.2021-12-10T23-03-39Z
|
||||||
created: "2022-03-17T11:30:33.729291768-07:00"
|
created: "2022-03-23T21:06:44.762111446-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: f8b22a5b8fe95a7ddf61b825e17d11c9345fb10e4c126b0d78381608aa300a08
|
digest: f8b22a5b8fe95a7ddf61b825e17d11c9345fb10e4c126b0d78381608aa300a08
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -531,7 +553,7 @@ entries:
|
|||||||
version: 3.3.3
|
version: 3.3.3
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-12-10T23-03-39Z
|
appVersion: RELEASE.2021-12-10T23-03-39Z
|
||||||
created: "2022-03-17T11:30:33.728256537-07:00"
|
created: "2022-03-23T21:06:44.760903355-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: c48d474f269427abe5ab446f00687d0625b3d1adfc5c73bdb4b21ca9e42853fb
|
digest: c48d474f269427abe5ab446f00687d0625b3d1adfc5c73bdb4b21ca9e42853fb
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -553,7 +575,7 @@ entries:
|
|||||||
version: 3.3.2
|
version: 3.3.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-11-24T23-19-33Z
|
appVersion: RELEASE.2021-11-24T23-19-33Z
|
||||||
created: "2022-03-17T11:30:33.726888242-07:00"
|
created: "2022-03-23T21:06:44.759169595-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 7c3da39d9b0090cbf5efedf0cc163a1e2df05becc5152c3add8e837384690bc4
|
digest: 7c3da39d9b0090cbf5efedf0cc163a1e2df05becc5152c3add8e837384690bc4
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -575,7 +597,7 @@ entries:
|
|||||||
version: 3.3.1
|
version: 3.3.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-11-24T23-19-33Z
|
appVersion: RELEASE.2021-11-24T23-19-33Z
|
||||||
created: "2022-03-17T11:30:33.725931133-07:00"
|
created: "2022-03-23T21:06:44.757570962-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 50d6590b4cc779c40f81cc13b1586fbe508aa7f3230036c760bfc5f4154fbce4
|
digest: 50d6590b4cc779c40f81cc13b1586fbe508aa7f3230036c760bfc5f4154fbce4
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -597,7 +619,7 @@ entries:
|
|||||||
version: 3.3.0
|
version: 3.3.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-10-13T00-23-17Z
|
appVersion: RELEASE.2021-10-13T00-23-17Z
|
||||||
created: "2022-03-17T11:30:33.724769561-07:00"
|
created: "2022-03-23T21:06:44.756372619-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 5b797b7208cd904c11a76cd72938c8652160cb5fcd7f09fa41e4e703e6d64054
|
digest: 5b797b7208cd904c11a76cd72938c8652160cb5fcd7f09fa41e4e703e6d64054
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -619,7 +641,7 @@ entries:
|
|||||||
version: 3.2.0
|
version: 3.2.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-10-10T16-53-30Z
|
appVersion: RELEASE.2021-10-10T16-53-30Z
|
||||||
created: "2022-03-17T11:30:33.723804755-07:00"
|
created: "2022-03-23T21:06:44.755234538-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: e084ac4bb095f071e59f8f08bd092e4ab2404c1ddadacfdce7dbe248f1bafff8
|
digest: e084ac4bb095f071e59f8f08bd092e4ab2404c1ddadacfdce7dbe248f1bafff8
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -641,7 +663,7 @@ entries:
|
|||||||
version: 3.1.9
|
version: 3.1.9
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-10-06T23-36-31Z
|
appVersion: RELEASE.2021-10-06T23-36-31Z
|
||||||
created: "2022-03-17T11:30:33.722848549-07:00"
|
created: "2022-03-23T21:06:44.754118063-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 2890430a8d9487d1fa5508c26776e4881d0086b2c052aa6bdc65c0e4423b9159
|
digest: 2890430a8d9487d1fa5508c26776e4881d0086b2c052aa6bdc65c0e4423b9159
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -663,7 +685,7 @@ entries:
|
|||||||
version: 3.1.8
|
version: 3.1.8
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-10-02T16-31-05Z
|
appVersion: RELEASE.2021-10-02T16-31-05Z
|
||||||
created: "2022-03-17T11:30:33.721885872-07:00"
|
created: "2022-03-23T21:06:44.752913852-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 01a92196af6c47e3a01e1c68d7cf693a8bc487cba810c2cecff155071e4d6a11
|
digest: 01a92196af6c47e3a01e1c68d7cf693a8bc487cba810c2cecff155071e4d6a11
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -685,7 +707,7 @@ entries:
|
|||||||
version: 3.1.7
|
version: 3.1.7
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-09-18T18-09-59Z
|
appVersion: RELEASE.2021-09-18T18-09-59Z
|
||||||
created: "2022-03-17T11:30:33.720537482-07:00"
|
created: "2022-03-23T21:06:44.751805247-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: e779d73f80b75f33b9c9d995ab10fa455c9c57ee575ebc54e06725a64cd04310
|
digest: e779d73f80b75f33b9c9d995ab10fa455c9c57ee575ebc54e06725a64cd04310
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -707,7 +729,7 @@ entries:
|
|||||||
version: 3.1.6
|
version: 3.1.6
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-09-18T18-09-59Z
|
appVersion: RELEASE.2021-09-18T18-09-59Z
|
||||||
created: "2022-03-17T11:30:33.71900182-07:00"
|
created: "2022-03-23T21:06:44.750080597-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 19de4bbc8a400f0c2a94c5e85fc25c9bfc666e773fb3e368dd621d5a57dd1c2a
|
digest: 19de4bbc8a400f0c2a94c5e85fc25c9bfc666e773fb3e368dd621d5a57dd1c2a
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -729,7 +751,7 @@ entries:
|
|||||||
version: 3.1.5
|
version: 3.1.5
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-09-18T18-09-59Z
|
appVersion: RELEASE.2021-09-18T18-09-59Z
|
||||||
created: "2022-03-17T11:30:33.71807513-07:00"
|
created: "2022-03-23T21:06:44.749074579-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: f789d93a171296dd01af0105a5ce067c663597afbb2432faeda293b752b355c0
|
digest: f789d93a171296dd01af0105a5ce067c663597afbb2432faeda293b752b355c0
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -751,7 +773,7 @@ entries:
|
|||||||
version: 3.1.4
|
version: 3.1.4
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||||
created: "2022-03-17T11:30:33.717129118-07:00"
|
created: "2022-03-23T21:06:44.748000876-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: e2eb34d31560b012ef6581f0ff6004ea4376c968cbe0daed2d8f3a614a892afb
|
digest: e2eb34d31560b012ef6581f0ff6004ea4376c968cbe0daed2d8f3a614a892afb
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -773,7 +795,7 @@ entries:
|
|||||||
version: 3.1.3
|
version: 3.1.3
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||||
created: "2022-03-17T11:30:33.716162478-07:00"
|
created: "2022-03-23T21:06:44.746861195-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 8d7e0cc46b3583abd71b97dc0c071f98321101f90eca17348f1e9e0831be64cd
|
digest: 8d7e0cc46b3583abd71b97dc0c071f98321101f90eca17348f1e9e0831be64cd
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -795,7 +817,7 @@ entries:
|
|||||||
version: 3.1.2
|
version: 3.1.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||||
created: "2022-03-17T11:30:33.715195889-07:00"
|
created: "2022-03-23T21:06:44.745725291-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 50dcbf366b1b21f4a6fc429d0b884c0c7ff481d0fb95c5e9b3ae157c348dd124
|
digest: 50dcbf366b1b21f4a6fc429d0b884c0c7ff481d0fb95c5e9b3ae157c348dd124
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -817,7 +839,7 @@ entries:
|
|||||||
version: 3.1.1
|
version: 3.1.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-09-09T21-37-07Z
|
appVersion: RELEASE.2021-09-09T21-37-07Z
|
||||||
created: "2022-03-17T11:30:33.714138645-07:00"
|
created: "2022-03-23T21:06:44.744677475-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 6c01af55d2e2e5f716eabf6fef3a92a8464d0674529e9bacab292e5478a73b7a
|
digest: 6c01af55d2e2e5f716eabf6fef3a92a8464d0674529e9bacab292e5478a73b7a
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -839,7 +861,7 @@ entries:
|
|||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-09-03T03-56-13Z
|
appVersion: RELEASE.2021-09-03T03-56-13Z
|
||||||
created: "2022-03-17T11:30:33.712713375-07:00"
|
created: "2022-03-23T21:06:44.743254312-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 18e10be4d0458bc590ca9abf753227e0c70f60511495387b8d4fb15a4daf932e
|
digest: 18e10be4d0458bc590ca9abf753227e0c70f60511495387b8d4fb15a4daf932e
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -861,7 +883,7 @@ entries:
|
|||||||
version: 3.0.2
|
version: 3.0.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-31T05-46-54Z
|
appVersion: RELEASE.2021-08-31T05-46-54Z
|
||||||
created: "2022-03-17T11:30:33.711866996-07:00"
|
created: "2022-03-23T21:06:44.74197572-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: f5b6e7f6272a9e71aef3b75555f6f756a39eef65cb78873f26451dba79b19906
|
digest: f5b6e7f6272a9e71aef3b75555f6f756a39eef65cb78873f26451dba79b19906
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -883,7 +905,7 @@ entries:
|
|||||||
version: 3.0.1
|
version: 3.0.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-31T05-46-54Z
|
appVersion: RELEASE.2021-08-31T05-46-54Z
|
||||||
created: "2022-03-17T11:30:33.711013642-07:00"
|
created: "2022-03-23T21:06:44.738596434-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 6d2ee1336c412affaaf209fdb80215be2a6ebb23ab2443adbaffef9e7df13fab
|
digest: 6d2ee1336c412affaaf209fdb80215be2a6ebb23ab2443adbaffef9e7df13fab
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -905,7 +927,7 @@ entries:
|
|||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-31T05-46-54Z
|
appVersion: RELEASE.2021-08-31T05-46-54Z
|
||||||
created: "2022-03-17T11:30:33.710116847-07:00"
|
created: "2022-03-23T21:06:44.737408609-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 0a004aaf5bb61deed6a5c88256d1695ebe2f9ff1553874a93e4acfd75e8d339b
|
digest: 0a004aaf5bb61deed6a5c88256d1695ebe2f9ff1553874a93e4acfd75e8d339b
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -925,7 +947,7 @@ entries:
|
|||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-25T00-41-18Z
|
appVersion: RELEASE.2021-08-25T00-41-18Z
|
||||||
created: "2022-03-17T11:30:33.707195901-07:00"
|
created: "2022-03-23T21:06:44.736406913-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: fcd944e837ee481307de6aa3d387ea18c234f995a84c15abb211aab4a4054afc
|
digest: fcd944e837ee481307de6aa3d387ea18c234f995a84c15abb211aab4a4054afc
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -945,7 +967,7 @@ entries:
|
|||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-25T00-41-18Z
|
appVersion: RELEASE.2021-08-25T00-41-18Z
|
||||||
created: "2022-03-17T11:30:33.706248526-07:00"
|
created: "2022-03-23T21:06:44.735376678-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 7b6c033d43a856479eb493ab8ca05b230f77c3e42e209e8f298fac6af1a9796f
|
digest: 7b6c033d43a856479eb493ab8ca05b230f77c3e42e209e8f298fac6af1a9796f
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -965,7 +987,7 @@ entries:
|
|||||||
version: 1.0.5
|
version: 1.0.5
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-25T00-41-18Z
|
appVersion: RELEASE.2021-08-25T00-41-18Z
|
||||||
created: "2022-03-17T11:30:33.70486202-07:00"
|
created: "2022-03-23T21:06:44.734196178-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: abd221245ace16c8e0c6c851cf262d1474a5219dcbf25c4b2e7b77142f9c59ed
|
digest: abd221245ace16c8e0c6c851cf262d1474a5219dcbf25c4b2e7b77142f9c59ed
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -985,7 +1007,7 @@ entries:
|
|||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-20T18-32-01Z
|
appVersion: RELEASE.2021-08-20T18-32-01Z
|
||||||
created: "2022-03-17T11:30:33.703923474-07:00"
|
created: "2022-03-23T21:06:44.732657511-07:00"
|
||||||
description: Multi-Cloud Object Storage
|
description: Multi-Cloud Object Storage
|
||||||
digest: 922a333f5413d1042f7aa81929f43767f6ffca9b260c46713f04ce1dda86d57d
|
digest: 922a333f5413d1042f7aa81929f43767f6ffca9b260c46713f04ce1dda86d57d
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -1005,7 +1027,7 @@ entries:
|
|||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-20T18-32-01Z
|
appVersion: RELEASE.2021-08-20T18-32-01Z
|
||||||
created: "2022-03-17T11:30:33.702996385-07:00"
|
created: "2022-03-23T21:06:44.731547254-07:00"
|
||||||
description: High Performance, Kubernetes Native Object Storage
|
description: High Performance, Kubernetes Native Object Storage
|
||||||
digest: 10e22773506bbfb1c66442937956534cf4057b94f06a977db78b8cd223588388
|
digest: 10e22773506bbfb1c66442937956534cf4057b94f06a977db78b8cd223588388
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -1025,7 +1047,7 @@ entries:
|
|||||||
version: 1.0.2
|
version: 1.0.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-20T18-32-01Z
|
appVersion: RELEASE.2021-08-20T18-32-01Z
|
||||||
created: "2022-03-17T11:30:33.702080599-07:00"
|
created: "2022-03-23T21:06:44.730531176-07:00"
|
||||||
description: High Performance, Kubernetes Native Object Storage
|
description: High Performance, Kubernetes Native Object Storage
|
||||||
digest: ef86ab6df23d6942705da9ef70991b649638c51bc310587d37a425268ba4a06c
|
digest: ef86ab6df23d6942705da9ef70991b649638c51bc310587d37a425268ba4a06c
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -1045,7 +1067,7 @@ entries:
|
|||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: RELEASE.2021-08-17T20-53-08Z
|
appVersion: RELEASE.2021-08-17T20-53-08Z
|
||||||
created: "2022-03-17T11:30:33.70120379-07:00"
|
created: "2022-03-23T21:06:44.729491755-07:00"
|
||||||
description: High Performance, Kubernetes Native Object Storage
|
description: High Performance, Kubernetes Native Object Storage
|
||||||
digest: 1add7608692cbf39aaf9b1252530e566f7b2f306a14e390b0f49b97a20f2b188
|
digest: 1add7608692cbf39aaf9b1252530e566f7b2f306a14e390b0f49b97a20f2b188
|
||||||
home: https://min.io
|
home: https://min.io
|
||||||
@@ -1063,4 +1085,4 @@ entries:
|
|||||||
urls:
|
urls:
|
||||||
- https://charts.min.io/helm-releases/minio-1.0.0.tgz
|
- https://charts.min.io/helm-releases/minio-1.0.0.tgz
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
generated: "2022-03-17T11:30:33.700070925-07:00"
|
generated: "2022-03-23T21:06:44.728148967-07:00"
|
||||||
|
|||||||
@@ -162,22 +162,6 @@ func (sCfg *Config) UnmarshalJSON(data []byte) error {
|
|||||||
return json.Unmarshal(data, &aux)
|
return json.Unmarshal(data, &aux)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListQuorum interprets list quorum values and returns appropriate
|
|
||||||
// acceptable quorum expected for list operations
|
|
||||||
func (sCfg Config) GetListQuorum() int {
|
|
||||||
switch sCfg.ListQuorum {
|
|
||||||
case "reduced":
|
|
||||||
return 2
|
|
||||||
case "disk":
|
|
||||||
// smallest possible value, generally meant for testing.
|
|
||||||
return 1
|
|
||||||
case "strict":
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
// Defaults to 3 drives per set, defaults to "optimal" value
|
|
||||||
return 3
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookupConfig - lookup api config and override with valid environment settings if any.
|
// LookupConfig - lookup api config and override with valid environment settings if any.
|
||||||
func LookupConfig(kvs config.KVS) (cfg Config, err error) {
|
func LookupConfig(kvs config.KVS) (cfg Config, err error) {
|
||||||
// remove this since we have removed this already.
|
// remove this since we have removed this already.
|
||||||
|
|||||||
@@ -84,6 +84,63 @@ func (s3 sses3) UnsealObjectKey(KMS kms.KMS, metadata map[string]string, bucket,
|
|||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnsealObjectsKeys extracts and decrypts all sealed object keys
|
||||||
|
// from the metadata using the KMS and returns the decrypted object
|
||||||
|
// keys.
|
||||||
|
//
|
||||||
|
// The metadata, buckets and objects slices must have the same length.
|
||||||
|
func (s3 sses3) UnsealObjectKeys(KMS kms.KMS, metadata []map[string]string, buckets, objects []string) ([]ObjectKey, error) {
|
||||||
|
if len(metadata) != len(buckets) || len(metadata) != len(objects) {
|
||||||
|
return nil, Errorf("invalid metadata/object count: %d != %d != %d", len(metadata), len(buckets), len(objects))
|
||||||
|
}
|
||||||
|
|
||||||
|
keyIDs := make([]string, 0, len(metadata))
|
||||||
|
kmsKeys := make([][]byte, 0, len(metadata))
|
||||||
|
sealedKeys := make([]SealedKey, 0, len(metadata))
|
||||||
|
|
||||||
|
sameKeyID := true
|
||||||
|
for i := range metadata {
|
||||||
|
keyID, kmsKey, sealedKey, err := s3.ParseMetadata(metadata[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keyIDs = append(keyIDs, keyID)
|
||||||
|
kmsKeys = append(kmsKeys, kmsKey)
|
||||||
|
sealedKeys = append(sealedKeys, sealedKey)
|
||||||
|
|
||||||
|
if i > 0 && keyID != keyIDs[i-1] {
|
||||||
|
sameKeyID = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sameKeyID {
|
||||||
|
contexts := make([]kms.Context, 0, len(keyIDs))
|
||||||
|
for i := range buckets {
|
||||||
|
contexts = append(contexts, kms.Context{buckets[i]: path.Join(buckets[i], objects[i])})
|
||||||
|
}
|
||||||
|
unsealKeys, err := KMS.DecryptAll(keyIDs[0], kmsKeys, contexts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keys := make([]ObjectKey, len(unsealKeys))
|
||||||
|
for i := range keys {
|
||||||
|
if err := keys[i].Unseal(unsealKeys[i], sealedKeys[i], s3.String(), buckets[i], objects[i]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := make([]ObjectKey, 0, len(keyIDs))
|
||||||
|
for i := range keyIDs {
|
||||||
|
key, err := s3.UnsealObjectKey(KMS, metadata[i], buckets[i], objects[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateMetadata encodes the sealed object key into the metadata and returns
|
// CreateMetadata encodes the sealed object key into the metadata and returns
|
||||||
// the modified metadata. If the keyID and the kmsKey is not empty it encodes
|
// the modified metadata. If the keyID and the kmsKey is not empty it encodes
|
||||||
// both into the metadata as well. It allocates a new metadata map if metadata
|
// both into the metadata as well. It allocates a new metadata map if metadata
|
||||||
|
|||||||
+17
-2
@@ -143,7 +143,22 @@ func (e ETag) String() string {
|
|||||||
|
|
||||||
// IsEncrypted reports whether the ETag is encrypted.
|
// IsEncrypted reports whether the ETag is encrypted.
|
||||||
func (e ETag) IsEncrypted() bool {
|
func (e ETag) IsEncrypted() bool {
|
||||||
return len(e) > 16 && !bytes.ContainsRune(e, '-')
|
// An encrypted ETag must be at least 32 bytes long.
|
||||||
|
// It contains the encrypted ETag value + an authentication
|
||||||
|
// code generated by the AEAD cipher.
|
||||||
|
//
|
||||||
|
// Here is an incorrect implementation of IsEncrypted:
|
||||||
|
//
|
||||||
|
// return len(e) > 16 && !bytes.ContainsRune(e, '-')
|
||||||
|
//
|
||||||
|
// An encrypted ETag may contain some random bytes - e.g.
|
||||||
|
// and nonce value. This nonce value may contain a '-'
|
||||||
|
// just by its nature of being randomly generated.
|
||||||
|
// The above implementation would incorrectly consider
|
||||||
|
// such an ETag (with a nonce value containing a '-')
|
||||||
|
// as non-encrypted.
|
||||||
|
|
||||||
|
return len(e) >= 32 // We consider all ETags longer than 32 bytes as encrypted
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsMultipart reports whether the ETag belongs to an
|
// IsMultipart reports whether the ETag belongs to an
|
||||||
@@ -151,7 +166,7 @@ func (e ETag) IsEncrypted() bool {
|
|||||||
// API.
|
// API.
|
||||||
// An S3 multipart ETag has a -<part-number> suffix.
|
// An S3 multipart ETag has a -<part-number> suffix.
|
||||||
func (e ETag) IsMultipart() bool {
|
func (e ETag) IsMultipart() bool {
|
||||||
return len(e) > 16 && bytes.ContainsRune(e, '-')
|
return len(e) > 16 && !e.IsEncrypted() && bytes.ContainsRune(e, '-')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parts returns the number of object parts that are
|
// Parts returns the number of object parts that are
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ var stringTests = []struct {
|
|||||||
ETag: ETag{144, 64, 44, 120, 210, 220, 205, 222, 225, 233, 232, 98, 34, 206, 44, 99, 97, 103, 95, 53, 41, 210, 96, 0, 174, 46, 144, 15, 242, 22, 179, 203, 89, 225, 48, 224, 146, 216, 162, 152, 30, 119, 111, 77, 11, 214, 9, 65},
|
ETag: ETag{144, 64, 44, 120, 210, 220, 205, 222, 225, 233, 232, 98, 34, 206, 44, 99, 97, 103, 95, 53, 41, 210, 96, 0, 174, 46, 144, 15, 242, 22, 179, 203, 89, 225, 48, 224, 146, 216, 162, 152, 30, 119, 111, 77, 11, 214, 9, 65},
|
||||||
String: "90402c78d2dccddee1e9e86222ce2c6361675f3529d26000ae2e900ff216b3cb59e130e092d8a2981e776f4d0bd60941",
|
String: "90402c78d2dccddee1e9e86222ce2c6361675f3529d26000ae2e900ff216b3cb59e130e092d8a2981e776f4d0bd60941",
|
||||||
},
|
},
|
||||||
|
{ // 5
|
||||||
|
ETag: ETag{32, 0, 15, 0, 219, 45, 144, 167, 180, 7, 130, 212, 207, 242, 180, 26, 119, 153, 252, 30, 126, 173, 37, 151, 45, 182, 81, 80, 17, 141, 251, 226, 186, 118, 163, 192, 2, 218, 40, 248, 92, 132, 12, 210, 0, 26, 40, 169},
|
||||||
|
String: "20000f00db2d90a7b40782d4cff2b41a7799fc1e7ead25972db65150118dfbe2ba76a3c002da28f85c840cd2001a28a9",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestString(t *testing.T) {
|
func TestString(t *testing.T) {
|
||||||
@@ -185,6 +189,30 @@ func TestMultipart(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isEncryptedTests = []struct {
|
||||||
|
ETag string
|
||||||
|
IsEncrypted bool
|
||||||
|
}{
|
||||||
|
{ETag: "20000f00db2d90a7b40782d4cff2b41a7799fc1e7ead25972db65150118dfbe2ba76a3c002da28f85c840cd2001a28a9", IsEncrypted: true}, // 0
|
||||||
|
|
||||||
|
{ETag: "3b83ef96387f14655fc854ddc3c6bd57"}, // 1
|
||||||
|
{ETag: "7b976cc68452e003eec7cb0eb631a19a-1"}, // 2
|
||||||
|
{ETag: "a7d414b9133d6483d9a1c4e04e856e3b-2"}, // 3
|
||||||
|
{ETag: "7b976cc68452e003eec7cb0eb631a19a-10000"}, // 4
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsEncrypted(t *testing.T) {
|
||||||
|
for i, test := range isEncryptedTests {
|
||||||
|
tag, err := Parse(test.ETag)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test %d: failed to parse ETag: %v", i, err)
|
||||||
|
}
|
||||||
|
if isEncrypted := tag.IsEncrypted(); isEncrypted != test.IsEncrypted {
|
||||||
|
t.Fatalf("Test %d: got '%v' - want '%v'", i, isEncrypted, test.IsEncrypted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var fromContentMD5Tests = []struct {
|
var fromContentMD5Tests = []struct {
|
||||||
Header http.Header
|
Header http.Header
|
||||||
ETag ETag
|
ETag ETag
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//go:build (linux && arm) || (linux && ppc64) || (linux && ppc64le) || (linux && s390x)
|
//go:build (linux && arm) || (linux && ppc64) || (linux && ppc64le) || (linux && s390x)|| (linux && riscv64)
|
||||||
// +build linux,arm linux,ppc64 linux,ppc64le linux,s390x
|
// +build linux,arm linux,ppc64 linux,ppc64le linux,s390x linux,riscv64
|
||||||
|
|
||||||
package kernel
|
package kernel
|
||||||
|
|
||||||
|
|||||||
+53
-2
@@ -22,6 +22,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/minio/kes"
|
"github.com/minio/kes"
|
||||||
@@ -69,15 +70,30 @@ func NewWithConfig(config Config) (KMS, error) {
|
|||||||
ClientSessionCache: tls.NewLRUClientSessionCache(tlsClientSessionCacheSize),
|
ClientSessionCache: tls.NewLRUClientSessionCache(tlsClientSessionCacheSize),
|
||||||
})
|
})
|
||||||
client.Endpoints = endpoints
|
client.Endpoints = endpoints
|
||||||
|
|
||||||
|
var bulkAvailable bool
|
||||||
|
_, policy, err := client.DescribeSelf(context.Background())
|
||||||
|
if err == nil {
|
||||||
|
const BulkAPI = "/v1/key/bulk/decrypt/"
|
||||||
|
for _, allow := range policy.Allow {
|
||||||
|
if strings.HasPrefix(allow, BulkAPI) {
|
||||||
|
bulkAvailable = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return &kesClient{
|
return &kesClient{
|
||||||
client: client,
|
client: client,
|
||||||
defaultKeyID: config.DefaultKeyID,
|
defaultKeyID: config.DefaultKeyID,
|
||||||
|
bulkAvailable: bulkAvailable,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type kesClient struct {
|
type kesClient struct {
|
||||||
defaultKeyID string
|
defaultKeyID string
|
||||||
client *kes.Client
|
client *kes.Client
|
||||||
|
|
||||||
|
bulkAvailable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ KMS = (*kesClient)(nil) // compiler check
|
var _ KMS = (*kesClient)(nil) // compiler check
|
||||||
@@ -145,3 +161,38 @@ func (c *kesClient) DecryptKey(keyID string, ciphertext []byte, ctx Context) ([]
|
|||||||
}
|
}
|
||||||
return c.client.Decrypt(context.Background(), keyID, ciphertext, ctxBytes)
|
return c.client.Decrypt(context.Background(), keyID, ciphertext, ctxBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *kesClient) DecryptAll(keyID string, ciphertexts [][]byte, contexts []Context) ([][]byte, error) {
|
||||||
|
if c.bulkAvailable {
|
||||||
|
CCPs := make([]kes.CCP, 0, len(ciphertexts))
|
||||||
|
for i := range ciphertexts {
|
||||||
|
bCtx, err := contexts[i].MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
CCPs = append(CCPs, kes.CCP{
|
||||||
|
Ciphertext: ciphertexts[i],
|
||||||
|
Context: bCtx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
PCPs, err := c.client.DecryptAll(context.Background(), keyID, CCPs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
plaintexts := make([][]byte, 0, len(PCPs))
|
||||||
|
for _, p := range PCPs {
|
||||||
|
plaintexts = append(plaintexts, p.Plaintext)
|
||||||
|
}
|
||||||
|
return plaintexts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintexts := make([][]byte, 0, len(ciphertexts))
|
||||||
|
for i := range ciphertexts {
|
||||||
|
plaintext, err := c.DecryptKey(keyID, ciphertexts[i], contexts[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
plaintexts = append(plaintexts, plaintext)
|
||||||
|
}
|
||||||
|
return plaintexts, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ package kms
|
|||||||
import (
|
import (
|
||||||
"encoding"
|
"encoding"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"github.com/minio/pkg/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
// KMS is the generic interface that abstracts over
|
// KMS is the generic interface that abstracts over
|
||||||
@@ -51,6 +53,23 @@ type KMS interface {
|
|||||||
// by the key ID. The context must match the context value
|
// by the key ID. The context must match the context value
|
||||||
// used to generate the ciphertext.
|
// used to generate the ciphertext.
|
||||||
DecryptKey(keyID string, ciphertext []byte, context Context) ([]byte, error)
|
DecryptKey(keyID string, ciphertext []byte, context Context) ([]byte, error)
|
||||||
|
|
||||||
|
// DecryptAll decrypts all ciphertexts with the key referenced
|
||||||
|
// by the key ID. The contexts must match the context value
|
||||||
|
// used to generate the ciphertexts.
|
||||||
|
DecryptAll(keyID string, ciphertext [][]byte, context []Context) ([][]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchSize returns the size of the batches that should be used during
|
||||||
|
// KES bulk decryption API calls.
|
||||||
|
func BatchSize() int {
|
||||||
|
const DefaultBatchSize = 500
|
||||||
|
v := env.Get("MINIO_KMS_KES_BULK_API_BATCH_SIZE", strconv.Itoa(DefaultBatchSize))
|
||||||
|
n, err := strconv.Atoi(v)
|
||||||
|
if err != nil {
|
||||||
|
return DefaultBatchSize
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status describes the current state of a KMS.
|
// Status describes the current state of a KMS.
|
||||||
|
|||||||
@@ -224,6 +224,18 @@ func (kms secretKey) DecryptKey(keyID string, ciphertext []byte, context Context
|
|||||||
return plaintext, nil
|
return plaintext, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (kms secretKey) DecryptAll(keyID string, ciphertexts [][]byte, contexts []Context) ([][]byte, error) {
|
||||||
|
plaintexts := make([][]byte, 0, len(ciphertexts))
|
||||||
|
for i := range ciphertexts {
|
||||||
|
plaintext, err := kms.DecryptKey(keyID, ciphertexts[i], contexts[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
plaintexts = append(plaintexts, plaintext)
|
||||||
|
}
|
||||||
|
return plaintexts, nil
|
||||||
|
}
|
||||||
|
|
||||||
type encryptedKey struct {
|
type encryptedKey struct {
|
||||||
Algorithm string `json:"aead"`
|
Algorithm string `json:"aead"`
|
||||||
IV []byte `json:"iv"`
|
IV []byte `json:"iv"`
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
package json
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -90,45 +89,31 @@ func NewReader(readCloser io.ReadCloser, args *ReaderArgs) *Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncReadCloser will wrap a readcloser and make it safe to call Close
|
// syncReadCloser will wrap a readcloser and make it safe to call Close while
|
||||||
// while reads are running.
|
// reads are running.
|
||||||
// All read errors are also postponed until Close is called and
|
|
||||||
// io.EOF is returned instead.
|
|
||||||
type syncReadCloser struct {
|
type syncReadCloser struct {
|
||||||
rc io.ReadCloser
|
rc io.ReadCloser
|
||||||
errMu sync.Mutex
|
mu sync.Mutex
|
||||||
err error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pr *syncReadCloser) Read(p []byte) (n int, err error) {
|
func (pr *syncReadCloser) Read(p []byte) (n int, err error) {
|
||||||
// This ensures that Close will block until Read has completed.
|
// This ensures that Close will block until Read has completed.
|
||||||
// This allows another goroutine to close the reader.
|
// This allows another goroutine to close the reader.
|
||||||
pr.errMu.Lock()
|
pr.mu.Lock()
|
||||||
defer pr.errMu.Unlock()
|
defer pr.mu.Unlock()
|
||||||
if pr.err != nil {
|
if pr.rc == nil {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
n, pr.err = pr.rc.Read(p)
|
return pr.rc.Read(p)
|
||||||
if pr.err != nil {
|
|
||||||
// Translate any error into io.EOF, so we don't crash:
|
|
||||||
// https://github.com/bcicen/jstream/blob/master/scanner.go#L48
|
|
||||||
return n, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
return n, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var errClosed = errors.New("read after close")
|
|
||||||
|
|
||||||
func (pr *syncReadCloser) Close() error {
|
func (pr *syncReadCloser) Close() error {
|
||||||
pr.errMu.Lock()
|
pr.mu.Lock()
|
||||||
defer pr.errMu.Unlock()
|
defer pr.mu.Unlock()
|
||||||
if pr.err == errClosed {
|
if pr.rc != nil {
|
||||||
return nil
|
err := pr.rc.Close()
|
||||||
|
pr.rc = nil
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if pr.err != nil {
|
return nil
|
||||||
return pr.err
|
|
||||||
}
|
|
||||||
pr.err = errClosed
|
|
||||||
return pr.rc.Close()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,7 +290,6 @@ type S3Select struct {
|
|||||||
statement *sql.SelectStatement
|
statement *sql.SelectStatement
|
||||||
progressReader *progressReader
|
progressReader *progressReader
|
||||||
recordReader recordReader
|
recordReader recordReader
|
||||||
close func() error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var legacyXMLName = "SelectObjectContentRequest"
|
var legacyXMLName = "SelectObjectContentRequest"
|
||||||
@@ -383,7 +382,9 @@ func (s3Select *S3Select) Open(getReader func(offset, length int64) (io.ReadClos
|
|||||||
|
|
||||||
s3Select.recordReader, err = csv.NewReader(s3Select.progressReader, &s3Select.Input.CSVArgs)
|
s3Select.recordReader, err = csv.NewReader(s3Select.progressReader, &s3Select.Input.CSVArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rc.Close()
|
// Close all reader resources opened so far.
|
||||||
|
s3Select.progressReader.Close()
|
||||||
|
|
||||||
var stErr bzip2.StructuralError
|
var stErr bzip2.StructuralError
|
||||||
if errors.As(err, &stErr) {
|
if errors.As(err, &stErr) {
|
||||||
return errInvalidCompression(err, s3Select.Input.CompressionType)
|
return errInvalidCompression(err, s3Select.Input.CompressionType)
|
||||||
@@ -402,7 +403,6 @@ func (s3Select *S3Select) Open(getReader func(offset, length int64) (io.ReadClos
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s3Select.close = rc.Close
|
|
||||||
return nil
|
return nil
|
||||||
case jsonFormat:
|
case jsonFormat:
|
||||||
rc, err := getReader(offset, end)
|
rc, err := getReader(offset, end)
|
||||||
@@ -426,7 +426,6 @@ func (s3Select *S3Select) Open(getReader func(offset, length int64) (io.ReadClos
|
|||||||
s3Select.recordReader = json.NewReader(s3Select.progressReader, &s3Select.Input.JSONArgs)
|
s3Select.recordReader = json.NewReader(s3Select.progressReader, &s3Select.Input.JSONArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
s3Select.close = rc.Close
|
|
||||||
return nil
|
return nil
|
||||||
case parquetFormat:
|
case parquetFormat:
|
||||||
if !strings.EqualFold(os.Getenv("MINIO_API_SELECT_PARQUET"), "on") {
|
if !strings.EqualFold(os.Getenv("MINIO_API_SELECT_PARQUET"), "on") {
|
||||||
@@ -494,12 +493,6 @@ func (s3Select *S3Select) marshal(buf *bytes.Buffer, record sql.Record) error {
|
|||||||
|
|
||||||
// Evaluate - filters and sends records read from opened reader as per select statement to http response writer.
|
// Evaluate - filters and sends records read from opened reader as per select statement to http response writer.
|
||||||
func (s3Select *S3Select) Evaluate(w http.ResponseWriter) {
|
func (s3Select *S3Select) Evaluate(w http.ResponseWriter) {
|
||||||
defer func() {
|
|
||||||
if s3Select.close != nil {
|
|
||||||
s3Select.close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
getProgressFunc := s3Select.getProgress
|
getProgressFunc := s3Select.getProgress
|
||||||
if !s3Select.Progress.Enabled {
|
if !s3Select.Progress.Enabled {
|
||||||
getProgressFunc = nil
|
getProgressFunc = nil
|
||||||
|
|||||||
Reference in New Issue
Block a user