Skip to content
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

feat(storage): support AbortIncompleteMultipartUpload LifecycleAction #5812

Merged
merged 14 commits into from Jun 8, 2022
12 changes: 9 additions & 3 deletions storage/bucket.go
Expand Up @@ -646,6 +646,13 @@ const (
// SetStorageClassAction changes the storage class of live and/or archived
// objects.
SetStorageClassAction = "SetStorageClass"

// AbortIncompleteMPUAction is a lifecycle action that aborts an incomplete
// multipart upload when the multipart upload meets the conditions specified
// in the lifecycle rule. The AgeInDays condition is the only allowed
// condition for this action. AgeInDays is measured from the time the
// multipart upload was created.
AbortIncompleteMPUAction = "AbortIncompleteMultipartUpload"
)

// LifecycleRule is a lifecycle configuration rule.
Expand All @@ -666,9 +673,8 @@ type LifecycleRule struct {
type LifecycleAction struct {
// Type is the type of action to take on matching objects.
//
// Acceptable values are "Delete" to delete matching objects and
// "SetStorageClass" to set the storage class defined in StorageClass on
// matching objects.
// Acceptable values are "Delete", "SetStorageClass", and
BrennaEpp marked this conversation as resolved.
Show resolved Hide resolved
// "AbortIncompleteMultipartUpload".
Type string

// StorageClass is the storage class to set on matching objects if the Action
Expand Down
22 changes: 22 additions & 0 deletions storage/bucket_test.go
Expand Up @@ -103,6 +103,13 @@ func TestBucketAttrsToRawBucket(t *testing.T) {
Condition: LifecycleCondition{
Liveness: Archived,
},
}, {
Action: LifecycleAction{
Type: AbortIncompleteMPUAction,
},
Condition: LifecycleCondition{
AgeInDays: 20,
},
}},
},
}
Expand Down Expand Up @@ -184,6 +191,13 @@ func TestBucketAttrsToRawBucket(t *testing.T) {
Condition: &raw.BucketLifecycleRuleCondition{
IsLive: googleapi.Bool(false),
},
}, {
Action: &raw.BucketLifecycleRuleAction{
Type: AbortIncompleteMPUAction,
},
Condition: &raw.BucketLifecycleRuleCondition{
Age: 20,
},
}},
},
}
Expand Down Expand Up @@ -329,6 +343,10 @@ func TestBucketAttrsToUpdateToRawBucket(t *testing.T) {
Action: LifecycleAction{Type: "Delete"},
Condition: LifecycleCondition{AgeInDays: 30},
},
{
Action: LifecycleAction{Type: AbortIncompleteMPUAction},
Condition: LifecycleCondition{AgeInDays: 13},
},
},
},
Logging: &BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"},
Expand Down Expand Up @@ -368,6 +386,10 @@ func TestBucketAttrsToUpdateToRawBucket(t *testing.T) {
Action: &raw.BucketLifecycleRuleAction{Type: "Delete"},
Condition: &raw.BucketLifecycleRuleCondition{Age: 30},
},
{
Action: &raw.BucketLifecycleRuleAction{Type: AbortIncompleteMPUAction},
Condition: &raw.BucketLifecycleRuleCondition{Age: 13},
},
},
},
Logging: &raw.BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"},
Expand Down
50 changes: 50 additions & 0 deletions storage/integration_test.go
Expand Up @@ -325,6 +325,13 @@ func TestIntegration_BucketMethods(t *testing.T) {
MatchesStorageClasses: []string{"NEARLINE"},
NumNewerVersions: 10,
},
}, {
Action: LifecycleAction{
Type: AbortIncompleteMPUAction,
},
Condition: LifecycleCondition{
AgeInDays: 12,
},
}},
},
}
Expand All @@ -351,6 +358,49 @@ func TestIntegration_BucketMethods(t *testing.T) {
h.mustDeleteBucket(b)
}

func TestIntegration_BucketLifecycle(t *testing.T) {
ctx := context.Background()
client := testConfig(ctx, t)
defer client.Close()
h := testHelper{t}

wantLifecycle := Lifecycle{
Rules: []LifecycleRule{
{
Action: LifecycleAction{Type: AbortIncompleteMPUAction},
Condition: LifecycleCondition{AgeInDays: 30},
},
},
}

bucket := client.Bucket(uidSpace.New())

// Create bucket with lifecycle rules
bucket.Create(ctx, testutil.ProjID(), &BucketAttrs{
Lifecycle: wantLifecycle,
})
defer h.mustDeleteBucket(bucket)

attrs := h.mustBucketAttrs(bucket)
if !testutil.Equal(attrs.Lifecycle, wantLifecycle) {
t.Fatalf("got %v, want %v", attrs.Lifecycle, wantLifecycle)
}

// Remove lifecycle rules
ua := BucketAttrsToUpdate{Lifecycle: &Lifecycle{}}
attrs = h.mustUpdateBucket(bucket, ua, attrs.MetaGeneration)
if !testutil.Equal(attrs.Lifecycle, Lifecycle{}) {
t.Fatalf("got %v, want %v", attrs.Lifecycle, Lifecycle{})
}

// Update bucket with a lifecycle rule
ua = BucketAttrsToUpdate{Lifecycle: &wantLifecycle}
attrs = h.mustUpdateBucket(bucket, ua, attrs.MetaGeneration)
if !testutil.Equal(attrs.Lifecycle, wantLifecycle) {
t.Fatalf("got %v, want %v", attrs.Lifecycle, wantLifecycle)
}
}

func TestIntegration_BucketUpdate(t *testing.T) {
ctx := context.Background()
client := testConfig(ctx, t)
Expand Down