github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/retention-set.go (about) 1 // Copyright (c) 2015-2022 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "context" 22 "strings" 23 "time" 24 25 "github.com/fatih/color" 26 "github.com/minio/cli" 27 "github.com/minio/mc/pkg/probe" 28 minio "github.com/minio/minio-go/v7" 29 "github.com/minio/pkg/v2/console" 30 ) 31 32 var retentionSetFlags = []cli.Flag{ 33 cli.BoolFlag{ 34 Name: "recursive, r", 35 Usage: "apply retention recursively", 36 }, 37 cli.BoolFlag{ 38 Name: "bypass", 39 Usage: "bypass governance", 40 }, 41 cli.StringFlag{ 42 Name: "version-id, vid", 43 Usage: "apply retention to a specific object version", 44 }, 45 cli.StringFlag{ 46 Name: "rewind", 47 Usage: "roll back object(s) to current version at specified time", 48 }, 49 cli.BoolFlag{ 50 Name: "versions", 51 Usage: "apply retention object(s) and all its versions", 52 }, 53 cli.BoolFlag{ 54 Name: "default", 55 Usage: "set bucket default retention mode", 56 }, 57 } 58 59 var retentionSetCmd = cli.Command{ 60 Name: "set", 61 Usage: "apply retention settings on object(s)", 62 Action: mainRetentionSet, 63 OnUsageError: onUsageError, 64 Before: setGlobalsFromContext, 65 Flags: append(retentionSetFlags, globalFlags...), 66 CustomHelpTemplate: `NAME: 67 {{.HelpName}} - {{.Usage}} 68 69 USAGE: 70 {{.HelpName}} [FLAGS] [governance | compliance] VALIDITY TARGET 71 72 FLAGS: 73 {{range .VisibleFlags}}{{.}} 74 {{end}} 75 VALIDITY: 76 This argument must be formatted like Nd or Ny where 'd' denotes days and 'y' denotes years e.g. 10d, 3y. 77 78 EXAMPLES: 79 1. Set object retention for a specific object 80 $ {{.HelpName}} compliance 30d myminio/mybucket/prefix/obj.csv 81 82 2. Set object retention for recursively for all objects at a given prefix 83 $ {{.HelpName}} governance 30d myminio/mybucket/prefix --recursive 84 85 3. Set object retention to a specific version of a specific object 86 $ {{.HelpName}} governance 30d myminio/mybucket/prefix/obj.csv --version-id "3Jr2x6fqlBUsVzbvPihBO3HgNpgZgAnp" 87 88 4. Set object retention for recursively for all versions of all objects 89 $ {{.HelpName}} governance 30d myminio/mybucket/prefix --recursive --versions 90 91 5. Set default lock retention configuration for a bucket 92 $ {{.HelpName}} --default governance 30d myminio/mybucket/ 93 `, 94 } 95 96 func parseSetRetentionArgs(cliCtx *cli.Context) (target, versionID string, recursive bool, timeRef time.Time, withVersions bool, mode minio.RetentionMode, validity uint64, unit minio.ValidityUnit, bypass, bucketMode bool) { 97 args := cliCtx.Args() 98 if len(args) != 3 { 99 showCommandHelpAndExit(cliCtx, 1) 100 } 101 102 mode = minio.RetentionMode(strings.ToUpper(args[0])) 103 if !mode.IsValid() { 104 fatalIf(errInvalidArgument().Trace(args...), "invalid retention mode '%v'", mode) 105 } 106 107 var err *probe.Error 108 validity, unit, err = parseRetentionValidity(args[1]) 109 fatalIf(err.Trace(args[1]), "invalid validity argument") 110 111 target = args[2] 112 if target == "" { 113 fatalIf(errInvalidArgument().Trace(), "invalid target url '%v'", target) 114 } 115 116 versionID = cliCtx.String("version-id") 117 timeRef = parseRewindFlag(cliCtx.String("rewind")) 118 withVersions = cliCtx.Bool("versions") 119 recursive = cliCtx.Bool("recursive") 120 bypass = cliCtx.Bool("bypass") 121 bucketMode = cliCtx.Bool("default") 122 123 if bucketMode && (versionID != "" || !timeRef.IsZero() || withVersions || recursive || bypass) { 124 fatalIf(errDummy(), "--default cannot be specified with any of --version-id, --rewind, --versions, --recursive, --bypass.") 125 } 126 127 return 128 } 129 130 // Set Retention for one object/version or many objects within a given prefix. 131 func setRetention(ctx context.Context, target, versionID string, timeRef time.Time, withOlderVersions, isRecursive bool, 132 mode minio.RetentionMode, validity uint64, unit minio.ValidityUnit, bypassGovernance bool, 133 ) error { 134 return applyRetention(ctx, lockOpSet, target, versionID, timeRef, withOlderVersions, isRecursive, mode, validity, unit, bypassGovernance) 135 } 136 137 func setBucketLock(urlStr string, mode minio.RetentionMode, validity uint64, unit minio.ValidityUnit) error { 138 return applyBucketLock(lockOpSet, urlStr, mode, validity, unit) 139 } 140 141 // main for retention set command. 142 func mainRetentionSet(cliCtx *cli.Context) error { 143 ctx, cancelSetRetention := context.WithCancel(globalContext) 144 defer cancelSetRetention() 145 146 console.SetColor("RetentionSuccess", color.New(color.FgGreen, color.Bold)) 147 console.SetColor("RetentionFailure", color.New(color.FgYellow)) 148 149 target, versionID, recursive, rewind, withVersions, mode, validity, unit, bypass, bucketMode := parseSetRetentionArgs(cliCtx) 150 151 fatalIfBucketLockNotSupported(ctx, target) 152 153 if bucketMode { 154 return setBucketLock(target, mode, validity, unit) 155 } 156 157 if withVersions && rewind.IsZero() { 158 rewind = time.Now().UTC() 159 } 160 161 return setRetention(ctx, target, versionID, rewind, withVersions, recursive, mode, validity, unit, bypass) 162 }