add flag for lock mode

This commit is contained in:
nyanotech 2025-06-09 03:42:16 -07:00
parent 7444577cb7
commit 7296cb21ac
Signed by: nyanotech
GPG Key ID: 872740637E938731
2 changed files with 22 additions and 5 deletions

View File

@ -15,6 +15,7 @@ object-holder
--bucket <bucket name> --bucket <bucket name>
[--prefix <prefix>] [--prefix <prefix>]
[--update-expires-within <seconds>] [--update-expires-within <seconds>]
[--lock-mode <governance|compliance>]
--lock-for <seconds> --lock-for <seconds>
[--threads <thread count>] [--threads <thread count>]
``` ```
@ -23,10 +24,14 @@ If you're using name-brand S3, you don't need to specify endpoint, just the regi
The aws keys can be fed in via the cli flags, via the usual env variables (`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`), via instance metadata, etc. The aws keys can be fed in via the cli flags, via the usual env variables (`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`), via instance metadata, etc.
`--bucket`, obviously, specifies the bucket you'd like to renew object locks in, and `--prefix` can be used to limit operation to only the objects with a name starting with a given prefix in the bucket. `--bucket`, obviously, specifies the bucket you'd like to renew object locks in
`--lock-for` specifies how many seconds the newly-made locks should last, counting from time of program start. `--prefix` can be used to limit operation to only the objects with a name starting with a given prefix in the bucket.
`--update-expires-within-seconds` can be used to limit operation to only objects whose existing lock expires within that many seconds. This might save you a bit depending on your s3 provider's API request pricing. For example, in name-brand S3, it costs about 10x more to set a lock than it does to check it, so this flag might save you a bit there. Meanwhile, in Backblaze B2, setting an object hold is free but checking an existing hold costs money, so there's no reason to do the extra check. `--update-expires-within-seconds` can be used to limit operation to only objects whose existing lock expires within that many seconds. This might save you a bit depending on your s3 provider's API request pricing. For example, in name-brand S3, it costs about 10x more to set a lock than it does to check it, so this flag might save you a bit there. Meanwhile, in Backblaze B2, setting an object hold is free but checking an existing hold costs money, so there's no reason to do the extra check.
Lastly, `--threads` specifies how many concurrent threads we should have getting/setting object holds (default 1024). Some s3-compatible providers' APIs seem to misbehave when sequentially updating object metadata at high speeds like this script does, so here's a handy knob to adjust the speed in case you need it. `--lock-mode` specifies the type of object lock to apply: `governance` or `compliance` (default: compliance). Governance mode allows users with specific permissions to remove or modify the lock, while compliance mode prevents anyone from removing the lock until the retention period expires.
`--lock-for` specifies how many seconds the newly-made locks should last, counting from time of program start.
`--threads` specifies how many concurrent threads we should have getting/setting object holds (default 1024). Some s3-compatible providers' APIs seem to misbehave when sequentially updating object metadata at high speeds like this script does, so here's a handy knob to adjust the speed in case you need it.

16
main.go
View File

@ -28,20 +28,33 @@ var updateExpiresWithin = flag.Int("update-expires-within", 0, "only update obje
var lockFor = flag.Int("lock-for", 90*24*3600, "how many seconds to renew the object lock for (default 90 days)") var lockFor = flag.Int("lock-for", 90*24*3600, "how many seconds to renew the object lock for (default 90 days)")
var threadCount = flag.Int("threads", 1024, "how many objects to operate on at a time") var threadCount = flag.Int("threads", 1024, "how many objects to operate on at a time")
var lockMode = flag.String("lock-mode", "compliance", "object lock mode (governance or compliance)")
type objectLockOptions struct { type objectLockOptions struct {
CheckExistingHold bool CheckExistingHold bool
UpdateExpiry time.Time UpdateExpiry time.Time
LockExpiry time.Time LockExpiry time.Time
Mode types.ObjectLockRetentionMode
} }
func main() { func main() {
flag.Parse() flag.Parse()
var mode types.ObjectLockRetentionMode
switch strings.ToLower(*lockMode) {
case "governance":
mode = types.ObjectLockRetentionModeGovernance
case "compliance":
mode = types.ObjectLockRetentionModeCompliance
default:
log.Fatalln("Invalid lock mode. Must be 'governance' or 'compliance'")
}
objectLockArguments := objectLockOptions{ objectLockArguments := objectLockOptions{
CheckExistingHold: *updateExpiresWithin != 0, CheckExistingHold: *updateExpiresWithin != 0,
UpdateExpiry: time.Now().Add(time.Second * time.Duration(*updateExpiresWithin)), UpdateExpiry: time.Now().Add(time.Second * time.Duration(*updateExpiresWithin)),
LockExpiry: time.Now().Add(time.Second * time.Duration(*lockFor)), LockExpiry: time.Now().Add(time.Second * time.Duration(*lockFor)),
Mode: mode,
} }
options := []func(*config.LoadOptions) error{} options := []func(*config.LoadOptions) error{}
@ -134,8 +147,7 @@ func checkAndRenewObjectLock(svc *s3.Client, options objectLockOptions, object s
Bucket: bucket, Bucket: bucket,
Key: &object, Key: &object,
Retention: &types.ObjectLockRetention{ Retention: &types.ObjectLockRetention{
// TODO: add flag for governance mode Mode: options.Mode,
Mode: "COMPLIANCE",
RetainUntilDate: aws.Time(options.LockExpiry), RetainUntilDate: aws.Time(options.LockExpiry),
}, },
}) })