mirror of
https://github.com/minio/mc.git
synced 2025-11-10 13:42:32 +03:00
cp: Add object lock related flags (#3127)
- Adds --retention-mode,--retention-duration & --legal-hold flags in cp command - Adds --bypass flag in rm command
This commit is contained in:
@@ -503,8 +503,8 @@ func deleteFile(deletePath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove - remove entry read from ClientContent channel.
|
// Remove - remove entry read from clientContent channel.
|
||||||
func (f *fsClient) Remove(isIncomplete, isRemoveBucket bool, contentCh <-chan *ClientContent) <-chan *probe.Error {
|
func (f *fsClient) Remove(isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *ClientContent) <-chan *probe.Error {
|
||||||
errorCh := make(chan *probe.Error)
|
errorCh := make(chan *probe.Error)
|
||||||
|
|
||||||
// Goroutine reads from contentCh and removes the entry in content.
|
// Goroutine reads from contentCh and removes the entry in content.
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ const (
|
|||||||
AmzObjectLockMode = "X-Amz-Object-Lock-Mode"
|
AmzObjectLockMode = "X-Amz-Object-Lock-Mode"
|
||||||
// AmzObjectLockRetainUntilDate sets object lock retain until date
|
// AmzObjectLockRetainUntilDate sets object lock retain until date
|
||||||
AmzObjectLockRetainUntilDate = "X-Amz-Object-Lock-Retain-Until-Date"
|
AmzObjectLockRetainUntilDate = "X-Amz-Object-Lock-Retain-Until-Date"
|
||||||
|
// AmzObjectLockLegalHold sets object lock legal hold
|
||||||
|
AmzObjectLockLegalHold = "X-Amz-Object-Lock-Legal-Hold"
|
||||||
)
|
)
|
||||||
|
|
||||||
var timeSentinel = time.Unix(0, 0).UTC()
|
var timeSentinel = time.Unix(0, 0).UTC()
|
||||||
@@ -785,8 +787,32 @@ func (c *S3Client) Copy(source string, size int64, progress io.Reader, srcSSE, t
|
|||||||
// Source object
|
// Source object
|
||||||
src := minio.NewSourceInfo(tokens[1], tokens[2], srcSSE)
|
src := minio.NewSourceInfo(tokens[1], tokens[2], srcSSE)
|
||||||
|
|
||||||
|
destOpts := minio.DestInfoOptions{
|
||||||
|
Encryption: tgtSSE,
|
||||||
|
}
|
||||||
|
|
||||||
|
if lockModeStr, ok := metadata[AmzObjectLockMode]; ok {
|
||||||
|
destOpts.Mode = minio.RetentionMode(strings.ToUpper(lockModeStr))
|
||||||
|
delete(metadata, AmzObjectLockMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if retainUntilDateStr, ok := metadata[AmzObjectLockRetainUntilDate]; ok {
|
||||||
|
delete(metadata, AmzObjectLockRetainUntilDate)
|
||||||
|
if t, e := time.Parse(time.RFC3339, retainUntilDateStr); e == nil {
|
||||||
|
destOpts.RetainUntilDate = t.UTC()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if lh, ok := metadata[AmzObjectLockLegalHold]; ok {
|
||||||
|
destOpts.LegalHold = minio.LegalHoldStatus(lh)
|
||||||
|
delete(metadata, AmzObjectLockLegalHold)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign metadata after irrelevant parts are delete above
|
||||||
|
destOpts.UserMeta = metadata
|
||||||
|
|
||||||
// Destination object
|
// Destination object
|
||||||
dst, e := minio.NewDestinationInfo(dstBucket, dstObject, tgtSSE, metadata)
|
dst, e := minio.NewDestinationInfoWithOptions(dstBucket, dstObject, destOpts)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return probe.NewError(e)
|
return probe.NewError(e)
|
||||||
}
|
}
|
||||||
@@ -865,7 +891,7 @@ func (c *S3Client) Put(ctx context.Context, reader io.Reader, size int64, metada
|
|||||||
lockModeStr, ok := metadata[AmzObjectLockMode]
|
lockModeStr, ok := metadata[AmzObjectLockMode]
|
||||||
lockMode := minio.RetentionMode("")
|
lockMode := minio.RetentionMode("")
|
||||||
if ok {
|
if ok {
|
||||||
lockMode = minio.RetentionMode(lockModeStr)
|
lockMode = minio.RetentionMode(strings.ToUpper(lockModeStr))
|
||||||
delete(metadata, AmzObjectLockMode)
|
delete(metadata, AmzObjectLockMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -892,10 +918,18 @@ func (c *S3Client) Put(ctx context.Context, reader io.Reader, size int64, metada
|
|||||||
}
|
}
|
||||||
if retainUntilDate != timeSentinel {
|
if retainUntilDate != timeSentinel {
|
||||||
opts.RetainUntilDate = &retainUntilDate
|
opts.RetainUntilDate = &retainUntilDate
|
||||||
|
opts.SendContentMd5 = true
|
||||||
}
|
}
|
||||||
if lockModeStr != "" {
|
if lockModeStr != "" {
|
||||||
opts.Mode = &lockMode
|
opts.Mode = &lockMode
|
||||||
|
opts.SendContentMd5 = true
|
||||||
}
|
}
|
||||||
|
if lh, ok := metadata[AmzObjectLockLegalHold]; ok {
|
||||||
|
delete(metadata, AmzObjectLockLegalHold)
|
||||||
|
opts.LegalHold = minio.LegalHoldStatus(strings.ToUpper(lh))
|
||||||
|
opts.SendContentMd5 = true
|
||||||
|
}
|
||||||
|
|
||||||
n, e := c.api.PutObjectWithContext(ctx, bucket, object, reader, size, opts)
|
n, e := c.api.PutObjectWithContext(ctx, bucket, object, reader, size, opts)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
errResponse := minio.ToErrorResponse(e)
|
errResponse := minio.ToErrorResponse(e)
|
||||||
@@ -962,13 +996,16 @@ func (c *S3Client) AddUserAgent(app string, version string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove - remove object or bucket(s).
|
// Remove - remove object or bucket(s).
|
||||||
func (c *S3Client) Remove(isIncomplete, isRemoveBucket bool, contentCh <-chan *ClientContent) <-chan *probe.Error {
|
func (c *S3Client) Remove(isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *ClientContent) <-chan *probe.Error {
|
||||||
errorCh := make(chan *probe.Error)
|
errorCh := make(chan *probe.Error)
|
||||||
|
|
||||||
prevBucket := ""
|
prevBucket := ""
|
||||||
// Maintain objectsCh, statusCh for each bucket
|
// Maintain objectsCh, statusCh for each bucket
|
||||||
var objectsCh chan string
|
var objectsCh chan string
|
||||||
var statusCh <-chan minio.RemoveObjectError
|
var statusCh <-chan minio.RemoveObjectError
|
||||||
|
opts := minio.RemoveObjectsOptions{
|
||||||
|
GovernanceBypass: isBypass,
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(errorCh)
|
defer close(errorCh)
|
||||||
@@ -995,7 +1032,7 @@ func (c *S3Client) Remove(isIncomplete, isRemoveBucket bool, contentCh <-chan *C
|
|||||||
if isIncomplete {
|
if isIncomplete {
|
||||||
statusCh = c.removeIncompleteObjects(bucket, objectsCh)
|
statusCh = c.removeIncompleteObjects(bucket, objectsCh)
|
||||||
} else {
|
} else {
|
||||||
statusCh = c.api.RemoveObjects(bucket, objectsCh)
|
statusCh = c.api.RemoveObjectsWithOptions(bucket, objectsCh, opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,7 +1054,7 @@ func (c *S3Client) Remove(isIncomplete, isRemoveBucket bool, contentCh <-chan *C
|
|||||||
if isIncomplete {
|
if isIncomplete {
|
||||||
statusCh = c.removeIncompleteObjects(bucket, objectsCh)
|
statusCh = c.removeIncompleteObjects(bucket, objectsCh)
|
||||||
} else {
|
} else {
|
||||||
statusCh = c.api.RemoveObjects(bucket, objectsCh)
|
statusCh = c.api.RemoveObjectsWithOptions(bucket, objectsCh, opts)
|
||||||
}
|
}
|
||||||
prevBucket = bucket
|
prevBucket = bucket
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,8 +80,7 @@ type Client interface {
|
|||||||
Watch(params watchParams) (*WatchObject, *probe.Error)
|
Watch(params watchParams) (*WatchObject, *probe.Error)
|
||||||
|
|
||||||
// Delete operations
|
// Delete operations
|
||||||
Remove(isIncomplete, isRemoveBucket bool, contentCh <-chan *ClientContent) (errorCh <-chan *probe.Error)
|
Remove(isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *ClientContent) (errorCh <-chan *probe.Error)
|
||||||
|
|
||||||
// GetURL returns back internal url
|
// GetURL returns back internal url
|
||||||
GetURL() ClientURL
|
GetURL() ClientURL
|
||||||
|
|
||||||
@@ -105,6 +104,10 @@ type ClientContent struct {
|
|||||||
ETag string
|
ETag string
|
||||||
Expires time.Time
|
Expires time.Time
|
||||||
Retention bool
|
Retention bool
|
||||||
|
RetentionMode string
|
||||||
|
RetentionDuration string
|
||||||
|
BypassGovernance bool
|
||||||
|
LegalHold string
|
||||||
Err *probe.Error
|
Err *probe.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -241,11 +241,14 @@ func putTargetRetention(ctx context.Context, alias string, urlStr string, metada
|
|||||||
}
|
}
|
||||||
|
|
||||||
// putTargetStream writes to URL from Reader.
|
// putTargetStream writes to URL from Reader.
|
||||||
func putTargetStream(ctx context.Context, alias string, urlStr string, reader io.Reader, size int64, metadata map[string]string, progress io.Reader, sse encrypt.ServerSide, disableMultipart bool) (int64, *probe.Error) {
|
func putTargetStream(ctx context.Context, alias, urlStr, mode, until, legalHold string, reader io.Reader, size int64, metadata map[string]string, progress io.Reader, sse encrypt.ServerSide, disableMultipart bool) (int64, *probe.Error) {
|
||||||
targetClnt, err := newClientFromAlias(alias, urlStr)
|
targetClnt, err := newClientFromAlias(alias, urlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err.Trace(alias, urlStr)
|
return 0, err.Trace(alias, urlStr)
|
||||||
}
|
}
|
||||||
|
metadata[AmzObjectLockMode] = mode
|
||||||
|
metadata[AmzObjectLockRetainUntilDate] = until
|
||||||
|
metadata[AmzObjectLockLegalHold] = legalHold
|
||||||
n, err := targetClnt.Put(ctx, reader, size, metadata, progress, sse, disableMultipart)
|
n, err := targetClnt.Put(ctx, reader, size, metadata, progress, sse, disableMultipart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err.Trace(alias, urlStr)
|
return n, err.Trace(alias, urlStr)
|
||||||
@@ -263,16 +266,22 @@ func putTargetStreamWithURL(urlStr string, reader io.Reader, size int64, sse enc
|
|||||||
metadata := map[string]string{
|
metadata := map[string]string{
|
||||||
"Content-Type": contentType,
|
"Content-Type": contentType,
|
||||||
}
|
}
|
||||||
return putTargetStream(context.Background(), alias, urlStrFull, reader, size, metadata, nil, sse, disableMultipart)
|
return putTargetStream(context.Background(), alias, urlStrFull, "", "", "", reader, size, metadata, nil, sse, disableMultipart)
|
||||||
}
|
}
|
||||||
|
|
||||||
// copySourceToTargetURL copies to targetURL from source.
|
// copySourceToTargetURL copies to targetURL from source.
|
||||||
func copySourceToTargetURL(alias string, urlStr string, source string, size int64, progress io.Reader, srcSSE, tgtSSE encrypt.ServerSide, metadata map[string]string, disableMultipart bool) *probe.Error {
|
func copySourceToTargetURL(alias, urlStr, source, mode, until, legalHold string, size int64, progress io.Reader, srcSSE, tgtSSE encrypt.ServerSide, metadata map[string]string, disableMultipart bool) *probe.Error {
|
||||||
|
|
||||||
targetClnt, err := newClientFromAlias(alias, urlStr)
|
targetClnt, err := newClientFromAlias(alias, urlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.Trace(alias, urlStr)
|
return err.Trace(alias, urlStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metadata[AmzObjectLockMode] = mode
|
||||||
|
metadata[AmzObjectLockRetainUntilDate] = until
|
||||||
|
metadata[AmzObjectLockLegalHold] = legalHold
|
||||||
err = targetClnt.Copy(source, size, progress, srcSSE, tgtSSE, metadata, disableMultipart)
|
err = targetClnt.Copy(source, size, progress, srcSSE, tgtSSE, metadata, disableMultipart)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.Trace(alias, urlStr)
|
return err.Trace(alias, urlStr)
|
||||||
}
|
}
|
||||||
@@ -336,6 +345,21 @@ func uploadSourceToTargetURL(ctx context.Context, urls URLs, progress io.Reader,
|
|||||||
var err *probe.Error
|
var err *probe.Error
|
||||||
var metadata = map[string]string{}
|
var metadata = map[string]string{}
|
||||||
|
|
||||||
|
var mode, until string
|
||||||
|
var pErr error
|
||||||
|
// add object retention fields in metadata
|
||||||
|
if urls.TargetContent.RetentionDuration != "" && urls.TargetContent.RetentionMode != "" {
|
||||||
|
m := minio.RetentionMode(strings.ToUpper(urls.TargetContent.RetentionMode))
|
||||||
|
|
||||||
|
dur, unit := parseRetentionValidity(urls.TargetContent.RetentionDuration, m)
|
||||||
|
mode = urls.TargetContent.RetentionMode
|
||||||
|
|
||||||
|
until, pErr = getRetainUntilDate(dur, unit)
|
||||||
|
if err != nil {
|
||||||
|
return urls.WithError(probe.NewError(pErr).Trace(sourceURL.String()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Optimize for server side copy if the host is same.
|
// Optimize for server side copy if the host is same.
|
||||||
if sourceAlias == targetAlias {
|
if sourceAlias == targetAlias {
|
||||||
for k, v := range urls.SourceContent.UserMetadata {
|
for k, v := range urls.SourceContent.UserMetadata {
|
||||||
@@ -358,7 +382,7 @@ func uploadSourceToTargetURL(ctx context.Context, urls URLs, progress io.Reader,
|
|||||||
err = putTargetRetention(ctx, targetAlias, targetURL.String(), metadata)
|
err = putTargetRetention(ctx, targetAlias, targetURL.String(), metadata)
|
||||||
return urls.WithError(err.Trace(sourceURL.String()))
|
return urls.WithError(err.Trace(sourceURL.String()))
|
||||||
}
|
}
|
||||||
err = copySourceToTargetURL(targetAlias, targetURL.String(), sourcePath, length,
|
err = copySourceToTargetURL(targetAlias, targetURL.String(), sourcePath, mode, until, urls.TargetContent.LegalHold, length,
|
||||||
progress, srcSSE, tgtSSE, filterMetadata(metadata), urls.DisableMultipart)
|
progress, srcSSE, tgtSSE, filterMetadata(metadata), urls.DisableMultipart)
|
||||||
} else {
|
} else {
|
||||||
if len(metadata) == 0 {
|
if len(metadata) == 0 {
|
||||||
@@ -386,7 +410,7 @@ func uploadSourceToTargetURL(ctx context.Context, urls URLs, progress io.Reader,
|
|||||||
for k, v := range urls.TargetContent.UserMetadata {
|
for k, v := range urls.TargetContent.UserMetadata {
|
||||||
metadata[k] = v
|
metadata[k] = v
|
||||||
}
|
}
|
||||||
_, err = putTargetStream(ctx, targetAlias, targetURL.String(), reader, length, filterMetadata(metadata),
|
_, err = putTargetStream(ctx, targetAlias, targetURL.String(), mode, until, urls.TargetContent.LegalHold, reader, length, filterMetadata(metadata),
|
||||||
progress, tgtSSE, urls.DisableMultipart)
|
progress, tgtSSE, urls.DisableMultipart)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -73,9 +73,25 @@ var (
|
|||||||
Name: "disable-multipart",
|
Name: "disable-multipart",
|
||||||
Usage: "disable multipart upload feature",
|
Usage: "disable multipart upload feature",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: rmFlag,
|
||||||
|
Usage: "retention mode to be applied on the object (governance, compliance)",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: rdFlag,
|
||||||
|
Usage: "retention duration for the object in d days or y years",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: lhFlag,
|
||||||
|
Usage: "apply legal hold to the copied object (on, off)",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var rmFlag = "retention-mode"
|
||||||
|
var rdFlag = "retention-duration"
|
||||||
|
var lhFlag = "legal-hold"
|
||||||
|
|
||||||
// ErrInvalidMetadata reflects invalid metadata format
|
// ErrInvalidMetadata reflects invalid metadata format
|
||||||
var ErrInvalidMetadata = errors.New("specified metadata should be of form key1=value1;key2=value2;... and so on")
|
var ErrInvalidMetadata = errors.New("specified metadata should be of form key1=value1;key2=value2;... and so on")
|
||||||
|
|
||||||
@@ -146,10 +162,13 @@ EXAMPLES:
|
|||||||
15. Copy a text file to an object storage and preserve the file system attribute as metadata.
|
15. Copy a text file to an object storage and preserve the file system attribute as metadata.
|
||||||
{{.Prompt}} {{.HelpName}} -a myobject.txt play/mybucket
|
{{.Prompt}} {{.HelpName}} -a myobject.txt play/mybucket
|
||||||
|
|
||||||
16. Copy a text file to an object storage with object lock mode set to 'GOVERNANCE' with retention date.
|
16. Copy a text file to an object storage with object lock mode set to 'GOVERNANCE' with retention duration 1 day.
|
||||||
{{.Prompt}} {{.HelpName}} --attr "x-amz-object-lock-mode=GOVERNANCE;x-amz-object-lock-retain-until-date=2020-01-11T01:57:02Z" locked.txt play/locked-bucket/
|
{{.Prompt}} {{.HelpName}} --retention-mode governance --retention-duration 1d locked.txt play/locked-bucket/
|
||||||
|
|
||||||
17. Copy a text file to an object storage and disable multipart upload feature.
|
17. Copy a text file to an object storage with legal-hold enabled.
|
||||||
|
{{.Prompt}} {{.HelpName}} --legal-hold on locked.txt play/locked-bucket/
|
||||||
|
|
||||||
|
18. Copy a text file to an object storage and disable multipart upload feature.
|
||||||
{{.Prompt}} {{.HelpName}} --disable-multipart myobject.txt play/mybucket
|
{{.Prompt}} {{.HelpName}} --disable-multipart myobject.txt play/mybucket
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
@@ -192,7 +211,7 @@ type ProgressReader interface {
|
|||||||
Progress
|
Progress
|
||||||
}
|
}
|
||||||
|
|
||||||
// doCopy - Copy a singe file from source to destination
|
// doCopy - Copy a single file from source to destination
|
||||||
func doCopy(ctx context.Context, cpURLs URLs, pg ProgressReader, encKeyDB map[string][]prefixSSEPair) URLs {
|
func doCopy(ctx context.Context, cpURLs URLs, pg ProgressReader, encKeyDB map[string][]prefixSSEPair) URLs {
|
||||||
if cpURLs.Error != nil {
|
if cpURLs.Error != nil {
|
||||||
cpURLs.Error = cpURLs.Error.Trace()
|
cpURLs.Error = cpURLs.Error.Trace()
|
||||||
@@ -435,6 +454,22 @@ func doCopySession(cli *cli.Context, session *sessionV8, encKeyDB map[string][]p
|
|||||||
cpURLs.TargetContent.Metadata["X-Amz-Storage-Class"] = storageClass
|
cpURLs.TargetContent.Metadata["X-Amz-Storage-Class"] = storageClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update Object retention related fields
|
||||||
|
if session != nil {
|
||||||
|
cpURLs.TargetContent.RetentionMode = session.Header.CommandStringFlags[rmFlag]
|
||||||
|
cpURLs.TargetContent.RetentionDuration = session.Header.CommandStringFlags[rdFlag]
|
||||||
|
cpURLs.TargetContent.LegalHold = session.Header.CommandStringFlags[lhFlag]
|
||||||
|
} else {
|
||||||
|
if rm := cli.String(rmFlag); rm != "" {
|
||||||
|
cpURLs.TargetContent.RetentionMode = rm
|
||||||
|
}
|
||||||
|
if rd := cli.String(rdFlag); rd != "" {
|
||||||
|
cpURLs.TargetContent.RetentionDuration = rd
|
||||||
|
}
|
||||||
|
if lh := cli.String(lhFlag); lh != "" {
|
||||||
|
cpURLs.TargetContent.LegalHold = lh
|
||||||
|
}
|
||||||
|
}
|
||||||
if cli.String("attr") != "" {
|
if cli.String("attr") != "" {
|
||||||
userMetaMap, _ := getMetaDataEntry(cli.String("attr"))
|
userMetaMap, _ := getMetaDataEntry(cli.String("attr"))
|
||||||
for metaDataKey, metaDataVal := range userMetaMap {
|
for metaDataKey, metaDataVal := range userMetaMap {
|
||||||
@@ -565,13 +600,16 @@ func mainCopy(ctx *cli.Context) error {
|
|||||||
// check 'copy' cli arguments.
|
// check 'copy' cli arguments.
|
||||||
checkCopySyntax(ctx, encKeyDB)
|
checkCopySyntax(ctx, encKeyDB)
|
||||||
|
|
||||||
// Additional command speific theme customization.
|
// Additional command specific theme customization.
|
||||||
console.SetColor("Copy", color.New(color.FgGreen, color.Bold))
|
console.SetColor("Copy", color.New(color.FgGreen, color.Bold))
|
||||||
|
|
||||||
recursive := ctx.Bool("recursive")
|
recursive := ctx.Bool("recursive")
|
||||||
olderThan := ctx.String("older-than")
|
olderThan := ctx.String("older-than")
|
||||||
newerThan := ctx.String("newer-than")
|
newerThan := ctx.String("newer-than")
|
||||||
storageClass := ctx.String("storage-class")
|
storageClass := ctx.String("storage-class")
|
||||||
|
retentionMode := ctx.String(rmFlag)
|
||||||
|
retentionDuration := ctx.String(rdFlag)
|
||||||
|
legalHold := ctx.String(lhFlag)
|
||||||
sseKeys := os.Getenv("MC_ENCRYPT_KEY")
|
sseKeys := os.Getenv("MC_ENCRYPT_KEY")
|
||||||
if key := ctx.String("encrypt-key"); key != "" {
|
if key := ctx.String("encrypt-key"); key != "" {
|
||||||
sseKeys = key
|
sseKeys = key
|
||||||
@@ -597,6 +635,9 @@ func mainCopy(ctx *cli.Context) error {
|
|||||||
session.Header.CommandStringFlags["older-than"] = olderThan
|
session.Header.CommandStringFlags["older-than"] = olderThan
|
||||||
session.Header.CommandStringFlags["newer-than"] = newerThan
|
session.Header.CommandStringFlags["newer-than"] = newerThan
|
||||||
session.Header.CommandStringFlags["storage-class"] = storageClass
|
session.Header.CommandStringFlags["storage-class"] = storageClass
|
||||||
|
session.Header.CommandStringFlags[rmFlag] = retentionMode
|
||||||
|
session.Header.CommandStringFlags[rdFlag] = retentionDuration
|
||||||
|
session.Header.CommandStringFlags[lhFlag] = legalHold
|
||||||
session.Header.CommandStringFlags["encrypt-key"] = sseKeys
|
session.Header.CommandStringFlags["encrypt-key"] = sseKeys
|
||||||
session.Header.CommandStringFlags["encrypt"] = sse
|
session.Header.CommandStringFlags["encrypt"] = sse
|
||||||
session.Header.CommandBoolFlags["session"] = ctx.Bool("continue")
|
session.Header.CommandBoolFlags["session"] = ctx.Bool("continue")
|
||||||
|
|||||||
@@ -55,6 +55,14 @@ func checkCopySyntax(ctx *cli.Context, encKeyDB map[string][]prefixSSEPair) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctx.String(rdFlag) != "" && ctx.String(rmFlag) == "" {
|
||||||
|
fatalIf(errInvalidArgument().Trace(), fmt.Sprintf("Both object retention flags `--%s` and `--%s` are required.\n", rdFlag, rmFlag))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.String(rdFlag) == "" && ctx.String(rmFlag) != "" {
|
||||||
|
fatalIf(errInvalidArgument().Trace(), fmt.Sprintf("Both object retention flags `--%s` and `--%s` are required.\n", rdFlag, rmFlag))
|
||||||
|
}
|
||||||
|
|
||||||
// Guess CopyURLsType based on source and target URLs.
|
// Guess CopyURLsType based on source and target URLs.
|
||||||
copyURLsType, err := guessCopyURLType(srcURLs, tgtURL, isRecursive, encKeyDB)
|
copyURLsType, err := guessCopyURLType(srcURLs, tgtURL, isRecursive, encKeyDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -136,6 +136,35 @@ func lock(urlStr string, mode *minio.RetentionMode, validity *uint, unit *minio.
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseRetentionValidity(validityStr string, m minio.RetentionMode) (*uint, *minio.ValidityUnit) {
|
||||||
|
if !m.IsValid() {
|
||||||
|
fatalIf(probe.NewError(errors.New("invalid argument")), "invalid retention mode '%v'", m)
|
||||||
|
}
|
||||||
|
|
||||||
|
unitStr := string(validityStr[len(validityStr)-1])
|
||||||
|
validityStr = validityStr[:len(validityStr)-1]
|
||||||
|
ui64, err := strconv.ParseUint(validityStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
fatalIf(probe.NewError(errors.New("invalid argument")), "invalid validity '%v'", validityStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
u := uint(ui64)
|
||||||
|
validity := &u
|
||||||
|
var unit *minio.ValidityUnit
|
||||||
|
switch unitStr {
|
||||||
|
case "d", "D":
|
||||||
|
d := minio.Days
|
||||||
|
unit = &d
|
||||||
|
case "y", "Y":
|
||||||
|
y := minio.Years
|
||||||
|
unit = &y
|
||||||
|
default:
|
||||||
|
fatalIf(probe.NewError(errors.New("invalid argument")), "invalid validity format '%v'", unitStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return validity, unit
|
||||||
|
}
|
||||||
|
|
||||||
// main for lock command.
|
// main for lock command.
|
||||||
func mainLock(ctx *cli.Context) error {
|
func mainLock(ctx *cli.Context) error {
|
||||||
console.SetColor("Mode", color.New(color.FgCyan, color.Bold))
|
console.SetColor("Mode", color.New(color.FgCyan, color.Bold))
|
||||||
@@ -162,33 +191,9 @@ func mainLock(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m := minio.RetentionMode(strings.ToUpper(args[1]))
|
m := minio.RetentionMode(strings.ToUpper(args[1]))
|
||||||
if !m.IsValid() {
|
|
||||||
fatalIf(probe.NewError(errors.New("invalid argument")), "invalid retention mode '%v'", m)
|
|
||||||
}
|
|
||||||
|
|
||||||
mode = &m
|
mode = &m
|
||||||
|
validity, unit = parseRetentionValidity(args[2], m)
|
||||||
|
|
||||||
validityStr := args[2]
|
|
||||||
unitStr := string(validityStr[len(validityStr)-1])
|
|
||||||
|
|
||||||
validityStr = validityStr[:len(validityStr)-1]
|
|
||||||
ui64, err := strconv.ParseUint(validityStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
fatalIf(probe.NewError(errors.New("invalid argument")), "invalid validity '%v'", args[2])
|
|
||||||
}
|
|
||||||
u := uint(ui64)
|
|
||||||
validity = &u
|
|
||||||
|
|
||||||
switch unitStr {
|
|
||||||
case "d", "D":
|
|
||||||
d := minio.Days
|
|
||||||
unit = &d
|
|
||||||
case "y", "Y":
|
|
||||||
y := minio.Years
|
|
||||||
unit = &y
|
|
||||||
default:
|
|
||||||
fatalIf(probe.NewError(errors.New("invalid argument")), "invalid validity format '%v'", args[2])
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
cli.ShowCommandHelpAndExit(ctx, "lock", 1)
|
cli.ShowCommandHelpAndExit(ctx, "lock", 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ func (mj *mirrorJob) doRemove(sURLs URLs) URLs {
|
|||||||
contentCh <- &ClientContent{URL: *newClientURL(sURLs.TargetContent.URL.Path)}
|
contentCh <- &ClientContent{URL: *newClientURL(sURLs.TargetContent.URL.Path)}
|
||||||
close(contentCh)
|
close(contentCh)
|
||||||
isRemoveBucket := false
|
isRemoveBucket := false
|
||||||
errorCh := clnt.Remove(false, isRemoveBucket, contentCh)
|
errorCh := clnt.Remove(false, isRemoveBucket, false, contentCh)
|
||||||
for pErr := range errorCh {
|
for pErr := range errorCh {
|
||||||
if pErr != nil {
|
if pErr != nil {
|
||||||
switch pErr.ToGoError().(type) {
|
switch pErr.ToGoError().(type) {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func deleteBucket(url string) *probe.Error {
|
|||||||
var isIncomplete bool
|
var isIncomplete bool
|
||||||
isRemoveBucket := true
|
isRemoveBucket := true
|
||||||
contentCh := make(chan *ClientContent)
|
contentCh := make(chan *ClientContent)
|
||||||
errorCh := clnt.Remove(isIncomplete, isRemoveBucket, contentCh)
|
errorCh := clnt.Remove(isIncomplete, isRemoveBucket, false, contentCh)
|
||||||
|
|
||||||
for content := range clnt.List(true, false, false, DirLast) {
|
for content := range clnt.List(true, false, false, DirLast) {
|
||||||
if content.Err != nil {
|
if content.Err != nil {
|
||||||
|
|||||||
@@ -38,11 +38,14 @@ var (
|
|||||||
Usage: "apply retention recursively",
|
Usage: "apply retention recursively",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "bypass",
|
Name: bypass,
|
||||||
Usage: "bypass governance",
|
Usage: "bypass governance",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var bypass = "bypass"
|
||||||
|
|
||||||
var retentionCmd = cli.Command{
|
var retentionCmd = cli.Command{
|
||||||
Name: "retention",
|
Name: "retention",
|
||||||
Usage: "set object retention for objects with a given prefix",
|
Usage: "set object retention for objects with a given prefix",
|
||||||
@@ -95,6 +98,21 @@ func (m retentionCmdMessage) JSON() string {
|
|||||||
return string(msgBytes)
|
return string(msgBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRetainUntilDate(validity *uint, unit *minio.ValidityUnit) (string, error) {
|
||||||
|
if validity == nil {
|
||||||
|
return "", fmt.Errorf("invalid validity '%v'", validity)
|
||||||
|
}
|
||||||
|
t := UTCNow()
|
||||||
|
if *unit == minio.Years {
|
||||||
|
t = t.AddDate(int(*validity), 0, 0)
|
||||||
|
} else {
|
||||||
|
t = t.AddDate(0, 0, int(*validity))
|
||||||
|
}
|
||||||
|
timeStr := t.Format(time.RFC3339)
|
||||||
|
|
||||||
|
return timeStr, nil
|
||||||
|
}
|
||||||
|
|
||||||
// setRetention - Set Retention for all objects within a given prefix.
|
// setRetention - Set Retention for all objects within a given prefix.
|
||||||
func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, bypassGovernance, isRecursive bool) error {
|
func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, bypassGovernance, isRecursive bool) error {
|
||||||
clnt, err := newClient(urlStr)
|
clnt, err := newClient(urlStr)
|
||||||
@@ -110,26 +128,6 @@ func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit
|
|||||||
|
|
||||||
alias, _, _ := mustExpandAlias(urlStr)
|
alias, _, _ := mustExpandAlias(urlStr)
|
||||||
|
|
||||||
retainUntilDate := func() (time.Time, error) {
|
|
||||||
if validity == nil {
|
|
||||||
return timeSentinel, fmt.Errorf("invalid validity '%v'", validity)
|
|
||||||
}
|
|
||||||
t := UTCNow()
|
|
||||||
if *unit == minio.Years {
|
|
||||||
t = t.AddDate(int(*validity), 0, 0)
|
|
||||||
} else {
|
|
||||||
t = t.AddDate(0, 0, int(*validity))
|
|
||||||
}
|
|
||||||
timeStr := t.Format(time.RFC3339)
|
|
||||||
|
|
||||||
t1, e := time.Parse(
|
|
||||||
time.RFC3339,
|
|
||||||
timeStr)
|
|
||||||
if e != nil {
|
|
||||||
return timeSentinel, e
|
|
||||||
}
|
|
||||||
return t1, nil
|
|
||||||
}
|
|
||||||
validityStr := func() *string {
|
validityStr := func() *string {
|
||||||
if validity == nil {
|
if validity == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -151,11 +149,17 @@ func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit
|
|||||||
cErr = exitStatus(globalErrorExitStatus) // Set the exit status.
|
cErr = exitStatus(globalErrorExitStatus) // Set the exit status.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
retainUntil, err := retainUntilDate()
|
timeStr, err := getRetainUntilDate(validity, unit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid retention date")
|
errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid retention date")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
retainUntil, e := time.Parse(time.RFC3339, timeStr)
|
||||||
|
if e != nil {
|
||||||
|
errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid retention date")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
newClnt, perr := newClientFromAlias(alias, content.URL.String())
|
newClnt, perr := newClientFromAlias(alias, content.URL.String())
|
||||||
if perr != nil {
|
if perr != nil {
|
||||||
errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid URL")
|
errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid URL")
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ var (
|
|||||||
Name: "newer-than",
|
Name: "newer-than",
|
||||||
Usage: "remove objects newer than L days, M hours and N minutes",
|
Usage: "remove objects newer than L days, M hours and N minutes",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: bypass,
|
||||||
|
Usage: "bypass governance",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -117,6 +121,9 @@ EXAMPLES:
|
|||||||
|
|
||||||
10. Remove an encrypted object from Amazon S3 cloud storage.
|
10. Remove an encrypted object from Amazon S3 cloud storage.
|
||||||
{{.Prompt}} {{.HelpName}} --encrypt-key "s3/sql-backups/=32byteslongsecretkeymustbegiven1" s3/sql-backups/1999/old-backup.tgz
|
{{.Prompt}} {{.HelpName}} --encrypt-key "s3/sql-backups/=32byteslongsecretkeymustbegiven1" s3/sql-backups/1999/old-backup.tgz
|
||||||
|
|
||||||
|
11. Bypass object retention in governance mode and delete the object.
|
||||||
|
{{.Prompt}} {{.HelpName}} --bypass s3/pop-songs/
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +187,7 @@ func checkRmSyntax(ctx *cli.Context, encKeyDB map[string][]prefixSSEPair) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeSingle(url string, isIncomplete bool, isFake, isForce bool, olderThan, newerThan string, encKeyDB map[string][]prefixSSEPair) error {
|
func removeSingle(url string, isIncomplete, isFake, isForce, isBypass bool, olderThan, newerThan string, encKeyDB map[string][]prefixSSEPair) error {
|
||||||
isRecursive := false
|
isRecursive := false
|
||||||
contents, pErr := statURL(url, isIncomplete, isRecursive, encKeyDB)
|
contents, pErr := statURL(url, isIncomplete, isRecursive, encKeyDB)
|
||||||
if pErr != nil {
|
if pErr != nil {
|
||||||
@@ -227,7 +234,7 @@ func removeSingle(url string, isIncomplete bool, isFake, isForce bool, olderThan
|
|||||||
contentCh <- &ClientContent{URL: *newClientURL(targetURL)}
|
contentCh <- &ClientContent{URL: *newClientURL(targetURL)}
|
||||||
close(contentCh)
|
close(contentCh)
|
||||||
isRemoveBucket := false
|
isRemoveBucket := false
|
||||||
errorCh := clnt.Remove(isIncomplete, isRemoveBucket, contentCh)
|
errorCh := clnt.Remove(isIncomplete, isRemoveBucket, isBypass, contentCh)
|
||||||
for pErr := range errorCh {
|
for pErr := range errorCh {
|
||||||
if pErr != nil {
|
if pErr != nil {
|
||||||
errorIf(pErr.Trace(url), "Failed to remove `"+url+"`.")
|
errorIf(pErr.Trace(url), "Failed to remove `"+url+"`.")
|
||||||
@@ -243,7 +250,7 @@ func removeSingle(url string, isIncomplete bool, isFake, isForce bool, olderThan
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeRecursive(url string, isIncomplete bool, isFake bool, olderThan, newerThan string, encKeyDB map[string][]prefixSSEPair) error {
|
func removeRecursive(url string, isIncomplete, isFake, isBypass bool, olderThan, newerThan string, encKeyDB map[string][]prefixSSEPair) error {
|
||||||
targetAlias, targetURL, _ := mustExpandAlias(url)
|
targetAlias, targetURL, _ := mustExpandAlias(url)
|
||||||
clnt, pErr := newClientFromAlias(targetAlias, targetURL)
|
clnt, pErr := newClientFromAlias(targetAlias, targetURL)
|
||||||
if pErr != nil {
|
if pErr != nil {
|
||||||
@@ -253,7 +260,7 @@ func removeRecursive(url string, isIncomplete bool, isFake bool, olderThan, newe
|
|||||||
contentCh := make(chan *ClientContent)
|
contentCh := make(chan *ClientContent)
|
||||||
isRemoveBucket := false
|
isRemoveBucket := false
|
||||||
|
|
||||||
errorCh := clnt.Remove(isIncomplete, isRemoveBucket, contentCh)
|
errorCh := clnt.Remove(isIncomplete, isRemoveBucket, isBypass, contentCh)
|
||||||
|
|
||||||
isRecursive := true
|
isRecursive := true
|
||||||
for content := range clnt.List(isRecursive, isIncomplete, false, DirNone) {
|
for content := range clnt.List(isRecursive, isIncomplete, false, DirNone) {
|
||||||
@@ -337,6 +344,7 @@ func mainRm(ctx *cli.Context) error {
|
|||||||
isRecursive := ctx.Bool("recursive")
|
isRecursive := ctx.Bool("recursive")
|
||||||
isFake := ctx.Bool("fake")
|
isFake := ctx.Bool("fake")
|
||||||
isStdin := ctx.Bool("stdin")
|
isStdin := ctx.Bool("stdin")
|
||||||
|
isBypass := ctx.Bool(bypass)
|
||||||
olderThan := ctx.String("older-than")
|
olderThan := ctx.String("older-than")
|
||||||
newerThan := ctx.String("newer-than")
|
newerThan := ctx.String("newer-than")
|
||||||
isForce := ctx.Bool("force")
|
isForce := ctx.Bool("force")
|
||||||
@@ -349,9 +357,9 @@ func mainRm(ctx *cli.Context) error {
|
|||||||
// Support multiple targets.
|
// Support multiple targets.
|
||||||
for _, url := range ctx.Args() {
|
for _, url := range ctx.Args() {
|
||||||
if isRecursive {
|
if isRecursive {
|
||||||
e = removeRecursive(url, isIncomplete, isFake, olderThan, newerThan, encKeyDB)
|
e = removeRecursive(url, isIncomplete, isFake, isBypass, olderThan, newerThan, encKeyDB)
|
||||||
} else {
|
} else {
|
||||||
e = removeSingle(url, isIncomplete, isFake, isForce, olderThan, newerThan, encKeyDB)
|
e = removeSingle(url, isIncomplete, isFake, isForce, isBypass, olderThan, newerThan, encKeyDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rerr == nil {
|
if rerr == nil {
|
||||||
@@ -367,9 +375,9 @@ func mainRm(ctx *cli.Context) error {
|
|||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
url := scanner.Text()
|
url := scanner.Text()
|
||||||
if isRecursive {
|
if isRecursive {
|
||||||
e = removeRecursive(url, isIncomplete, isFake, olderThan, newerThan, encKeyDB)
|
e = removeRecursive(url, isIncomplete, isFake, isBypass, olderThan, newerThan, encKeyDB)
|
||||||
} else {
|
} else {
|
||||||
e = removeSingle(url, isIncomplete, isFake, isForce, olderThan, newerThan, encKeyDB)
|
e = removeSingle(url, isIncomplete, isFake, isForce, isBypass, olderThan, newerThan, encKeyDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rerr == nil {
|
if rerr == nil {
|
||||||
|
|||||||
6
go.mod
6
go.mod
@@ -16,8 +16,8 @@ require (
|
|||||||
github.com/mattn/go-isatty v0.0.8
|
github.com/mattn/go-isatty v0.0.8
|
||||||
github.com/mattn/go-runewidth v0.0.5 // indirect
|
github.com/mattn/go-runewidth v0.0.5 // indirect
|
||||||
github.com/minio/cli v1.22.0
|
github.com/minio/cli v1.22.0
|
||||||
github.com/minio/minio v0.0.0-20200404010650-2155e74951bf
|
github.com/minio/minio v0.0.0-20200327214830-6f992134a25f
|
||||||
github.com/minio/minio-go/v6 v6.0.52
|
github.com/minio/minio-go/v6 v6.0.52-0.20200403112139-73469ba42c49
|
||||||
github.com/minio/sha256-simd v0.1.1
|
github.com/minio/sha256-simd v0.1.1
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/pkg/profile v1.3.0
|
github.com/pkg/profile v1.3.0
|
||||||
@@ -31,6 +31,6 @@ require (
|
|||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
|
||||||
gopkg.in/h2non/filetype.v1 v1.0.5
|
gopkg.in/h2non/filetype.v1 v1.0.5
|
||||||
gopkg.in/ini.v1 v1.52.0 // indirect
|
gopkg.in/ini.v1 v1.55.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.4
|
gopkg.in/yaml.v2 v2.2.4
|
||||||
)
|
)
|
||||||
|
|||||||
23
go.sum
23
go.sum
@@ -220,8 +220,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7 h1:smZXPopqRVVywwzou4WYWvUbJvSAzIDFizfWElpmAqY=
|
github.com/kurin/blazer v0.5.4-0.20190613185654-cf2f27cc0be3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
||||||
github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
|
||||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5 h1:0x4qcEHDpruK6ML/m/YSlFUUu0UpRD3I2PHsNCuGnyA=
|
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5 h1:0x4qcEHDpruK6ML/m/YSlFUUu0UpRD3I2PHsNCuGnyA=
|
||||||
@@ -255,12 +254,13 @@ github.com/minio/highwayhash v1.0.0 h1:iMSDhgUILCr0TNm8LWlSjF8N0ZIj2qbO8WHp6Q/J2
|
|||||||
github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc=
|
github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc=
|
||||||
github.com/minio/lsync v1.0.1 h1:AVvILxA976xc27hstd1oR+X9PQG0sPSom1MNb1ImfUs=
|
github.com/minio/lsync v1.0.1 h1:AVvILxA976xc27hstd1oR+X9PQG0sPSom1MNb1ImfUs=
|
||||||
github.com/minio/lsync v1.0.1/go.mod h1:tCFzfo0dlvdGl70IT4IAK/5Wtgb0/BrTmo/jE8pArKA=
|
github.com/minio/lsync v1.0.1/go.mod h1:tCFzfo0dlvdGl70IT4IAK/5Wtgb0/BrTmo/jE8pArKA=
|
||||||
github.com/minio/minio v0.0.0-20200404010650-2155e74951bf h1:pyWpAtXni2XVeObXm5clbHw5m8YWVOEQNSMcZXTjf94=
|
github.com/minio/minio v0.0.0-20200327214830-6f992134a25f h1:RoOBi0vhXkZqe2b6RTROOsVJUwMqLMoet9r7eL01euo=
|
||||||
github.com/minio/minio v0.0.0-20200404010650-2155e74951bf/go.mod h1:7HGxQRqSt4Jfb86tZUQ+ZOWHDLswFu5uB+q2mjFW3O8=
|
github.com/minio/minio v0.0.0-20200327214830-6f992134a25f/go.mod h1:BzbIyKUJPp+4f03i2XF7+GsijXnxMakUe5x+lm2WNc8=
|
||||||
github.com/minio/minio-go/v6 v6.0.45/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
github.com/minio/minio-go/v6 v6.0.45/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||||
github.com/minio/minio-go/v6 v6.0.52 h1:sS8NjhahYzX71nuUvO14PBpdNUTjeaNvjySmVnozGmw=
|
github.com/minio/minio-go/v6 v6.0.51-0.20200319192131-097caa7760c7 h1:WQmYVUDRGdcEWhJeb42/Fn1IO7SBLem173DTE4+jp/E=
|
||||||
github.com/minio/minio-go/v6 v6.0.52/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI=
|
github.com/minio/minio-go/v6 v6.0.51-0.20200319192131-097caa7760c7/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||||
github.com/minio/parquet-go v0.0.0-20200125064549-a1e49702e174 h1:WYFHZIJ5LTWd4C3CW26jguaBLLDdX7l1/Xa3QSKGkIc=
|
github.com/minio/minio-go/v6 v6.0.52-0.20200403112139-73469ba42c49 h1:eOc5mvyNftWN13g0ubArdVjWisj20TPGh6lSpb55xvk=
|
||||||
|
github.com/minio/minio-go/v6 v6.0.52-0.20200403112139-73469ba42c49/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI=
|
||||||
github.com/minio/parquet-go v0.0.0-20200125064549-a1e49702e174/go.mod h1:PXYM9yI2l0YPmxHUXe6mFTmkQcyaVasDshAPTbGpDoo=
|
github.com/minio/parquet-go v0.0.0-20200125064549-a1e49702e174/go.mod h1:PXYM9yI2l0YPmxHUXe6mFTmkQcyaVasDshAPTbGpDoo=
|
||||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||||
@@ -365,10 +365,10 @@ github.com/secure-io/sio-go v0.3.0/go.mod h1:D3KmXgKETffyYxBdFRN+Hpd2WzhzqS0EQwT
|
|||||||
github.com/shirou/gopsutil v2.20.3-0.20200314133625-53cec6b37e6a+incompatible h1:YiKUe2ZOmfpDBH4OSyxwkx/mjNqHHnNhOtZ2mPyRme8=
|
github.com/shirou/gopsutil v2.20.3-0.20200314133625-53cec6b37e6a+incompatible h1:YiKUe2ZOmfpDBH4OSyxwkx/mjNqHHnNhOtZ2mPyRme8=
|
||||||
github.com/shirou/gopsutil v2.20.3-0.20200314133625-53cec6b37e6a+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
github.com/shirou/gopsutil v2.20.3-0.20200314133625-53cec6b37e6a+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
|
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
|
||||||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||||
github.com/skyrings/skyring-common v0.0.0-20160929130248-d1c0bb1cbd5e h1:jrZSSgPUDtBeJbGXqgGUeupQH8I+ZvGXfhpIahye2Bc=
|
|
||||||
github.com/skyrings/skyring-common v0.0.0-20160929130248-d1c0bb1cbd5e/go.mod h1:d8hQseuYt4rJoOo21lFzYJdhMjmDqLY++ayArbgYjWI=
|
github.com/skyrings/skyring-common v0.0.0-20160929130248-d1c0bb1cbd5e/go.mod h1:d8hQseuYt4rJoOo21lFzYJdhMjmDqLY++ayArbgYjWI=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0=
|
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0=
|
||||||
@@ -453,6 +453,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@@ -480,6 +481,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200320181252-af34d8274f85/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -532,9 +534,8 @@ gopkg.in/h2non/filetype.v1 v1.0.5 h1:CC1jjJjoEhNVbMhXYalmGBhOBK2V70Q1N850wt/98/Y
|
|||||||
gopkg.in/h2non/filetype.v1 v1.0.5/go.mod h1:M0yem4rwSX5lLVrkEuRRp2/NinFMD5vgJ4DlAhZcfNo=
|
gopkg.in/h2non/filetype.v1 v1.0.5/go.mod h1:M0yem4rwSX5lLVrkEuRRp2/NinFMD5vgJ4DlAhZcfNo=
|
||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=
|
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||||
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=
|
|
||||||
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
|
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
|
||||||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM=
|
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM=
|
||||||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
|
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
|
||||||
|
|||||||
Reference in New Issue
Block a user