mirror of
https://github.com/pgsty/minio.git
synced 2026-08-06 07:41:16 +03:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 099e88516d | |||
| 82a6ad2c10 | |||
| c1a78224cf | |||
| 39f9350697 | |||
| e31081d79d | |||
| f02d282754 | |||
| a89e0bab7d | |||
| 3a90af0bcd | |||
| 53ceb0791f | |||
| 2cd98a0d21 | |||
| a0b10c05e5 |
@@ -0,0 +1,18 @@
|
||||
# @format
|
||||
|
||||
name: Issue Workflow
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add issue to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@v0.5.0
|
||||
with:
|
||||
project-url: https://github.com/orgs/miniohq/projects/2
|
||||
github-token: ${{ secrets.BOT_PAT }}
|
||||
@@ -9706,6 +9706,31 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/go-task/slim-sprig
|
||||
https://github.com/go-task/slim-sprig
|
||||
----------------------------------------------------------------
|
||||
Copyright (C) 2013-2020 Masterminds
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/gobwas/httphead
|
||||
https://github.com/gobwas/httphead
|
||||
----------------------------------------------------------------
|
||||
@@ -24822,6 +24847,58 @@ THE SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/onsi/ginkgo/v2
|
||||
https://github.com/onsi/ginkgo/v2
|
||||
----------------------------------------------------------------
|
||||
Copyright (c) 2013-2014 Onsi Fakhouri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/onsi/gomega
|
||||
https://github.com/onsi/gomega
|
||||
----------------------------------------------------------------
|
||||
Copyright (c) 2013-2014 Onsi Fakhouri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/philhofer/fwd
|
||||
https://github.com/philhofer/fwd
|
||||
----------------------------------------------------------------
|
||||
|
||||
+72
-4
@@ -36,6 +36,7 @@ import (
|
||||
"github.com/minio/pkg/v2/env"
|
||||
"github.com/minio/pkg/v2/wildcard"
|
||||
"github.com/minio/pkg/v2/workers"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// expire: # Expire objects that match a condition
|
||||
@@ -80,19 +81,41 @@ import (
|
||||
|
||||
// BatchJobExpirePurge type accepts non-negative versions to be retained
|
||||
type BatchJobExpirePurge struct {
|
||||
line, col int
|
||||
RetainVersions int `yaml:"retainVersions" json:"retainVersions"`
|
||||
}
|
||||
|
||||
var _ yaml.Unmarshaler = &BatchJobExpirePurge{}
|
||||
|
||||
// UnmarshalYAML - BatchJobExpirePurge extends unmarshal to extract line, col
|
||||
func (p *BatchJobExpirePurge) UnmarshalYAML(val *yaml.Node) error {
|
||||
type purge BatchJobExpirePurge
|
||||
var tmp purge
|
||||
err := val.Decode(&tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*p = BatchJobExpirePurge(tmp)
|
||||
p.line, p.col = val.Line, val.Column
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns nil if value is valid, ie > 0.
|
||||
func (p BatchJobExpirePurge) Validate() error {
|
||||
if p.RetainVersions < 0 {
|
||||
return errors.New("retainVersions must be >= 0")
|
||||
return BatchJobYamlErr{
|
||||
line: p.line,
|
||||
col: p.col,
|
||||
msg: "retainVersions must be >= 0",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchJobExpireFilter holds all the filters currently supported for batch replication
|
||||
type BatchJobExpireFilter struct {
|
||||
line, col int
|
||||
OlderThan time.Duration `yaml:"olderThan,omitempty" json:"olderThan"`
|
||||
CreatedBefore *time.Time `yaml:"createdBefore,omitempty" json:"createdBefore"`
|
||||
Tags []BatchJobKV `yaml:"tags,omitempty" json:"tags"`
|
||||
@@ -103,6 +126,22 @@ type BatchJobExpireFilter struct {
|
||||
Purge BatchJobExpirePurge `yaml:"purge" json:"purge"`
|
||||
}
|
||||
|
||||
var _ yaml.Unmarshaler = &BatchJobExpireFilter{}
|
||||
|
||||
// UnmarshalYAML - BatchJobExpireFilter extends unmarshal to extract line, col
|
||||
// information
|
||||
func (ef *BatchJobExpireFilter) UnmarshalYAML(value *yaml.Node) error {
|
||||
type expFilter BatchJobExpireFilter
|
||||
var tmp expFilter
|
||||
err := value.Decode(&tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*ef = BatchJobExpireFilter(tmp)
|
||||
ef.line, ef.col = value.Line, value.Column
|
||||
return err
|
||||
}
|
||||
|
||||
// Matches returns true if obj matches the filter conditions specified in ef.
|
||||
func (ef BatchJobExpireFilter) Matches(obj ObjectInfo, now time.Time) bool {
|
||||
switch ef.Type {
|
||||
@@ -194,10 +233,18 @@ func (ef BatchJobExpireFilter) Validate() error {
|
||||
case BatchJobExpireObject:
|
||||
case BatchJobExpireDeleted:
|
||||
if len(ef.Tags) > 0 || len(ef.Metadata) > 0 {
|
||||
return errors.New("invalid batch-expire rule filter")
|
||||
return BatchJobYamlErr{
|
||||
line: ef.line,
|
||||
col: ef.col,
|
||||
msg: "delete type filter can't have tags or metadata",
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("invalid batch-expire type")
|
||||
return BatchJobYamlErr{
|
||||
line: ef.line,
|
||||
col: ef.col,
|
||||
msg: "invalid batch-expire type",
|
||||
}
|
||||
}
|
||||
|
||||
for _, tag := range ef.Tags {
|
||||
@@ -218,7 +265,11 @@ func (ef BatchJobExpireFilter) Validate() error {
|
||||
return err
|
||||
}
|
||||
if ef.CreatedBefore != nil && !ef.CreatedBefore.Before(time.Now()) {
|
||||
return errors.New("CreatedBefore is in the future")
|
||||
return BatchJobYamlErr{
|
||||
line: ef.line,
|
||||
col: ef.col,
|
||||
msg: "CreatedBefore is in the future",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -226,6 +277,7 @@ func (ef BatchJobExpireFilter) Validate() error {
|
||||
// BatchJobExpire represents configuration parameters for a batch expiration
|
||||
// job typically supplied in yaml form
|
||||
type BatchJobExpire struct {
|
||||
line, col int
|
||||
APIVersion string `yaml:"apiVersion" json:"apiVersion"`
|
||||
Bucket string `yaml:"bucket" json:"bucket"`
|
||||
Prefix string `yaml:"prefix" json:"prefix"`
|
||||
@@ -234,6 +286,22 @@ type BatchJobExpire struct {
|
||||
Rules []BatchJobExpireFilter `yaml:"rules" json:"rules"`
|
||||
}
|
||||
|
||||
var _ yaml.Unmarshaler = &BatchJobExpire{}
|
||||
|
||||
// UnmarshalYAML - BatchJobExpire extends default unmarshal to extract line, col information.
|
||||
func (r *BatchJobExpire) UnmarshalYAML(val *yaml.Node) error {
|
||||
type expireJob BatchJobExpire
|
||||
var tmp expireJob
|
||||
err := val.Decode(&tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*r = BatchJobExpire(tmp)
|
||||
r.line, r.col = val.Line, val.Column
|
||||
return nil
|
||||
}
|
||||
|
||||
// Notify notifies notification endpoint if configured regarding job failure or success.
|
||||
func (r BatchJobExpire) Notify(ctx context.Context, body io.Reader) error {
|
||||
if r.NotificationCfg.Endpoint == "" {
|
||||
|
||||
@@ -52,7 +52,7 @@ import (
|
||||
"github.com/minio/pkg/v2/env"
|
||||
"github.com/minio/pkg/v2/policy"
|
||||
"github.com/minio/pkg/v2/workers"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var globalBatchConfig batch.Config
|
||||
@@ -1564,7 +1564,7 @@ func (a adminAPIHandlers) StartBatchJob(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
job := &BatchJobRequest{}
|
||||
if err = yaml.UnmarshalStrict(buf, job); err != nil {
|
||||
if err = yaml.Unmarshal(buf, job); err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAPIError(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
+139
-15
@@ -18,26 +18,66 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/minio/pkg/v2/wildcard"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
//go:generate msgp -file $GOFILE
|
||||
//msgp:ignore BatchJobYamlErr
|
||||
|
||||
// BatchJobYamlErr can be used to return yaml validation errors with line,
|
||||
// column information guiding user to fix syntax errors
|
||||
type BatchJobYamlErr struct {
|
||||
line, col int
|
||||
msg string
|
||||
}
|
||||
|
||||
// message returns the error message excluding line, col information.
|
||||
// Intended to be used in unit tests.
|
||||
func (b BatchJobYamlErr) message() string {
|
||||
return b.msg
|
||||
}
|
||||
|
||||
// Error implements Error interface
|
||||
func (b BatchJobYamlErr) Error() string {
|
||||
return fmt.Sprintf("%s\n Hint: error near line: %d, col: %d", b.msg, b.line, b.col)
|
||||
}
|
||||
|
||||
// BatchJobKV is a key-value data type which supports wildcard matching
|
||||
type BatchJobKV struct {
|
||||
Key string `yaml:"key" json:"key"`
|
||||
Value string `yaml:"value" json:"value"`
|
||||
line, col int
|
||||
Key string `yaml:"key" json:"key"`
|
||||
Value string `yaml:"value" json:"value"`
|
||||
}
|
||||
|
||||
var _ yaml.Unmarshaler = &BatchJobKV{}
|
||||
|
||||
// UnmarshalYAML - BatchJobKV extends default unmarshal to extract line, col information.
|
||||
func (kv *BatchJobKV) UnmarshalYAML(val *yaml.Node) error {
|
||||
type jobKV BatchJobKV
|
||||
var tmp jobKV
|
||||
err := val.Decode(&tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*kv = BatchJobKV(tmp)
|
||||
kv.line, kv.col = val.Line, val.Column
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if key is empty
|
||||
func (kv BatchJobKV) Validate() error {
|
||||
if kv.Key == "" {
|
||||
return errInvalidArgument
|
||||
return BatchJobYamlErr{
|
||||
line: kv.line,
|
||||
col: kv.col,
|
||||
msg: "key can't be empty",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -61,24 +101,66 @@ func (kv BatchJobKV) Match(ikv BatchJobKV) bool {
|
||||
// BatchJobNotification stores notification endpoint and token information.
|
||||
// Used by batch jobs to notify of their status.
|
||||
type BatchJobNotification struct {
|
||||
Endpoint string `yaml:"endpoint" json:"endpoint"`
|
||||
Token string `yaml:"token" json:"token"`
|
||||
line, col int
|
||||
Endpoint string `yaml:"endpoint" json:"endpoint"`
|
||||
Token string `yaml:"token" json:"token"`
|
||||
}
|
||||
|
||||
var _ yaml.Unmarshaler = &BatchJobNotification{}
|
||||
|
||||
// UnmarshalYAML - BatchJobNotification extends unmarshal to extract line, column information
|
||||
func (b *BatchJobNotification) UnmarshalYAML(val *yaml.Node) error {
|
||||
type notification BatchJobNotification
|
||||
var tmp notification
|
||||
err := val.Decode(&tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*b = BatchJobNotification(tmp)
|
||||
b.line, b.col = val.Line, val.Column
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchJobRetry stores retry configuration used in the event of failures.
|
||||
type BatchJobRetry struct {
|
||||
Attempts int `yaml:"attempts" json:"attempts"` // number of retry attempts
|
||||
Delay time.Duration `yaml:"delay" json:"delay"` // delay between each retries
|
||||
line, col int
|
||||
Attempts int `yaml:"attempts" json:"attempts"` // number of retry attempts
|
||||
Delay time.Duration `yaml:"delay" json:"delay"` // delay between each retries
|
||||
}
|
||||
|
||||
var _ yaml.Unmarshaler = &BatchJobRetry{}
|
||||
|
||||
// UnmarshalYAML - BatchJobRetry extends unmarshal to extract line, column information
|
||||
func (r *BatchJobRetry) UnmarshalYAML(val *yaml.Node) error {
|
||||
type retry BatchJobRetry
|
||||
var tmp retry
|
||||
err := val.Decode(&tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*r = BatchJobRetry(tmp)
|
||||
r.line, r.col = val.Line, val.Column
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate validates input replicate retries.
|
||||
func (r BatchJobRetry) Validate() error {
|
||||
if r.Attempts < 0 {
|
||||
return errInvalidArgument
|
||||
return BatchJobYamlErr{
|
||||
line: r.line,
|
||||
col: r.col,
|
||||
msg: "Invalid arguments specified",
|
||||
}
|
||||
}
|
||||
|
||||
if r.Delay < 0 {
|
||||
return errInvalidArgument
|
||||
return BatchJobYamlErr{
|
||||
line: r.line,
|
||||
col: r.col,
|
||||
msg: "Invalid arguments specified",
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -96,6 +178,7 @@ func (r BatchJobRetry) Validate() error {
|
||||
|
||||
// BatchJobSnowball describes the snowball feature when replicating objects from a local source to a remote target
|
||||
type BatchJobSnowball struct {
|
||||
line, col int
|
||||
Disable *bool `yaml:"disable" json:"disable"`
|
||||
Batch *int `yaml:"batch" json:"batch"`
|
||||
InMemory *bool `yaml:"inmemory" json:"inmemory"`
|
||||
@@ -104,21 +187,60 @@ type BatchJobSnowball struct {
|
||||
SkipErrs *bool `yaml:"skipErrs" json:"skipErrs"`
|
||||
}
|
||||
|
||||
var _ yaml.Unmarshaler = &BatchJobSnowball{}
|
||||
|
||||
// UnmarshalYAML - BatchJobSnowball extends unmarshal to extract line, column information
|
||||
func (b *BatchJobSnowball) UnmarshalYAML(val *yaml.Node) error {
|
||||
type snowball BatchJobSnowball
|
||||
var tmp snowball
|
||||
err := val.Decode(&tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*b = BatchJobSnowball(tmp)
|
||||
b.line, b.col = val.Line, val.Column
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate the snowball parameters in the job description
|
||||
func (b BatchJobSnowball) Validate() error {
|
||||
if *b.Batch <= 0 {
|
||||
return errors.New("batch number should be non positive zero")
|
||||
return BatchJobYamlErr{
|
||||
line: b.line,
|
||||
col: b.col,
|
||||
msg: "batch number should be non positive zero",
|
||||
}
|
||||
}
|
||||
_, err := humanize.ParseBytes(*b.SmallerThan)
|
||||
return err
|
||||
return BatchJobYamlErr{
|
||||
line: b.line,
|
||||
col: b.col,
|
||||
msg: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
// BatchJobSizeFilter supports size based filters - LesserThan and GreaterThan
|
||||
type BatchJobSizeFilter struct {
|
||||
line, col int
|
||||
UpperBound BatchJobSize `yaml:"lessThan" json:"lessThan"`
|
||||
LowerBound BatchJobSize `yaml:"greaterThan" json:"greaterThan"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML - BatchJobSizeFilter extends unmarshal to extract line, column information
|
||||
func (sf *BatchJobSizeFilter) UnmarshalYAML(val *yaml.Node) error {
|
||||
type sizeFilter BatchJobSizeFilter
|
||||
var tmp sizeFilter
|
||||
err := val.Decode(&tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*sf = BatchJobSizeFilter(tmp)
|
||||
sf.line, sf.col = val.Line, val.Column
|
||||
return nil
|
||||
}
|
||||
|
||||
// InRange returns true in the following cases and false otherwise,
|
||||
// - sf.LowerBound < sz, when sf.LowerBound alone is specified
|
||||
// - sz < sf.UpperBound, when sf.UpperBound alone is specified
|
||||
@@ -134,12 +256,14 @@ func (sf BatchJobSizeFilter) InRange(sz int64) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var errInvalidBatchJobSizeFilter = errors.New("invalid batch-job size filter")
|
||||
|
||||
// Validate checks if sf is a valid batch-job size filter
|
||||
func (sf BatchJobSizeFilter) Validate() error {
|
||||
if sf.LowerBound > 0 && sf.UpperBound > 0 && sf.LowerBound >= sf.UpperBound {
|
||||
return errInvalidBatchJobSizeFilter
|
||||
return BatchJobYamlErr{
|
||||
line: sf.line,
|
||||
col: sf.col,
|
||||
msg: "invalid batch-job size filter",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -83,6 +83,10 @@ func TestBatchJobSizeInRange(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBatchJobSizeValidate(t *testing.T) {
|
||||
errInvalidBatchJobSizeFilter := BatchJobYamlErr{
|
||||
msg: "invalid batch-job size filter",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
sizeFilter BatchJobSizeFilter
|
||||
err error
|
||||
@@ -128,8 +132,16 @@ func TestBatchJobSizeValidate(t *testing.T) {
|
||||
}
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("test-%d", i+1), func(t *testing.T) {
|
||||
if err := test.sizeFilter.Validate(); err != test.err {
|
||||
t.Fatalf("Expected %v but got %v", test.err, err)
|
||||
err := test.sizeFilter.Validate()
|
||||
if err != nil {
|
||||
gotErr := err.(BatchJobYamlErr)
|
||||
testErr := test.err.(BatchJobYamlErr)
|
||||
if gotErr.message() != testErr.message() {
|
||||
t.Fatalf("Expected %v but got %v", test.err, err)
|
||||
}
|
||||
}
|
||||
if err == nil && test.err != nil {
|
||||
t.Fatalf("Expected %v but got nil", test.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1015,8 +1015,6 @@ func CreatePoolEndpoints(serverAddr string, poolsLayout ...poolDisksLayout) ([]E
|
||||
poolEndpoints[i] = endpoints
|
||||
}
|
||||
|
||||
// TODO: ensure that each pool has at least two nodes in a distributed setup
|
||||
|
||||
publicIPs := env.Get(config.EnvPublicIPs, "")
|
||||
if len(publicIPs) == 0 {
|
||||
updateDomainIPs(uniqueArgs)
|
||||
|
||||
+17
-154
@@ -128,159 +128,6 @@ func (er erasureObjects) listAndHeal(bucket, prefix string, scanMode madmin.Heal
|
||||
return nil
|
||||
}
|
||||
|
||||
// HealBucket heals a bucket if it doesn't exist on one of the disks, additionally
|
||||
// also heals the missing entries for bucket metadata files
|
||||
// `policy.json, notification.xml, listeners.json`.
|
||||
func (er erasureObjects) HealBucket(ctx context.Context, bucket string, opts madmin.HealOpts) (
|
||||
result madmin.HealResultItem, err error,
|
||||
) {
|
||||
storageDisks := er.getDisks()
|
||||
storageEndpoints := er.getEndpoints()
|
||||
|
||||
// Heal bucket.
|
||||
return er.healBucket(ctx, storageDisks, storageEndpoints, bucket, opts)
|
||||
}
|
||||
|
||||
// Heal bucket - create buckets on disks where it does not exist.
|
||||
func (er erasureObjects) healBucket(ctx context.Context, storageDisks []StorageAPI, storageEndpoints []Endpoint, bucket string, opts madmin.HealOpts) (res madmin.HealResultItem, err error) {
|
||||
// get write quorum for an object
|
||||
writeQuorum := len(storageDisks) - er.defaultParityCount
|
||||
if writeQuorum == er.defaultParityCount {
|
||||
writeQuorum++
|
||||
}
|
||||
|
||||
if globalTrace.NumSubscribers(madmin.TraceHealing) > 0 {
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
healTrace(healingMetricBucket, startTime, bucket, "", &opts, err, &res)
|
||||
}()
|
||||
}
|
||||
|
||||
// Initialize sync waitgroup.
|
||||
g := errgroup.WithNErrs(len(storageDisks))
|
||||
|
||||
// Disk states slices
|
||||
beforeState := make([]string, len(storageDisks))
|
||||
afterState := make([]string, len(storageDisks))
|
||||
|
||||
// Make a volume entry on all underlying storage disks.
|
||||
for index := range storageDisks {
|
||||
index := index
|
||||
g.Go(func() error {
|
||||
if storageDisks[index] == nil {
|
||||
beforeState[index] = madmin.DriveStateOffline
|
||||
afterState[index] = madmin.DriveStateOffline
|
||||
return errDiskNotFound
|
||||
}
|
||||
|
||||
beforeState[index] = madmin.DriveStateOk
|
||||
afterState[index] = madmin.DriveStateOk
|
||||
|
||||
if bucket == minioReservedBucket {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, serr := storageDisks[index].StatVol(ctx, bucket); serr != nil {
|
||||
if serr == errDiskNotFound {
|
||||
beforeState[index] = madmin.DriveStateOffline
|
||||
afterState[index] = madmin.DriveStateOffline
|
||||
return serr
|
||||
}
|
||||
if serr != errVolumeNotFound {
|
||||
beforeState[index] = madmin.DriveStateCorrupt
|
||||
afterState[index] = madmin.DriveStateCorrupt
|
||||
return serr
|
||||
}
|
||||
|
||||
beforeState[index] = madmin.DriveStateMissing
|
||||
afterState[index] = madmin.DriveStateMissing
|
||||
|
||||
// mutate only if not a dry-run
|
||||
if opts.DryRun {
|
||||
return nil
|
||||
}
|
||||
|
||||
return serr
|
||||
}
|
||||
return nil
|
||||
}, index)
|
||||
}
|
||||
|
||||
errs := g.Wait()
|
||||
|
||||
// Initialize heal result info
|
||||
res = madmin.HealResultItem{
|
||||
Type: madmin.HealItemBucket,
|
||||
Bucket: bucket,
|
||||
DiskCount: len(storageDisks),
|
||||
ParityBlocks: er.defaultParityCount,
|
||||
DataBlocks: len(storageDisks) - er.defaultParityCount,
|
||||
}
|
||||
|
||||
for i := range beforeState {
|
||||
res.Before.Drives = append(res.Before.Drives, madmin.HealDriveInfo{
|
||||
UUID: "",
|
||||
Endpoint: storageEndpoints[i].String(),
|
||||
State: beforeState[i],
|
||||
})
|
||||
}
|
||||
|
||||
reducedErr := reduceReadQuorumErrs(ctx, errs, bucketOpIgnoredErrs, res.DataBlocks)
|
||||
if errors.Is(reducedErr, errVolumeNotFound) && !opts.Recreate {
|
||||
for i := range beforeState {
|
||||
res.After.Drives = append(res.After.Drives, madmin.HealDriveInfo{
|
||||
UUID: "",
|
||||
Endpoint: storageEndpoints[i].String(),
|
||||
State: madmin.DriveStateOk,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Initialize sync waitgroup.
|
||||
g = errgroup.WithNErrs(len(storageDisks))
|
||||
|
||||
// Make a volume entry on all underlying storage disks.
|
||||
for index := range storageDisks {
|
||||
index := index
|
||||
g.Go(func() error {
|
||||
if beforeState[index] == madmin.DriveStateMissing {
|
||||
makeErr := storageDisks[index].MakeVol(ctx, bucket)
|
||||
if makeErr == nil {
|
||||
afterState[index] = madmin.DriveStateOk
|
||||
}
|
||||
return makeErr
|
||||
}
|
||||
return errs[index]
|
||||
}, index)
|
||||
}
|
||||
|
||||
errs = g.Wait()
|
||||
|
||||
reducedErr = reduceWriteQuorumErrs(ctx, errs, bucketOpIgnoredErrs, writeQuorum)
|
||||
if reducedErr != nil {
|
||||
// If we have exactly half the drives not available,
|
||||
// we should still allow HealBucket to not return error.
|
||||
// this is necessary for starting the server.
|
||||
readQuorum := res.DataBlocks
|
||||
switch reduceReadQuorumErrs(ctx, errs, nil, readQuorum) {
|
||||
case nil:
|
||||
case errDiskNotFound:
|
||||
default:
|
||||
return res, reducedErr
|
||||
}
|
||||
}
|
||||
|
||||
for i := range afterState {
|
||||
res.After.Drives = append(res.After.Drives, madmin.HealDriveInfo{
|
||||
UUID: "",
|
||||
Endpoint: storageEndpoints[i].String(),
|
||||
State: afterState[i],
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// listAllBuckets lists all buckets from all disks. It also
|
||||
// returns the occurrence of each buckets in all disks
|
||||
func listAllBuckets(ctx context.Context, storageDisks []StorageAPI, healBuckets map[string]VolInfo, readQuorum int) error {
|
||||
@@ -1019,6 +866,22 @@ func isAllNotFound(errs []error) bool {
|
||||
return len(errs) > 0
|
||||
}
|
||||
|
||||
// isAllBucketsNotFound will return true if all the errors are either errFileNotFound
|
||||
// or errFileCorrupt
|
||||
// A 0 length slice will always return false.
|
||||
func isAllBucketsNotFound(errs []error) bool {
|
||||
if len(errs) == 0 {
|
||||
return false
|
||||
}
|
||||
notFoundCount := 0
|
||||
for _, err := range errs {
|
||||
if err != nil && errors.Is(err, errVolumeNotFound) {
|
||||
notFoundCount++
|
||||
}
|
||||
}
|
||||
return len(errs) == notFoundCount
|
||||
}
|
||||
|
||||
// ObjectDir is considered dangling/corrupted if any only
|
||||
// if total disks - a combination of corrupted and missing
|
||||
// files is lesser than N/2+1 number of disks.
|
||||
@@ -1044,7 +907,7 @@ func isObjectDirDangling(errs []error) (ok bool) {
|
||||
return found < notFound && found > 0
|
||||
}
|
||||
|
||||
// Object is considered dangling/corrupted if any only
|
||||
// Object is considered dangling/corrupted if and only
|
||||
// if total disks - a combination of corrupted and missing
|
||||
// files is lesser than number of data blocks.
|
||||
func isObjectDangling(metaArr []FileInfo, errs []error, dataErrs []error) (validMeta FileInfo, ok bool) {
|
||||
|
||||
@@ -362,7 +362,7 @@ func TestHealing(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// This would create the bucket.
|
||||
_, err = er.HealBucket(ctx, bucket, madmin.HealOpts{
|
||||
_, err = obj.HealBucket(ctx, bucket, madmin.HealOpts{
|
||||
DryRun: false,
|
||||
Remove: false,
|
||||
})
|
||||
@@ -543,7 +543,7 @@ func TestHealingVersioned(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// This would create the bucket.
|
||||
_, err = er.HealBucket(ctx, bucket, madmin.HealOpts{
|
||||
_, err = obj.HealBucket(ctx, bucket, madmin.HealOpts{
|
||||
DryRun: false,
|
||||
Remove: false,
|
||||
})
|
||||
|
||||
@@ -1941,8 +1941,53 @@ func (z *erasureServerPools) HealBucket(ctx context.Context, bucket string, opts
|
||||
hopts.Recreate = false
|
||||
defer z.HealObject(ctx, minioMetaBucket, pathJoin(bucketMetaPrefix, bucket, bucketMetadataFile), "", hopts)
|
||||
|
||||
type DiskStat struct {
|
||||
VolInfos []VolInfo
|
||||
Errs []error
|
||||
}
|
||||
|
||||
for _, pool := range z.serverPools {
|
||||
result, err := pool.HealBucket(ctx, bucket, opts)
|
||||
// map of node wise disk stats
|
||||
diskStats := make(map[string]DiskStat)
|
||||
for _, set := range pool.sets {
|
||||
for _, disk := range set.getDisks() {
|
||||
if disk == OfflineDisk {
|
||||
continue
|
||||
}
|
||||
vi, err := disk.StatVol(ctx, bucket)
|
||||
hostName := disk.Hostname()
|
||||
if disk.IsLocal() {
|
||||
hostName = "local"
|
||||
}
|
||||
ds, ok := diskStats[hostName]
|
||||
if !ok {
|
||||
newds := DiskStat{
|
||||
VolInfos: []VolInfo{vi},
|
||||
Errs: []error{err},
|
||||
}
|
||||
diskStats[hostName] = newds
|
||||
} else {
|
||||
ds.VolInfos = append(ds.VolInfos, vi)
|
||||
ds.Errs = append(ds.Errs, err)
|
||||
diskStats[hostName] = ds
|
||||
}
|
||||
}
|
||||
}
|
||||
nodeCount := len(diskStats)
|
||||
bktNotFoundCount := 0
|
||||
for _, ds := range diskStats {
|
||||
if isAllBucketsNotFound(ds.Errs) {
|
||||
bktNotFoundCount++
|
||||
}
|
||||
}
|
||||
// if the bucket if not found on more than hslf the no of nodes, its dangling
|
||||
if bktNotFoundCount > nodeCount/2 {
|
||||
opts.Remove = true
|
||||
} else {
|
||||
opts.Recreate = true
|
||||
}
|
||||
|
||||
result, err := z.s3Peer.HealBucket(ctx, bucket, opts)
|
||||
if err != nil {
|
||||
if _, ok := err.(BucketNotFound); ok {
|
||||
continue
|
||||
|
||||
@@ -1186,28 +1186,6 @@ func (s *erasureSets) HealFormat(ctx context.Context, dryRun bool) (res madmin.H
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// HealBucket - heals inconsistent buckets and bucket metadata on all sets.
|
||||
func (s *erasureSets) HealBucket(ctx context.Context, bucket string, opts madmin.HealOpts) (result madmin.HealResultItem, err error) {
|
||||
// Initialize heal result info
|
||||
result = madmin.HealResultItem{
|
||||
Type: madmin.HealItemBucket,
|
||||
Bucket: bucket,
|
||||
DiskCount: s.setCount * s.setDriveCount,
|
||||
SetCount: s.setCount,
|
||||
}
|
||||
|
||||
for _, set := range s.sets {
|
||||
healResult, err := set.HealBucket(ctx, bucket, opts)
|
||||
if err != nil {
|
||||
return result, toObjectErr(err, bucket)
|
||||
}
|
||||
result.Before.Drives = append(result.Before.Drives, healResult.Before.Drives...)
|
||||
result.After.Drives = append(result.After.Drives, healResult.After.Drives...)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// HealObject - heals inconsistent object on a hashedSet based on object name.
|
||||
func (s *erasureSets) HealObject(ctx context.Context, bucket, object, versionID string, opts madmin.HealOpts) (madmin.HealResultItem, error) {
|
||||
return s.getHashedSet(object).HealObject(ctx, bucket, object, versionID, opts)
|
||||
|
||||
+7
-5
@@ -143,10 +143,13 @@ func (er *erasureObjects) healErasureSet(ctx context.Context, buckets []string,
|
||||
healBuckets := make([]string, len(buckets))
|
||||
copy(healBuckets, buckets)
|
||||
|
||||
// Heal all buckets first in this erasure set - this is useful
|
||||
// for new objects upload in different buckets to be successful
|
||||
objAPI := newObjectLayerFn()
|
||||
if objAPI == nil {
|
||||
return errServerNotInitialized
|
||||
}
|
||||
|
||||
for _, bucket := range healBuckets {
|
||||
_, err := er.HealBucket(ctx, bucket, madmin.HealOpts{ScanMode: scanMode})
|
||||
_, err := objAPI.HealBucket(ctx, bucket, madmin.HealOpts{ScanMode: scanMode})
|
||||
if err != nil {
|
||||
// Log bucket healing error if any, we shall retry again.
|
||||
logger.LogIf(ctx, err)
|
||||
@@ -195,10 +198,9 @@ func (er *erasureObjects) healErasureSet(ctx context.Context, buckets []string,
|
||||
}
|
||||
tracker.setObject("")
|
||||
tracker.setBucket(bucket)
|
||||
|
||||
// Heal current bucket again in case if it is failed
|
||||
// in the beginning of erasure set healing
|
||||
if _, err := er.HealBucket(ctx, bucket, madmin.HealOpts{
|
||||
if _, err := objAPI.HealBucket(ctx, bucket, madmin.HealOpts{
|
||||
ScanMode: scanMode,
|
||||
}); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
|
||||
+11
@@ -1358,9 +1358,15 @@ func (sys *IAMSys) updateGroupMembershipsForLDAP(ctx context.Context) {
|
||||
// DN to ldap username mapping for each LDAP user
|
||||
parentUserToLDAPUsernameMap := make(map[string]string)
|
||||
for _, cred := range allCreds {
|
||||
// Expired credentials don't need parent user updates.
|
||||
if cred.IsExpired() {
|
||||
continue
|
||||
}
|
||||
|
||||
if !sys.LDAPConfig.IsLDAPUserDN(cred.ParentUser) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if this is the first time we are
|
||||
// encountering this LDAP user.
|
||||
if _, ok := parentUserToCredsMap[cred.ParentUser]; !ok {
|
||||
@@ -1425,6 +1431,11 @@ func (sys *IAMSys) updateGroupMembershipsForLDAP(ctx context.Context) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Expired credentials don't need group membership updates.
|
||||
if cred.IsExpired() {
|
||||
continue
|
||||
}
|
||||
|
||||
cred.Groups = currGroups
|
||||
if err := sys.store.UpdateUserIdentity(ctx, cred); err != nil {
|
||||
// Log and continue error - perhaps it'll work the next time.
|
||||
|
||||
+154
-103
@@ -50,32 +50,32 @@ var (
|
||||
|
||||
func init() {
|
||||
clusterMetricsGroups := []*MetricsGroup{
|
||||
getNodeHealthMetrics(),
|
||||
getClusterStorageMetrics(),
|
||||
getClusterTierMetrics(),
|
||||
getClusterUsageMetrics(),
|
||||
getKMSMetrics(),
|
||||
getClusterHealthMetrics(),
|
||||
getIAMNodeMetrics(),
|
||||
getReplicationSiteMetrics(),
|
||||
getNodeHealthMetrics(MetricsGroupOpts{dependGlobalNotificationSys: true}),
|
||||
getClusterStorageMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true}),
|
||||
getClusterTierMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true}),
|
||||
getClusterUsageMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true}),
|
||||
getKMSMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true, dependGlobalKMS: true}),
|
||||
getClusterHealthMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true}),
|
||||
getIAMNodeMetrics(MetricsGroupOpts{dependGlobalAuthNPlugin: true, dependGlobalIAMSys: true}),
|
||||
getReplicationSiteMetrics(MetricsGroupOpts{dependGlobalSiteReplicationSys: true}),
|
||||
}
|
||||
|
||||
peerMetricsGroups = []*MetricsGroup{
|
||||
getGoMetrics(),
|
||||
getHTTPMetrics(false),
|
||||
getNotificationMetrics(),
|
||||
getLocalStorageMetrics(),
|
||||
getHTTPMetrics(MetricsGroupOpts{}),
|
||||
getNotificationMetrics(MetricsGroupOpts{dependGlobalLambdaTargetList: true}),
|
||||
getLocalStorageMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true}),
|
||||
getMinioProcMetrics(),
|
||||
getMinioVersionMetrics(),
|
||||
getNetworkMetrics(),
|
||||
getS3TTFBMetric(),
|
||||
getILMNodeMetrics(),
|
||||
getScannerNodeMetrics(),
|
||||
getIAMNodeMetrics(),
|
||||
getKMSNodeMetrics(),
|
||||
getMinioHealingMetrics(),
|
||||
getIAMNodeMetrics(MetricsGroupOpts{dependGlobalAuthNPlugin: true, dependGlobalIAMSys: true}),
|
||||
getKMSNodeMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true, dependGlobalKMS: true}),
|
||||
getMinioHealingMetrics(MetricsGroupOpts{dependGlobalBackgroundHealState: true}),
|
||||
getWebhookMetrics(),
|
||||
getReplicationClusterMetrics(),
|
||||
getReplicationClusterMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true, dependBucketTargetSys: true}),
|
||||
}
|
||||
|
||||
allMetricsGroups := func() (allMetrics []*MetricsGroup) {
|
||||
@@ -85,27 +85,27 @@ func init() {
|
||||
}()
|
||||
|
||||
nodeGroups := []*MetricsGroup{
|
||||
getNodeHealthMetrics(),
|
||||
getHTTPMetrics(false),
|
||||
getNodeHealthMetrics(MetricsGroupOpts{dependGlobalNotificationSys: true}),
|
||||
getHTTPMetrics(MetricsGroupOpts{}),
|
||||
getNetworkMetrics(),
|
||||
getMinioVersionMetrics(),
|
||||
getS3TTFBMetric(),
|
||||
getTierMetrics(),
|
||||
getNotificationMetrics(),
|
||||
getDistLockMetrics(),
|
||||
getIAMNodeMetrics(),
|
||||
getLocalStorageMetrics(),
|
||||
getNotificationMetrics(MetricsGroupOpts{dependGlobalLambdaTargetList: true}),
|
||||
getDistLockMetrics(MetricsGroupOpts{dependGlobalIsDistErasure: true, dependGlobalLockServer: true}),
|
||||
getIAMNodeMetrics(MetricsGroupOpts{dependGlobalAuthNPlugin: true, dependGlobalIAMSys: true}),
|
||||
getLocalStorageMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true}),
|
||||
}
|
||||
|
||||
bucketMetricsGroups := []*MetricsGroup{
|
||||
getBucketUsageMetrics(),
|
||||
getHTTPMetrics(true),
|
||||
getBucketUsageMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true}),
|
||||
getHTTPMetrics(MetricsGroupOpts{bucketOnly: true}),
|
||||
getBucketTTFBMetric(),
|
||||
getBatchJobsMetrics(),
|
||||
getBatchJobsMetrics(MetricsGroupOpts{dependGlobalObjectAPI: true}),
|
||||
}
|
||||
|
||||
bucketPeerMetricsGroups = []*MetricsGroup{
|
||||
getHTTPMetrics(true),
|
||||
getHTTPMetrics(MetricsGroupOpts{bucketOnly: true}),
|
||||
getBucketTTFBMetric(),
|
||||
}
|
||||
|
||||
@@ -315,8 +315,25 @@ type Metric struct {
|
||||
|
||||
// MetricsGroup are a group of metrics that are initialized together.
|
||||
type MetricsGroup struct {
|
||||
metricsCache timedValue
|
||||
cacheInterval time.Duration
|
||||
metricsCache timedValue
|
||||
cacheInterval time.Duration
|
||||
metricsGroupOpts MetricsGroupOpts
|
||||
}
|
||||
|
||||
// MetricsGroupOpts are a group of metrics opts to be used to initialize the metrics group.
|
||||
type MetricsGroupOpts struct {
|
||||
dependGlobalObjectAPI bool
|
||||
dependGlobalAuthNPlugin bool
|
||||
dependGlobalSiteReplicationSys bool
|
||||
dependGlobalNotificationSys bool
|
||||
dependGlobalKMS bool
|
||||
bucketOnly bool
|
||||
dependGlobalLambdaTargetList bool
|
||||
dependGlobalIAMSys bool
|
||||
dependGlobalLockServer bool
|
||||
dependGlobalIsDistErasure bool
|
||||
dependGlobalBackgroundHealState bool
|
||||
dependBucketTargetSys bool
|
||||
}
|
||||
|
||||
// RegisterRead register the metrics populator function to be used
|
||||
@@ -326,6 +343,63 @@ func (g *MetricsGroup) RegisterRead(read func(ctx context.Context) []Metric) {
|
||||
g.metricsCache.Relax = true
|
||||
g.metricsCache.TTL = g.cacheInterval
|
||||
g.metricsCache.Update = func() (interface{}, error) {
|
||||
if g.metricsGroupOpts.dependGlobalObjectAPI {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalAuthNPlugin {
|
||||
if globalAuthNPlugin == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalSiteReplicationSys {
|
||||
if !globalSiteReplicationSys.isEnabled() {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalNotificationSys {
|
||||
if globalNotificationSys == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalKMS {
|
||||
if GlobalKMS == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalLambdaTargetList {
|
||||
if globalLambdaTargetList == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalIAMSys {
|
||||
if globalIAMSys == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalLockServer {
|
||||
if globalLockServer == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalIsDistErasure {
|
||||
if !globalIsDistErasure {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependGlobalBackgroundHealState {
|
||||
if globalBackgroundHealState == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
if g.metricsGroupOpts.dependBucketTargetSys {
|
||||
if globalBucketTargetSys == nil {
|
||||
return []Metric{}, nil
|
||||
}
|
||||
}
|
||||
return read(GlobalContext), nil
|
||||
}
|
||||
})
|
||||
@@ -1889,9 +1963,10 @@ func getScannerNodeMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getIAMNodeMetrics() *MetricsGroup {
|
||||
func getIAMNodeMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
cacheInterval: 10 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(_ context.Context) (metrics []Metric) {
|
||||
lastSyncTime := atomic.LoadUint64(&globalIAMSys.LastRefreshTimeUnixNano)
|
||||
@@ -2010,9 +2085,10 @@ func getIAMNodeMetrics() *MetricsGroup {
|
||||
}
|
||||
|
||||
// replication metrics for each node - published to the cluster endpoint with nodename as label
|
||||
func getReplicationClusterMetrics() *MetricsGroup {
|
||||
func getReplicationClusterMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Minute,
|
||||
cacheInterval: 1 * time.Minute,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
const (
|
||||
Online = 1
|
||||
@@ -2197,9 +2273,10 @@ func getReplicationClusterMetrics() *MetricsGroup {
|
||||
}
|
||||
|
||||
// replication metrics for site replication
|
||||
func getReplicationSiteMetrics() *MetricsGroup {
|
||||
func getReplicationSiteMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Minute,
|
||||
cacheInterval: 1 * time.Minute,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(_ context.Context) []Metric {
|
||||
ml := []Metric{}
|
||||
@@ -2296,9 +2373,10 @@ func getMinioVersionMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getNodeHealthMetrics() *MetricsGroup {
|
||||
func getNodeHealthMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Minute,
|
||||
cacheInterval: 1 * time.Minute,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(_ context.Context) (metrics []Metric) {
|
||||
metrics = make([]Metric, 0, 16)
|
||||
@@ -2316,9 +2394,10 @@ func getNodeHealthMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getMinioHealingMetrics() *MetricsGroup {
|
||||
func getMinioHealingMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
cacheInterval: 10 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(_ context.Context) (metrics []Metric) {
|
||||
bgSeq, exists := globalBackgroundHealState.getHealSequenceByToken(bgHealingUUID)
|
||||
@@ -2386,9 +2465,10 @@ func getObjectsScanned(seq *healSequence) (m []Metric) {
|
||||
return
|
||||
}
|
||||
|
||||
func getDistLockMetrics() *MetricsGroup {
|
||||
func getDistLockMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Second,
|
||||
cacheInterval: 1 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) []Metric {
|
||||
if !globalIsDistErasure {
|
||||
@@ -2433,9 +2513,10 @@ func getDistLockMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getNotificationMetrics() *MetricsGroup {
|
||||
func getNotificationMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
cacheInterval: 10 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) []Metric {
|
||||
metrics := make([]Metric, 0, 3)
|
||||
@@ -2608,12 +2689,13 @@ func getNotificationMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getHTTPMetrics(bucketOnly bool) *MetricsGroup {
|
||||
func getHTTPMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
cacheInterval: 10 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
if !bucketOnly {
|
||||
if !mg.metricsGroupOpts.bucketOnly {
|
||||
httpStats := globalHTTPStats.toServerHTTPStats()
|
||||
metrics = make([]Metric, 0, 3+
|
||||
len(httpStats.CurrentS3Requests.APIStats)+
|
||||
@@ -2799,16 +2881,13 @@ func getNetworkMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getClusterUsageMetrics() *MetricsGroup {
|
||||
func getClusterUsageMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Minute,
|
||||
cacheInterval: 1 * time.Minute,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
metrics = make([]Metric, 0, 50)
|
||||
dataUsageInfo, err := loadDataUsageFromBackend(ctx, objLayer)
|
||||
@@ -2905,16 +2984,13 @@ func getClusterUsageMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getBucketUsageMetrics() *MetricsGroup {
|
||||
func getBucketUsageMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Minute,
|
||||
cacheInterval: 1 * time.Minute,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
metrics = make([]Metric, 0, 50)
|
||||
dataUsageInfo, err := loadDataUsageFromBackend(ctx, objLayer)
|
||||
@@ -3094,15 +3170,14 @@ func getClusterTransitionedVersionsMD() MetricDescription {
|
||||
}
|
||||
}
|
||||
|
||||
func getClusterTierMetrics() *MetricsGroup {
|
||||
func getClusterTierMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Minute,
|
||||
cacheInterval: 1 * time.Minute,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
objLayer := newObjectLayerFn()
|
||||
if objLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if globalTierConfigMgr.Empty() {
|
||||
return
|
||||
}
|
||||
@@ -3122,16 +3197,13 @@ func getClusterTierMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getLocalStorageMetrics() *MetricsGroup {
|
||||
func getLocalStorageMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Minute,
|
||||
cacheInterval: 1 * time.Minute,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
metrics = make([]Metric, 0, 50)
|
||||
storageInfo := objLayer.LocalStorageInfo(ctx, true)
|
||||
@@ -3276,16 +3348,13 @@ func getClusterErasureSetHealingDrivesMD() MetricDescription {
|
||||
}
|
||||
}
|
||||
|
||||
func getClusterHealthMetrics() *MetricsGroup {
|
||||
func getClusterHealthMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
cacheInterval: 10 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
opts := HealthOptions{}
|
||||
result := objLayer.Health(ctx, opts)
|
||||
@@ -3340,18 +3409,13 @@ func getClusterHealthMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getBatchJobsMetrics() *MetricsGroup {
|
||||
func getBatchJobsMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
cacheInterval: 10 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var m madmin.RealtimeMetrics
|
||||
mLocal := collectLocalMetrics(madmin.MetricsBatchJobs, collectMetricsOpts{})
|
||||
m.Merge(&mLocal)
|
||||
@@ -3411,16 +3475,13 @@ func getBatchJobsMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getClusterStorageMetrics() *MetricsGroup {
|
||||
func getClusterStorageMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 1 * time.Minute,
|
||||
cacheInterval: 1 * time.Minute,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch disk space info, ignore errors
|
||||
metrics = make([]Metric, 0, 10)
|
||||
@@ -3467,18 +3528,13 @@ func getClusterStorageMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getKMSNodeMetrics() *MetricsGroup {
|
||||
func getKMSNodeMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
cacheInterval: 10 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
|
||||
mg.RegisterRead(func(ctx context.Context) (metrics []Metric) {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil || GlobalKMS == nil {
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
Online = 1
|
||||
Offline = 0
|
||||
@@ -3572,18 +3628,13 @@ func getWebhookMetrics() *MetricsGroup {
|
||||
return mg
|
||||
}
|
||||
|
||||
func getKMSMetrics() *MetricsGroup {
|
||||
func getKMSMetrics(opts MetricsGroupOpts) *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
cacheInterval: 10 * time.Second,
|
||||
metricsGroupOpts: opts,
|
||||
}
|
||||
|
||||
mg.RegisterRead(func(ctx context.Context) []Metric {
|
||||
objLayer := newObjectLayerFn()
|
||||
// Service not initialized yet
|
||||
if objLayer == nil || GlobalKMS == nil {
|
||||
return []Metric{}
|
||||
}
|
||||
|
||||
metrics := make([]Metric, 0, 4)
|
||||
metric, err := GlobalKMS.Metrics(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -39,6 +39,8 @@ const (
|
||||
osMetricRename
|
||||
osMetricOpenFileW
|
||||
osMetricOpenFileR
|
||||
osMetricOpenFileWFd
|
||||
osMetricOpenFileRFd
|
||||
osMetricOpen
|
||||
osMetricOpenFileDirectIO
|
||||
osMetricLstat
|
||||
|
||||
+25
-8
@@ -39,6 +39,22 @@ func access(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// openFileWithFD return 'fd' based file descriptor
|
||||
func openFileWithFD(name string, flag int, perm os.FileMode) (fd int, err error) {
|
||||
switch flag & writeMode {
|
||||
case writeMode:
|
||||
defer updateOSMetrics(osMetricOpenFileWFd, name)(err)
|
||||
default:
|
||||
defer updateOSMetrics(osMetricOpenFileRFd, name)(err)
|
||||
}
|
||||
var e error
|
||||
fd, e = syscall.Open(name, flag|syscall.O_CLOEXEC, uint32(perm))
|
||||
if e != nil {
|
||||
return -1, &os.PathError{Op: "open", Path: name, Err: e}
|
||||
}
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// Forked from Golang but chooses to avoid performing lookup
|
||||
//
|
||||
// osMkdirAll creates a directory named path,
|
||||
@@ -149,7 +165,7 @@ func parseDirEnt(buf []byte) (consumed int, name []byte, typ os.FileMode, err er
|
||||
// the directory itself, if the dirPath doesn't exist this function doesn't return
|
||||
// an error.
|
||||
func readDirFn(dirPath string, fn func(name string, typ os.FileMode) error) error {
|
||||
f, err := OpenFile(dirPath, readMode, 0o666)
|
||||
fd, err := openFileWithFD(dirPath, readMode, 0o666)
|
||||
if err != nil {
|
||||
if osErrToFileErr(err) == errFileNotFound {
|
||||
return nil
|
||||
@@ -160,15 +176,16 @@ func readDirFn(dirPath string, fn func(name string, typ os.FileMode) error) erro
|
||||
// There may be permission error when dirPath
|
||||
// is at the root of the disk mount that may
|
||||
// not have the permissions to avoid 'noatime'
|
||||
f, err = Open(dirPath)
|
||||
fd, err = openFileWithFD(dirPath, os.O_RDONLY, 0o666)
|
||||
if err != nil {
|
||||
if osErrToFileErr(err) == errFileNotFound {
|
||||
return nil
|
||||
}
|
||||
return osErrToFileErr(err)
|
||||
}
|
||||
|
||||
}
|
||||
defer f.Close()
|
||||
defer syscall.Close(fd)
|
||||
|
||||
bufp := direntPool.Get().(*[]byte)
|
||||
defer direntPool.Put(bufp)
|
||||
@@ -181,7 +198,7 @@ func readDirFn(dirPath string, fn func(name string, typ os.FileMode) error) erro
|
||||
if boff >= nbuf {
|
||||
boff = 0
|
||||
stop := globalOSMetrics.time(osMetricReadDirent)
|
||||
nbuf, err = syscall.ReadDirent(int(f.Fd()), buf)
|
||||
nbuf, err = syscall.ReadDirent(fd, buf)
|
||||
stop()
|
||||
if err != nil {
|
||||
if isSysErrNotDir(err) {
|
||||
@@ -241,7 +258,7 @@ func readDirFn(dirPath string, fn func(name string, typ os.FileMode) error) erro
|
||||
// Return count entries at the directory dirPath and all entries
|
||||
// if count is set to -1
|
||||
func readDirWithOpts(dirPath string, opts readDirOpts) (entries []string, err error) {
|
||||
f, err := OpenFile(dirPath, readMode, 0o666)
|
||||
fd, err := openFileWithFD(dirPath, readMode, 0o666)
|
||||
if err != nil {
|
||||
if !osIsPermission(err) {
|
||||
return nil, osErrToFileErr(err)
|
||||
@@ -249,12 +266,12 @@ func readDirWithOpts(dirPath string, opts readDirOpts) (entries []string, err er
|
||||
// There may be permission error when dirPath
|
||||
// is at the root of the disk mount that may
|
||||
// not have the permissions to avoid 'noatime'
|
||||
f, err = Open(dirPath)
|
||||
fd, err = openFileWithFD(dirPath, os.O_RDONLY, 0o666)
|
||||
if err != nil {
|
||||
return nil, osErrToFileErr(err)
|
||||
}
|
||||
}
|
||||
defer f.Close()
|
||||
defer syscall.Close(fd)
|
||||
|
||||
bufp := direntPool.Get().(*[]byte)
|
||||
defer direntPool.Put(bufp)
|
||||
@@ -273,7 +290,7 @@ func readDirWithOpts(dirPath string, opts readDirOpts) (entries []string, err er
|
||||
if boff >= nbuf {
|
||||
boff = 0
|
||||
stop := globalOSMetrics.time(osMetricReadDirent)
|
||||
nbuf, err = syscall.ReadDirent(int(f.Fd()), buf)
|
||||
nbuf, err = syscall.ReadDirent(fd, buf)
|
||||
stop()
|
||||
if err != nil {
|
||||
if isSysErrNotDir(err) {
|
||||
|
||||
+16
-14
@@ -14,23 +14,25 @@ func _() {
|
||||
_ = x[osMetricRename-3]
|
||||
_ = x[osMetricOpenFileW-4]
|
||||
_ = x[osMetricOpenFileR-5]
|
||||
_ = x[osMetricOpen-6]
|
||||
_ = x[osMetricOpenFileDirectIO-7]
|
||||
_ = x[osMetricLstat-8]
|
||||
_ = x[osMetricRemove-9]
|
||||
_ = x[osMetricStat-10]
|
||||
_ = x[osMetricAccess-11]
|
||||
_ = x[osMetricCreate-12]
|
||||
_ = x[osMetricReadDirent-13]
|
||||
_ = x[osMetricFdatasync-14]
|
||||
_ = x[osMetricSync-15]
|
||||
_ = x[osMetricRename2-16]
|
||||
_ = x[osMetricLast-17]
|
||||
_ = x[osMetricOpenFileWFd-6]
|
||||
_ = x[osMetricOpenFileRFd-7]
|
||||
_ = x[osMetricOpen-8]
|
||||
_ = x[osMetricOpenFileDirectIO-9]
|
||||
_ = x[osMetricLstat-10]
|
||||
_ = x[osMetricRemove-11]
|
||||
_ = x[osMetricStat-12]
|
||||
_ = x[osMetricAccess-13]
|
||||
_ = x[osMetricCreate-14]
|
||||
_ = x[osMetricReadDirent-15]
|
||||
_ = x[osMetricFdatasync-16]
|
||||
_ = x[osMetricSync-17]
|
||||
_ = x[osMetricRename2-18]
|
||||
_ = x[osMetricLast-19]
|
||||
}
|
||||
|
||||
const _osMetric_name = "RemoveAllMkdirAllMkdirRenameOpenFileWOpenFileROpenOpenFileDirectIOLstatRemoveStatAccessCreateReadDirentFdatasyncSyncRename2Last"
|
||||
const _osMetric_name = "RemoveAllMkdirAllMkdirRenameOpenFileWOpenFileROpenFileWFdOpenFileRFdOpenOpenFileDirectIOLstatRemoveStatAccessCreateReadDirentFdatasyncSyncRename2Last"
|
||||
|
||||
var _osMetric_index = [...]uint8{0, 9, 17, 22, 28, 37, 46, 50, 66, 71, 77, 81, 87, 93, 103, 112, 116, 123, 127}
|
||||
var _osMetric_index = [...]uint8{0, 9, 17, 22, 28, 37, 46, 57, 68, 72, 88, 93, 99, 103, 109, 115, 125, 134, 138, 145, 149}
|
||||
|
||||
func (i osMetric) String() string {
|
||||
if i >= osMetric(len(_osMetric_index)-1) {
|
||||
|
||||
@@ -25,7 +25,9 @@ import (
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/minio/madmin-go/v3"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
"github.com/minio/minio/internal/rest"
|
||||
"github.com/minio/pkg/v2/sync/errgroup"
|
||||
@@ -36,6 +38,7 @@ var errPeerOffline = errors.New("peer is offline")
|
||||
|
||||
type peerS3Client interface {
|
||||
ListBuckets(ctx context.Context, opts BucketOptions) ([]BucketInfo, error)
|
||||
HealBucket(ctx context.Context, bucket string, opts madmin.HealOpts) (madmin.HealResultItem, error)
|
||||
GetBucketInfo(ctx context.Context, bucket string, opts BucketOptions) (BucketInfo, error)
|
||||
MakeBucket(ctx context.Context, bucket string, opts MakeBucketOptions) error
|
||||
DeleteBucket(ctx context.Context, bucket string, opts DeleteBucketOptions) error
|
||||
@@ -67,6 +70,10 @@ func (l localPeerS3Client) ListBuckets(ctx context.Context, opts BucketOptions)
|
||||
return listBucketsLocal(ctx, opts)
|
||||
}
|
||||
|
||||
func (l localPeerS3Client) HealBucket(ctx context.Context, bucket string, opts madmin.HealOpts) (madmin.HealResultItem, error) {
|
||||
return healBucketLocal(ctx, bucket, opts)
|
||||
}
|
||||
|
||||
func (l localPeerS3Client) GetBucketInfo(ctx context.Context, bucket string, opts BucketOptions) (BucketInfo, error) {
|
||||
return getBucketInfoLocal(ctx, bucket, opts)
|
||||
}
|
||||
@@ -124,6 +131,51 @@ func NewS3PeerSys(endpoints EndpointServerPools) *S3PeerSys {
|
||||
}
|
||||
}
|
||||
|
||||
// HealBucket - heals buckets at node level
|
||||
func (sys *S3PeerSys) HealBucket(ctx context.Context, bucket string, opts madmin.HealOpts) (madmin.HealResultItem, error) {
|
||||
g := errgroup.WithNErrs(len(sys.peerClients))
|
||||
|
||||
healBucketResults := make([]madmin.HealResultItem, len(sys.peerClients))
|
||||
for idx, client := range sys.peerClients {
|
||||
idx := idx
|
||||
client := client
|
||||
g.Go(func() error {
|
||||
if client == nil {
|
||||
return errPeerOffline
|
||||
}
|
||||
res, err := client.HealBucket(ctx, bucket, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
healBucketResults[idx] = res
|
||||
return nil
|
||||
}, idx)
|
||||
}
|
||||
|
||||
errs := g.Wait()
|
||||
|
||||
for poolIdx := 0; poolIdx < sys.poolsCount; poolIdx++ {
|
||||
perPoolErrs := make([]error, 0, len(sys.peerClients))
|
||||
for i, client := range sys.peerClients {
|
||||
if slices.Contains(client.GetPools(), poolIdx) {
|
||||
perPoolErrs = append(perPoolErrs, errs[i])
|
||||
}
|
||||
}
|
||||
quorum := len(perPoolErrs) / 2
|
||||
if poolErr := reduceWriteQuorumErrs(ctx, perPoolErrs, bucketOpIgnoredErrs, quorum); poolErr != nil {
|
||||
return madmin.HealResultItem{}, poolErr
|
||||
}
|
||||
}
|
||||
|
||||
for i, err := range errs {
|
||||
if err == nil {
|
||||
return healBucketResults[i], nil
|
||||
}
|
||||
}
|
||||
|
||||
return madmin.HealResultItem{}, toObjectErr(errVolumeNotFound, bucket)
|
||||
}
|
||||
|
||||
// ListBuckets lists buckets across all nodes and returns a consistent view:
|
||||
// - Return an error when a pool cannot return N/2+1 valid bucket information
|
||||
// - For each pool, check if the bucket exists in N/2+1 nodes before including it in the final result
|
||||
@@ -185,6 +237,22 @@ func (sys *S3PeerSys) ListBuckets(ctx context.Context, opts BucketOptions) ([]Bu
|
||||
}
|
||||
}
|
||||
}
|
||||
// loop through buckets and see if some with lost quorum
|
||||
// these could be stale buckets lying around, queue a heal
|
||||
// of such a bucket. This is needed here as we identify such
|
||||
// buckets here while listing buckets. As part of regular
|
||||
// globalBucketMetadataSys.Init() call would get a valid
|
||||
// buckets only and not the quourum lost ones like this, so
|
||||
// explicit call
|
||||
for bktName, count := range bucketsMap {
|
||||
if count < quorum {
|
||||
// Queue a bucket heal task
|
||||
globalMRFState.addPartialOp(partialOperation{
|
||||
bucket: bktName,
|
||||
queued: time.Now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]BucketInfo, 0, len(resultMap))
|
||||
@@ -259,6 +327,23 @@ func (client *remotePeerS3Client) ListBuckets(ctx context.Context, opts BucketOp
|
||||
return buckets, err
|
||||
}
|
||||
|
||||
func (client *remotePeerS3Client) HealBucket(ctx context.Context, bucket string, opts madmin.HealOpts) (madmin.HealResultItem, error) {
|
||||
v := url.Values{}
|
||||
v.Set(peerS3Bucket, bucket)
|
||||
v.Set(peerS3BucketDeleted, strconv.FormatBool(opts.Remove))
|
||||
|
||||
respBody, err := client.call(peerS3MethodHealBucket, v, nil, -1)
|
||||
if err != nil {
|
||||
return madmin.HealResultItem{}, err
|
||||
}
|
||||
defer xhttp.DrainBody(respBody)
|
||||
|
||||
var res madmin.HealResultItem
|
||||
err = gob.NewDecoder(respBody).Decode(&res)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// GetBucketInfo returns bucket stat info from a peer
|
||||
func (client *remotePeerS3Client) GetBucketInfo(ctx context.Context, bucket string, opts BucketOptions) (BucketInfo, error) {
|
||||
v := url.Values{}
|
||||
|
||||
@@ -21,8 +21,10 @@ import (
|
||||
"context"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/minio/madmin-go/v3"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/mux"
|
||||
"github.com/minio/pkg/v2/sync/errgroup"
|
||||
@@ -42,6 +44,7 @@ const (
|
||||
peerS3MethodGetBucketInfo = "/get-bucket-info"
|
||||
peerS3MethodDeleteBucket = "/delete-bucket"
|
||||
peerS3MethodListBuckets = "/list-buckets"
|
||||
peerS3MethodHealBucket = "/heal-bucket"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -78,6 +81,134 @@ func (s *peerS3Server) HealthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.IsValid(w, r)
|
||||
}
|
||||
|
||||
func healBucketLocal(ctx context.Context, bucket string, opts madmin.HealOpts) (res madmin.HealResultItem, err error) {
|
||||
globalLocalDrivesMu.RLock()
|
||||
globalLocalDrives := globalLocalDrives
|
||||
globalLocalDrivesMu.RUnlock()
|
||||
|
||||
// Initialize sync waitgroup.
|
||||
g := errgroup.WithNErrs(len(globalLocalDrives))
|
||||
|
||||
// Disk states slices
|
||||
beforeState := make([]string, len(globalLocalDrives))
|
||||
afterState := make([]string, len(globalLocalDrives))
|
||||
|
||||
// Make a volume entry on all underlying storage disks.
|
||||
for index := range globalLocalDrives {
|
||||
index := index
|
||||
g.Go(func() (serr error) {
|
||||
if globalLocalDrives[index] == nil {
|
||||
beforeState[index] = madmin.DriveStateOffline
|
||||
afterState[index] = madmin.DriveStateOffline
|
||||
return errDiskNotFound
|
||||
}
|
||||
|
||||
beforeState[index] = madmin.DriveStateOk
|
||||
afterState[index] = madmin.DriveStateOk
|
||||
|
||||
if bucket == minioReservedBucket {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, serr = globalLocalDrives[index].StatVol(ctx, bucket)
|
||||
if serr != nil {
|
||||
if serr == errDiskNotFound {
|
||||
beforeState[index] = madmin.DriveStateOffline
|
||||
afterState[index] = madmin.DriveStateOffline
|
||||
return serr
|
||||
}
|
||||
if serr != errVolumeNotFound {
|
||||
beforeState[index] = madmin.DriveStateCorrupt
|
||||
afterState[index] = madmin.DriveStateCorrupt
|
||||
return serr
|
||||
}
|
||||
|
||||
beforeState[index] = madmin.DriveStateMissing
|
||||
afterState[index] = madmin.DriveStateMissing
|
||||
|
||||
return serr
|
||||
}
|
||||
return nil
|
||||
}, index)
|
||||
}
|
||||
|
||||
errs := g.Wait()
|
||||
|
||||
// Initialize heal result info
|
||||
res = madmin.HealResultItem{
|
||||
Type: madmin.HealItemBucket,
|
||||
Bucket: bucket,
|
||||
DiskCount: len(globalLocalDrives),
|
||||
SetCount: -1, // explicitly set an invalid value -1, for bucket heal scenario
|
||||
}
|
||||
|
||||
// mutate only if not a dry-run
|
||||
if opts.DryRun {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
for i := range beforeState {
|
||||
res.Before.Drives = append(res.Before.Drives, madmin.HealDriveInfo{
|
||||
UUID: "",
|
||||
Endpoint: globalLocalDrives[i].String(),
|
||||
State: beforeState[i],
|
||||
})
|
||||
}
|
||||
|
||||
// check dangling and delete bucket only if its not a meta bucket
|
||||
if !isMinioMetaBucketName(bucket) && !isAllBucketsNotFound(errs) && opts.Remove {
|
||||
g := errgroup.WithNErrs(len(globalLocalDrives))
|
||||
for index := range globalLocalDrives {
|
||||
index := index
|
||||
g.Go(func() error {
|
||||
if globalLocalDrives[index] == nil {
|
||||
return errDiskNotFound
|
||||
}
|
||||
err := globalLocalDrives[index].DeleteVol(ctx, bucket, false)
|
||||
if errors.Is(err, errVolumeNotEmpty) {
|
||||
logger.LogOnceIf(ctx, fmt.Errorf("While deleting dangling Bucket (%s), Drive %s:%s returned an error (%w)",
|
||||
bucket, globalLocalDrives[index].Hostname(), globalLocalDrives[index], err), "delete-dangling-bucket-"+bucket)
|
||||
}
|
||||
return nil
|
||||
}, index)
|
||||
}
|
||||
|
||||
g.Wait()
|
||||
}
|
||||
|
||||
// Create the quorum lost volume only if its nor makred for delete
|
||||
if !opts.Remove {
|
||||
// Initialize sync waitgroup.
|
||||
g = errgroup.WithNErrs(len(globalLocalDrives))
|
||||
|
||||
// Make a volume entry on all underlying storage disks.
|
||||
for index := range globalLocalDrives {
|
||||
index := index
|
||||
g.Go(func() error {
|
||||
if beforeState[index] == madmin.DriveStateMissing {
|
||||
makeErr := globalLocalDrives[index].MakeVol(ctx, bucket)
|
||||
if makeErr == nil {
|
||||
afterState[index] = madmin.DriveStateOk
|
||||
}
|
||||
return makeErr
|
||||
}
|
||||
return errs[index]
|
||||
}, index)
|
||||
}
|
||||
|
||||
errs = g.Wait()
|
||||
}
|
||||
|
||||
for i := range afterState {
|
||||
res.After.Drives = append(res.After.Drives, madmin.HealDriveInfo{
|
||||
UUID: "",
|
||||
Endpoint: globalLocalDrives[i].String(),
|
||||
State: afterState[i],
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func listBucketsLocal(ctx context.Context, opts BucketOptions) (buckets []BucketInfo, err error) {
|
||||
globalLocalDrivesMu.RLock()
|
||||
localDrives := globalLocalDrives
|
||||
@@ -259,6 +390,30 @@ func (s *peerS3Server) ListBucketsHandler(w http.ResponseWriter, r *http.Request
|
||||
logger.LogIf(r.Context(), gob.NewEncoder(w).Encode(buckets))
|
||||
}
|
||||
|
||||
func (s *peerS3Server) HealBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.IsValid(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
bucketDeleted := r.Form.Get(peerS3BucketDeleted) == "true"
|
||||
|
||||
bucket := r.Form.Get(peerS3Bucket)
|
||||
if isMinioMetaBucket(bucket) {
|
||||
s.writeErrorResponse(w, errInvalidArgument)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := healBucketLocal(r.Context(), bucket, madmin.HealOpts{
|
||||
Remove: bucketDeleted,
|
||||
})
|
||||
if err != nil {
|
||||
s.writeErrorResponse(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
logger.LogIf(r.Context(), gob.NewEncoder(w).Encode(res))
|
||||
}
|
||||
|
||||
// GetBucketInfoHandler implements peer BuckeInfo call, returns bucket create date.
|
||||
func (s *peerS3Server) GetBucketInfoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.IsValid(w, r) {
|
||||
@@ -333,4 +488,5 @@ func registerPeerS3Handlers(router *mux.Router) {
|
||||
subrouter.Methods(http.MethodPost).Path(peerS3VersionPrefix + peerS3MethodDeleteBucket).HandlerFunc(h(server.DeleteBucketHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerS3VersionPrefix + peerS3MethodGetBucketInfo).HandlerFunc(h(server.GetBucketInfoHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerS3VersionPrefix + peerS3MethodListBuckets).HandlerFunc(h(server.ListBucketsHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerS3VersionPrefix + peerS3MethodHealBucket).HandlerFunc(h(server.HealBucketHandler))
|
||||
}
|
||||
|
||||
Regular → Executable
+3
-3
@@ -24,7 +24,7 @@ export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9000/"
|
||||
(minio server /tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
./mc admin user add myminio/ minio123 minio123
|
||||
./mc admin user add myminio/ minio12345 minio12345
|
||||
@@ -55,7 +55,7 @@ kill $pid
|
||||
(minio server /tmp/xl/{1...10}/disk{0...1} /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded.log) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
expanded_user_count=$(./mc admin user list myminio/ | wc -l)
|
||||
expanded_policy_count=$(./mc admin policy list myminio/ | wc -l)
|
||||
@@ -94,7 +94,7 @@ kill $pid
|
||||
(minio server /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/removed.log) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
decom_user_count=$(./mc admin user list myminio/ | wc -l)
|
||||
decom_policy_count=$(./mc admin policy list myminio/ | wc -l)
|
||||
|
||||
Regular → Executable
+3
-3
@@ -19,7 +19,7 @@ export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9000/"
|
||||
(minio server /tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
./mc admin user add myminio/ minio123 minio123
|
||||
./mc admin user add myminio/ minio12345 minio12345
|
||||
@@ -52,7 +52,7 @@ kill $pid
|
||||
(minio server /tmp/xl/{1...10}/disk{0...1} /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded.log) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
expanded_user_count=$(./mc admin user list myminio/ | wc -l)
|
||||
expanded_policy_count=$(./mc admin policy list myminio/ | wc -l)
|
||||
@@ -98,7 +98,7 @@ kill $pid
|
||||
(minio server /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/removed.log) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
decom_user_count=$(./mc admin user list myminio/ | wc -l)
|
||||
decom_policy_count=$(./mc admin policy list myminio/ | wc -l)
|
||||
|
||||
Regular → Executable
+3
-3
@@ -19,7 +19,7 @@ export MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl
|
||||
(minio server /tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9000/"
|
||||
|
||||
@@ -51,7 +51,7 @@ kill $pid
|
||||
(minio server /tmp/xl/{1...10}/disk{0...1} /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded.log) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
expanded_user_count=$(./mc admin user list myminio/ | wc -l)
|
||||
expanded_policy_count=$(./mc admin policy list myminio/ | wc -l)
|
||||
@@ -90,7 +90,7 @@ kill $pid
|
||||
(minio server /tmp/xl/{11...30}/disk{0...3} 2>&1 >/dev/null) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
decom_user_count=$(./mc admin user list myminio/ | wc -l)
|
||||
decom_policy_count=$(./mc admin policy list myminio/ | wc -l)
|
||||
|
||||
@@ -19,7 +19,7 @@ export MINIO_SCANNER_SPEED=fastest
|
||||
(minio server /tmp/xl/{1...10}/disk{0...1} 2>&1 >/tmp/decom.log) &
|
||||
pid=$!
|
||||
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9000/"
|
||||
|
||||
@@ -49,7 +49,7 @@ policy_count=$(./mc admin policy list myminio/ | wc -l)
|
||||
|
||||
## create a warm tier instance
|
||||
(minio server /tmp/xltier/{1...4}/disk{0...1} --address :9001 2>&1 >/dev/null) &
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
export MC_HOST_mytier="http://minioadmin:minioadmin@localhost:9001/"
|
||||
|
||||
@@ -117,7 +117,7 @@ kill $pid
|
||||
(minio server /tmp/xl/{11...30}/disk{0...3} 2>&1 >/dev/null) &
|
||||
pid=$!
|
||||
|
||||
sleep 20
|
||||
sleep 30
|
||||
|
||||
decom_user_count=$(./mc admin user list myminio/ | wc -l)
|
||||
decom_policy_count=$(./mc admin policy list myminio/ | wc -l)
|
||||
|
||||
Regular → Executable
+1
-1
@@ -58,7 +58,7 @@ site3_pid=$!
|
||||
minio server --config /tmp/minio.configfile.4 >/tmp/minio4_1.log 2>&1 &
|
||||
site4_pid=$!
|
||||
|
||||
sleep 5
|
||||
sleep 30
|
||||
|
||||
export MC_HOST_minio1=http://minr0otUS2r:pBU94AGAY85e@localhost:9001
|
||||
export MC_HOST_minio3=http://minr0otUS2r:pBU94AGAY85e@localhost:9003
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3.7'
|
||||
|
||||
# Settings and configurations that are common for all containers
|
||||
x-minio-common: &minio-common
|
||||
image: quay.io/minio/minio:RELEASE.2024-01-01T16-36-33Z
|
||||
image: quay.io/minio/minio:RELEASE.2024-01-05T22-17-24Z
|
||||
command: server --console-address ":9001" http://minio{1...4}/data{1...2}
|
||||
expose:
|
||||
- "9000"
|
||||
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
github.com/IBM/sarama v1.42.1
|
||||
github.com/alecthomas/participle v0.7.1
|
||||
github.com/bcicen/jstream v1.0.1
|
||||
github.com/beevik/ntp v1.3.0
|
||||
github.com/beevik/ntp v1.3.1
|
||||
github.com/buger/jsonparser v1.1.1
|
||||
github.com/cespare/xxhash/v2 v2.2.0
|
||||
github.com/cheggaaa/pb v1.0.29
|
||||
@@ -26,9 +26,9 @@ require (
|
||||
github.com/felixge/fgprof v0.9.3
|
||||
github.com/fraugster/parquet-go v0.12.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.6
|
||||
github.com/go-openapi/loads v0.21.4
|
||||
github.com/go-openapi/loads v0.21.5
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/gobwas/ws v1.3.1
|
||||
github.com/gobwas/ws v1.3.2
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/gomodule/redigo v1.8.9
|
||||
github.com/google/uuid v1.5.0
|
||||
@@ -45,13 +45,13 @@ require (
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0
|
||||
github.com/miekg/dns v1.1.57
|
||||
github.com/minio/cli v1.24.2
|
||||
github.com/minio/console v0.44.0
|
||||
github.com/minio/console v0.45.0
|
||||
github.com/minio/csvparser v1.0.0
|
||||
github.com/minio/dnscache v0.1.1
|
||||
github.com/minio/dperf v0.5.3
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/minio/kes-go v0.2.0
|
||||
github.com/minio/madmin-go/v3 v3.0.38-0.20231221010728-743d3caa32cf
|
||||
github.com/minio/madmin-go/v3 v3.0.38
|
||||
github.com/minio/minio-go/v7 v7.0.66
|
||||
github.com/minio/mux v1.9.0
|
||||
github.com/minio/pkg/v2 v2.0.8
|
||||
@@ -72,7 +72,7 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/sftp v1.13.6
|
||||
github.com/pkg/xattr v0.4.9
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/prometheus/client_model v0.5.0
|
||||
github.com/prometheus/common v0.45.0
|
||||
github.com/prometheus/procfs v0.12.0
|
||||
@@ -91,13 +91,14 @@ require (
|
||||
go.uber.org/atomic v1.11.0
|
||||
go.uber.org/zap v1.26.0
|
||||
goftp.io/server/v2 v2.0.1
|
||||
golang.org/x/crypto v0.17.0
|
||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848
|
||||
golang.org/x/oauth2 v0.15.0
|
||||
golang.org/x/sys v0.15.0
|
||||
golang.org/x/crypto v0.18.0
|
||||
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e
|
||||
golang.org/x/oauth2 v0.16.0
|
||||
golang.org/x/sys v0.16.0
|
||||
golang.org/x/time v0.5.0
|
||||
google.golang.org/api v0.154.0
|
||||
google.golang.org/api v0.155.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -140,15 +141,15 @@ require (
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-openapi/analysis v0.22.0 // indirect
|
||||
github.com/go-openapi/analysis v0.22.2 // indirect
|
||||
github.com/go-openapi/errors v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.2 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.4 // indirect
|
||||
github.com/go-openapi/runtime v0.26.2 // indirect
|
||||
github.com/go-openapi/spec v0.20.13 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.10 // indirect
|
||||
github.com/go-openapi/swag v0.22.6 // indirect
|
||||
github.com/go-openapi/validate v0.22.4 // indirect
|
||||
github.com/go-openapi/spec v0.20.14 // indirect
|
||||
github.com/go-openapi/strfmt v0.22.0 // indirect
|
||||
github.com/go-openapi/swag v0.22.7 // indirect
|
||||
github.com/go-openapi/validate v0.22.6 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
@@ -156,7 +157,7 @@ require (
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e // indirect
|
||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
@@ -172,7 +173,7 @@ require (
|
||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.9 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.2 // indirect
|
||||
github.com/jessevdk/go-flags v1.5.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
@@ -181,7 +182,7 @@ require (
|
||||
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/jwx v1.2.27 // indirect
|
||||
github.com/lestrrat-go/jwx v1.2.28 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect
|
||||
@@ -195,7 +196,7 @@ require (
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/minio/colorjson v1.0.6 // indirect
|
||||
github.com/minio/filepath v1.0.0 // indirect
|
||||
github.com/minio/mc v0.0.0-20231223084721-c27ddd4adf53 // indirect
|
||||
github.com/minio/mc v0.0.0-20240111054932-d4305a5bf95e // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/websocket v1.6.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
@@ -208,17 +209,17 @@ require (
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.5.0 // indirect
|
||||
github.com/nats-io/nats-streaming-server v0.24.3 // indirect
|
||||
github.com/nats-io/nkeys v0.4.6 // indirect
|
||||
github.com/nats-io/nkeys v0.4.7 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/navidys/tvxwidgets v0.5.0 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.19 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/posener/complete v1.2.3 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/pquerna/cachecontrol v0.2.0 // indirect
|
||||
github.com/prometheus/prom2json v1.3.3 // indirect
|
||||
github.com/rivo/tview v0.0.0-20231206124440-5f078138442e // indirect
|
||||
github.com/rivo/tview v0.0.0-20240101144852-b3bd1aa5e9f2 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rjeczalik/notify v0.9.3 // indirect
|
||||
github.com/rs/xid v1.5.0 // indirect
|
||||
@@ -230,7 +231,7 @@ require (
|
||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||
github.com/unrolled/secure v1.13.0 // indirect
|
||||
github.com/vbauerster/mpb/v8 v8.7.1 // indirect
|
||||
github.com/vbauerster/mpb/v8 v8.7.2 // indirect
|
||||
github.com/xdg/stringprep v1.0.3 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.11 // indirect
|
||||
@@ -243,20 +244,19 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.21.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sync v0.5.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/term v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
||||
google.golang.org/grpc v1.60.1 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
gopkg.in/h2non/filetype.v1 v1.0.5 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -69,8 +69,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/bcicen/jstream v1.0.1 h1:BXY7Cu4rdmc0rhyTVyT3UkxAiX3bnLpKLas9btbH5ck=
|
||||
github.com/bcicen/jstream v1.0.1/go.mod h1:9ielPxqFry7Y4Tg3j4BfjPocfJ3TbsRtXOAYXYmRuAQ=
|
||||
github.com/beevik/ntp v1.3.0 h1:/w5VhpW5BGKS37vFm1p9oVk/t4HnnkKZAZIubHM6F7Q=
|
||||
github.com/beevik/ntp v1.3.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78=
|
||||
github.com/beevik/ntp v1.3.1 h1:Y/srlT8L1yQr58kyPWFPZIxRL8ttx2SRIpVYJqZIlAM=
|
||||
github.com/beevik/ntp v1.3.1/go.mod h1:fT6PylBq86Tsq23ZMEe47b7QQrZfYBFPnpzt0a9kJxw=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -180,26 +180,26 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-openapi/analysis v0.22.0 h1:wQ/d07nf78HNj4u+KiSY0sT234IAyePPbMgpUjUJQR0=
|
||||
github.com/go-openapi/analysis v0.22.0/go.mod h1:acDnkkCI2QxIo8sSIPgmp1wUlRohV7vfGtAIVae73b0=
|
||||
github.com/go-openapi/analysis v0.22.2 h1:ZBmNoP2h5omLKr/srIC9bfqrUGzT6g6gNv03HE9Vpj0=
|
||||
github.com/go-openapi/analysis v0.22.2/go.mod h1:pDF4UbZsQTo/oNuRfAWWd4dAh4yuYf//LYorPTjrpvo=
|
||||
github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY=
|
||||
github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho=
|
||||
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
|
||||
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
|
||||
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
|
||||
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
|
||||
github.com/go-openapi/loads v0.21.4 h1:PKP7B5J3tpLqmTFzg7OeM9vjmcAi3axt9+kouFOvJxQ=
|
||||
github.com/go-openapi/loads v0.21.4/go.mod h1:PxTsnFBoBe+z89riT+wYt3prmSBP6GDAQh2l9H1Flz8=
|
||||
github.com/go-openapi/loads v0.21.5 h1:jDzF4dSoHw6ZFADCGltDb2lE4F6De7aWSpe+IcsRzT0=
|
||||
github.com/go-openapi/loads v0.21.5/go.mod h1:PxTsnFBoBe+z89riT+wYt3prmSBP6GDAQh2l9H1Flz8=
|
||||
github.com/go-openapi/runtime v0.26.2 h1:elWyB9MacRzvIVgAZCBJmqTi7hBzU0hlKD4IvfX0Zl0=
|
||||
github.com/go-openapi/runtime v0.26.2/go.mod h1:O034jyRZ557uJKzngbMDJXkcKJVzXJiymdSfgejrcRw=
|
||||
github.com/go-openapi/spec v0.20.13 h1:XJDIN+dLH6vqXgafnl5SUIMnzaChQ6QTo0/UPMbkIaE=
|
||||
github.com/go-openapi/spec v0.20.13/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
|
||||
github.com/go-openapi/strfmt v0.21.10 h1:JIsly3KXZB/Qf4UzvzJpg4OELH/0ASDQsyk//TTBDDk=
|
||||
github.com/go-openapi/strfmt v0.21.10/go.mod h1:vNDMwbilnl7xKiO/Ve/8H8Bb2JIInBnH+lqiw6QWgis=
|
||||
github.com/go-openapi/swag v0.22.6 h1:dnqg1XfHXL9aBxSbktBqFR5CxVyVI+7fYWhAf1JOeTw=
|
||||
github.com/go-openapi/swag v0.22.6/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
|
||||
github.com/go-openapi/validate v0.22.4 h1:5v3jmMyIPKTR8Lv9syBAIRxG6lY0RqeBPB1LKEijzk8=
|
||||
github.com/go-openapi/validate v0.22.4/go.mod h1:qm6O8ZIcPVdSY5219468Jv7kBdGvkiZLPOmqnqTUZ2A=
|
||||
github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
|
||||
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
|
||||
github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI=
|
||||
github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4=
|
||||
github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8=
|
||||
github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
|
||||
github.com/go-openapi/validate v0.22.6 h1:+NhuwcEYpWdO5Nm4bmvhGLW0rt1Fcc532Mu3wpypXfo=
|
||||
github.com/go-openapi/validate v0.22.6/go.mod h1:eaddXSqKeTg5XpSmj1dYyFTK/95n/XHwcOY+BMxKMyM=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
@@ -209,8 +209,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU=
|
||||
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/gobwas/ws v1.3.2 h1:zlnbNHxumkRvfPWgfXu8RBwyNR1x8wh9cf5PTOCqs9Q=
|
||||
github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
@@ -262,8 +262,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e h1:bwOy7hAFd0C91URzMIEBfr6BAz29yk7Qj0cy6S7DJlU=
|
||||
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 h1:dHLYa5D8/Ta0aLR2XcPsrkpAgGeFs6thhMcQK0oQ0n8=
|
||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
@@ -327,8 +327,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.9 h1:vZ6bjGg2eBSrJn365qlxGcaWu09Id+LHtrfDWlB2Usc=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.9/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.2 h1:1zphkAo77tdoCkdqIYsMHoXmEGTnTy3GZ6Mn+NyIro0=
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.2/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg=
|
||||
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jlaffaye/ftp v0.0.0-20190624084859-c1312a7102bf/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY=
|
||||
@@ -380,8 +380,8 @@ github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZ
|
||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||
github.com/lestrrat-go/jwx v1.2.27 h1:cvnTnda/YzdyFuWdEAMkI6BsLtItSrASEVCI3C/IUEQ=
|
||||
github.com/lestrrat-go/jwx v1.2.27/go.mod h1:Stob9LjSqR3lOmNdxF0/TvZo60V3hUGv8Fr7Bwzla3k=
|
||||
github.com/lestrrat-go/jwx v1.2.28 h1:uadI6o0WpOVrBSf498tRXZIwPpEtLnR9CvqPFXeI5sA=
|
||||
github.com/lestrrat-go/jwx v1.2.28/go.mod h1:nF+91HEMh/MYFVwKPl5HHsBGMPscqbQb+8IDQdIazP8=
|
||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
@@ -416,7 +416,6 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
@@ -430,8 +429,8 @@ github.com/minio/cli v1.24.2 h1:J+fCUh9mhPLjN3Lj/YhklXvxj8mnyE/D6FpFduXJ2jg=
|
||||
github.com/minio/cli v1.24.2/go.mod h1:bYxnK0uS629N3Bq+AOZZ+6lwF77Sodk4+UL9vNuXhOY=
|
||||
github.com/minio/colorjson v1.0.6 h1:m7TUvpvt0u7FBmVIEQNIa0T4NBQlxrcMBp4wJKsg2Ik=
|
||||
github.com/minio/colorjson v1.0.6/go.mod h1:LUXwS5ZGNb6Eh9f+t+3uJiowD3XsIWtsvTriUBeqgYs=
|
||||
github.com/minio/console v0.44.0 h1:VclHJzIT7tzaTJ3JG6n5vBizpk7XyBIpyOFsv+E+ojE=
|
||||
github.com/minio/console v0.44.0/go.mod h1:nUPbLiOTMLEDb2JK/tvY75l7Cg+d3BDqJhI7881U+rc=
|
||||
github.com/minio/console v0.45.0 h1:Bo3lpMoqmuai4z/+R0YBh23Qw55a3je35OsqUGPSK6s=
|
||||
github.com/minio/console v0.45.0/go.mod h1:nUPbLiOTMLEDb2JK/tvY75l7Cg+d3BDqJhI7881U+rc=
|
||||
github.com/minio/csvparser v1.0.0 h1:xJEHcYK8ZAjeW4hNV9Zu30u+/2o4UyPnYgyjWp8b7ZU=
|
||||
github.com/minio/csvparser v1.0.0/go.mod h1:lKXskSLzPgC5WQyzP7maKH7Sl1cqvANXo9YCto8zbtM=
|
||||
github.com/minio/dnscache v0.1.1 h1:AMYLqomzskpORiUA1ciN9k7bZT1oB3YZN4cEIi88W5o=
|
||||
@@ -444,10 +443,10 @@ github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/minio/kes-go v0.2.0 h1:HA33arq9s3MErbsj3PAXFVfFo4U4yw7lTKQ5kWFrpCA=
|
||||
github.com/minio/kes-go v0.2.0/go.mod h1:VorHLaIYis9/MxAHAtXN4d8PUMNKhIxTIlvFt0hBOEo=
|
||||
github.com/minio/madmin-go/v3 v3.0.38-0.20231221010728-743d3caa32cf h1:JlSWDteG4F4Q9rpTxLctWv/r6+wd0TTlevXtPd1Ecg8=
|
||||
github.com/minio/madmin-go/v3 v3.0.38-0.20231221010728-743d3caa32cf/go.mod h1:4QN2NftLSV7MdlT50dkrenOMmNVHluxTvlqJou3hte8=
|
||||
github.com/minio/mc v0.0.0-20231223084721-c27ddd4adf53 h1:fo8cqbNFT4zI+XMQak5/I5X1KqNNTNOn16SwphRyhLQ=
|
||||
github.com/minio/mc v0.0.0-20231223084721-c27ddd4adf53/go.mod h1:wFVJTmLJniMFDkcvPP0h/KvCxK+MiA2rc6q7KUefN28=
|
||||
github.com/minio/madmin-go/v3 v3.0.38 h1:hgyQg43IkTq40ymFWoJwZyoqjYoT2GkiPlc1e7Bu+dY=
|
||||
github.com/minio/madmin-go/v3 v3.0.38/go.mod h1:4QN2NftLSV7MdlT50dkrenOMmNVHluxTvlqJou3hte8=
|
||||
github.com/minio/mc v0.0.0-20240111054932-d4305a5bf95e h1:vKnv5aBTcAAnDGYeJW/SPieXCerp/7MIYxuEUYt7iOE=
|
||||
github.com/minio/mc v0.0.0-20240111054932-d4305a5bf95e/go.mod h1:wFVJTmLJniMFDkcvPP0h/KvCxK+MiA2rc6q7KUefN28=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v6 v6.0.46/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
@@ -510,8 +509,8 @@ github.com/nats-io/nats.go v1.22.1/go.mod h1:tLqubohF7t4z3du1QDPYJIQQyhb4wl6Dhjx
|
||||
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
|
||||
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
|
||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||
github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
|
||||
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
|
||||
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nats-io/stan.go v0.10.2/go.mod h1:vo2ax8K2IxaR3JtEMLZRFKIdoK/3o1/PKueapB7ezX0=
|
||||
@@ -536,14 +535,13 @@ github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
|
||||
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.1.19 h1:tYLzDnjDXh9qIxSTKHwXwOYmm9d887Y7Y1ZkyXYHAN4=
|
||||
github.com/pierrec/lz4/v4 v4.1.19/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
|
||||
github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
|
||||
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
|
||||
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
|
||||
@@ -561,8 +559,8 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
@@ -587,8 +585,8 @@ github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc
|
||||
github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rivo/tview v0.0.0-20231206124440-5f078138442e h1:mPy47VW9tkqImnSPgcjnEHJuG3XHDBtXj2hDb1qBrRs=
|
||||
github.com/rivo/tview v0.0.0-20231206124440-5f078138442e/go.mod h1:c0SPlNPXkM+/Zgjn/0vD3W0Ds1yxstN7lpquqLDpWCg=
|
||||
github.com/rivo/tview v0.0.0-20240101144852-b3bd1aa5e9f2 h1:Q41smlaCKxGtMlRwvZchzy7iDXAk89Wj5wMhlZXkpMI=
|
||||
github.com/rivo/tview v0.0.0-20240101144852-b3bd1aa5e9f2/go.mod h1:c0SPlNPXkM+/Zgjn/0vD3W0Ds1yxstN7lpquqLDpWCg=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
@@ -637,7 +635,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
@@ -665,8 +662,8 @@ github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFs
|
||||
github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/vbauerster/mpb/v8 v8.7.1 h1:bQoSMMTFAg/gjsLrBYmO8gbRcZt7aDq6WI2IMa9BTqM=
|
||||
github.com/vbauerster/mpb/v8 v8.7.1/go.mod h1:fWgXcAu4W+0cBSUh4ZlaKJyC2KtgU27ZSTaiIk0QNsQ=
|
||||
github.com/vbauerster/mpb/v8 v8.7.2 h1:SMJtxhNho1MV3OuFgS1DAzhANN1Ejc5Ct+0iSaIkB14=
|
||||
github.com/vbauerster/mpb/v8 v8.7.2/go.mod h1:ZFnrjzspgDHoxYLGvxIruiNk73GNTPG4YHgVNpR10VY=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
@@ -738,14 +735,13 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
|
||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e h1:723BNChdd0c2Wk6WOE320qGBiPtYx0F0Bbm1kriShfE=
|
||||
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
@@ -780,12 +776,11 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
|
||||
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
|
||||
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
|
||||
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -795,8 +790,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -836,12 +831,11 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -849,10 +843,10 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -863,7 +857,6 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
@@ -891,8 +884,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
google.golang.org/api v0.154.0 h1:X7QkVKZBskztmpPKWQXgjJRPA2dJYrL6r+sYPRLj050=
|
||||
google.golang.org/api v0.154.0/go.mod h1:qhSMkM85hgqiokIYsrRyKxrjfBeIhgl4Z2JmeRkYylc=
|
||||
google.golang.org/api v0.155.0 h1:vBmGhCYs0djJttDNynWo44zosHlPvHmA0XiN2zP2DtA=
|
||||
google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
@@ -900,12 +893,12 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 h1:YJ5pD9rF8o9Qtta0Cmy9rdBwkSjrTCT6XTiUQVOtIos=
|
||||
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA=
|
||||
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1 h1:/IWabOtPziuXTEtI1KYCpM6Ss7vaAkeMxk+uXV/xvZs=
|
||||
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
|
||||
@@ -128,7 +128,7 @@ type JSONPath struct {
|
||||
// AliasedExpression is an expression that can be optionally named
|
||||
type AliasedExpression struct {
|
||||
Expression *Expression `parser:"@@"`
|
||||
As string `parser:"[ \"AS\" @Ident ]"`
|
||||
As string `parser:"[ \"AS\" @Ident | \"AS\" @LitString ]"`
|
||||
}
|
||||
|
||||
// Grammar for Expression
|
||||
|
||||
@@ -383,3 +383,13 @@ func TestSqlLexerArithOps(t *testing.T) {
|
||||
// fmt.Printf("%d: %#v\n", i, t)
|
||||
// }
|
||||
}
|
||||
|
||||
func TestParseSelectStatement(t *testing.T) {
|
||||
exp, err := ParseSelectStatement("select _3,_1,_2 as 'mytest' from S3object")
|
||||
if err != nil {
|
||||
t.Fatalf("parse alias sql error: %v", err)
|
||||
}
|
||||
if exp.selectAST.Expression.Expressions[2].As != "mytest" {
|
||||
t.Fatalf("parse alias sql error: %s not equal %s", exp.selectAST.Expression.Expressions[2].As, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,14 @@ func ParseSelectStatement(s string) (stmt SelectStatement, err error) {
|
||||
|
||||
// Set table alias
|
||||
stmt.tableAlias = selectAST.From.As
|
||||
// Remove quotes from column aliases
|
||||
if selectAST.Expression != nil {
|
||||
for _, exp := range selectAST.Expression.Expressions {
|
||||
if strings.HasSuffix(exp.As, "'") && strings.HasPrefix(exp.As, "'") && len(exp.As) >= 2 {
|
||||
exp.As = exp.As[1 : len(exp.As)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user