Skip to content

mc retention: add --recursive and --bypass flags. #3100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/client-fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ func (f *fsClient) GetAccessRules() (map[string]string, *probe.Error) {
}

// Set object retention for a given object.
func (f *fsClient) PutObjectRetention(mode *minio.RetentionMode, retainUntilDate *time.Time) *probe.Error {
func (f *fsClient) PutObjectRetention(mode *minio.RetentionMode, retainUntilDate *time.Time, bypassGovernance bool) *probe.Error {
return probe.NewError(APINotImplemented{
API: "PutObjectRetention",
APIType: "filesystem",
Expand Down
7 changes: 4 additions & 3 deletions cmd/client-s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -2074,12 +2074,13 @@ func (c *s3Client) SetObjectLockConfig(mode *minio.RetentionMode, validity *uint
}

// Set object retention for a given object.
func (c *s3Client) PutObjectRetention(mode *minio.RetentionMode, retainUntilDate *time.Time) *probe.Error {
func (c *s3Client) PutObjectRetention(mode *minio.RetentionMode, retainUntilDate *time.Time, bypassGovernance bool) *probe.Error {
bucket, object := c.url2BucketAndObject()

opts := minio.PutObjectRetentionOptions{
RetainUntilDate: retainUntilDate,
Mode: mode,
RetainUntilDate: retainUntilDate,
Mode: mode,
GovernanceBypass: bypassGovernance,
}
err := c.api.PutObjectRetention(bucket, object, opts)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ type Client interface {
Get(sse encrypt.ServerSide) (reader io.ReadCloser, err *probe.Error)
Put(ctx context.Context, reader io.Reader, size int64, metadata map[string]string, progress io.Reader, sse encrypt.ServerSide) (n int64, err *probe.Error)
// Object Locking related API
PutObjectRetention(mode *minio.RetentionMode, retainUntilDate *time.Time) *probe.Error
PutObjectRetention(mode *minio.RetentionMode, retainUntilDate *time.Time, bypassGovernance bool) *probe.Error

// I/O operations with expiration
ShareDownload(expires time.Duration) (string, *probe.Error)
Expand Down
2 changes: 1 addition & 1 deletion cmd/common-methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func putTargetRetention(ctx context.Context, alias string, urlStr string, metada
retainUntilDate = t.UTC()
}
}
if err := targetClnt.PutObjectRetention(&lockMode, &retainUntilDate); err != nil {
if err := targetClnt.PutObjectRetention(&lockMode, &retainUntilDate, false); err != nil {
return err.Trace(alias, urlStr)
}
return nil
Expand Down
35 changes: 26 additions & 9 deletions cmd/retention-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,24 @@ import (
"github.com/minio/minio/pkg/console"
)

var (
rFlags = []cli.Flag{
cli.BoolFlag{
Name: "recursive, r",
Usage: "apply retention recursively",
},
cli.BoolFlag{
Name: "bypass",
Usage: "bypass governance",
},
}
)
var retentionCmd = cli.Command{
Name: "retention",
Usage: "set object retention for objects with a given prefix",
Action: mainRetention,
Before: setGlobalsFromContext,
Flags: globalFlags,
Flags: append(rFlags, globalFlags...),
CustomHelpTemplate: `NAME:
{{.HelpName}} - {{.Usage}}

Expand All @@ -50,9 +62,13 @@ VALIDITY:
This argument must be formatted like Nd or Ny where 'd' denotes days and 'y' denotes years e.g. 10d, 3y.

EXAMPLES:
1. Set object retention for objects in a given prefix
$ {{.HelpName}} myminio/mybucket/prefix compliance 30d
`,
1. Set object retention for a specific object
$ {{.HelpName}} myminio/mybucket/prefix/obj.csv compliance 30d

2. Set object retention for objects in a given prefix
$ {{.HelpName}} myminio/mybucket/prefix compliance 30d --recursive

`,
}

// Structured message depending on the type of console.
Expand Down Expand Up @@ -80,7 +96,7 @@ func (m retentionCmdMessage) JSON() string {
}

// setRetention - Set Retention for all objects within a given prefix.
func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit) error {
func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, bypassGovernance, isRecursive bool) error {
clnt, err := newClient(urlStr)
if err != nil {
fatalIf(err.Trace(), "Cannot parse the provided url.")
Expand All @@ -93,6 +109,7 @@ func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit
}

alias, _, _ := mustExpandAlias(urlStr)

retainUntilDate := func() (time.Time, error) {
if validity == nil {
return timeSentinel, fmt.Errorf("invalid validity '%v'", validity)
Expand Down Expand Up @@ -128,7 +145,7 @@ func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit

var cErr error
errorsFound := false
for content := range clnt.List(true, false, false, DirNone) {
for content := range clnt.List(isRecursive, false, false, DirNone) {
if content.Err != nil {
errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list folder.")
cErr = exitStatus(globalErrorExitStatus) // Set the exit status.
Expand All @@ -144,7 +161,7 @@ func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit
errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid URL")
continue
}
probeErr := newClnt.PutObjectRetention(mode, &retainUntil)
probeErr := newClnt.PutObjectRetention(mode, &retainUntil, bypassGovernance)
if probeErr != nil {
errorsFound = true
printMsg(retentionCmdMessage{
Expand All @@ -169,7 +186,7 @@ func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit
if errorsFound {
console.Print(console.Colorize("RetentionPartialFailure", fmt.Sprintf("Errors found while setting retention on objects with prefix `%s`.\n", urlStr)))
} else {
console.Print(console.Colorize("RetentionSuccess", fmt.Sprintf("Object retention successfully set for prefix `%s`.\n", urlStr)))
console.Print(console.Colorize("RetentionSuccess", fmt.Sprintf("Object retention successfully set for `%s`.\n", urlStr)))
}
}
return cErr
Expand Down Expand Up @@ -221,5 +238,5 @@ func mainRetention(ctx *cli.Context) error {
default:
cli.ShowCommandHelpAndExit(ctx, "retention", 1)
}
return setRetention(urlStr, mode, validity, unit)
return setRetention(urlStr, mode, validity, unit, ctx.Bool("bypass"), ctx.Bool("recursive"))
}
8 changes: 5 additions & 3 deletions docs/minio-client-complete-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -584,15 +584,17 @@ USAGE:
mc retention [FLAGS] TARGET [governance | compliance] [VALIDITY]

FLAGS:
--bypass bypass governance
--recursive, -r apply retention recursively
--json enable JSON formatted output
--help, -h show help
```

*Example: Set governance for 30 days for objects with prefix `prefix` on bucket `mybucket`*
*Example: Set governance for 30 days for object `prefix` on bucket `mybucket`*

```
mc retention myminio/mybucket/prefix governance 30d
Object retention successfully set for prefix `myminio/mybucket/prefix`.
mc retention myminio/mybucket/prefix governance 30d -r
Object retention successfully set for objects with prefix `myminio/mybucket/prefix`.

```
*Objects created with prefix `prefix` in the above bucket `mybucket` cannot be deleted until the compliance period is over*
Expand Down