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

Add support for multiple lifecycle rules #85

Merged
merged 15 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
60 changes: 60 additions & 0 deletions examples/complete/lifecycle.us-west-1.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
region = "us-west-1"

namespace = "eg"

stage = "test"

name = "s3-lifecycle-test"

acl = "private"

lifecycle_rules = [
{
prefix = null
enabled = true
tags = { "temp" : "true" }

enable_glacier_transition = false
enable_deeparchive_transition = false
enable_standard_ia_transition = false
enable_current_object_expiration = true

abort_incomplete_multipart_upload_days = 1
noncurrent_version_glacier_transition_days = 0
noncurrent_version_deeparchive_transition_days = 0
noncurrent_version_expiration_days = 30

standard_transition_days = 0
glacier_transition_days = 0
deeparchive_transition_days = 0
expiration_days = 1
},
{
prefix = null
enabled = true
tags = {}

enable_glacier_transition = false
enable_deeparchive_transition = false
enable_standard_ia_transition = false
enable_current_object_expiration = true

abort_incomplete_multipart_upload_days = 1
noncurrent_version_glacier_transition_days = 0
noncurrent_version_deeparchive_transition_days = 0
noncurrent_version_expiration_days = 30

standard_transition_days = 0
glacier_transition_days = 0
deeparchive_transition_days = 0
expiration_days = 30
}
]

force_destroy = true

versioning_enabled = false

allow_encrypted_uploads_only = true

allowed_bucket_actions = ["s3:PutObject", "s3:PutObjectAcl", "s3:GetObject", "s3:DeleteObject", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:GetBucketLocation", "s3:AbortMultipartUpload"]
1 change: 1 addition & 0 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module "s3_bucket" {
acl = var.acl
force_destroy = var.force_destroy
grants = var.grants
lifecycle_rules = var.lifecycle_rules
versioning_enabled = var.versioning_enabled
allow_encrypted_uploads_only = var.allow_encrypted_uploads_only
allowed_bucket_actions = var.allowed_bucket_actions
Expand Down
26 changes: 26 additions & 0 deletions examples/complete/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,32 @@ variable "grants" {
description = "A list of ACL policy grants. Conflicts with `acl`. Set `acl` to `null` to use this."
}

variable "lifecycle_rules" {
type = list(object({
prefix = string
enabled = bool
tags = map(string)

enable_glacier_transition = bool
enable_deeparchive_transition = bool
enable_standard_ia_transition = bool
enable_current_object_expiration = bool

abort_incomplete_multipart_upload_days = number
noncurrent_version_glacier_transition_days = number
noncurrent_version_deeparchive_transition_days = number
noncurrent_version_expiration_days = number

standard_transition_days = number
glacier_transition_days = number
deeparchive_transition_days = number
expiration_days = number
}))
default = []

description = "A list of lifecycle rules."
}

variable "policy" {
type = string
default = ""
Expand Down
90 changes: 46 additions & 44 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,69 +16,71 @@ resource "aws_s3_bucket" "default" {
enabled = var.versioning_enabled
}

lifecycle_rule {
id = module.this.id
enabled = var.lifecycle_rule_enabled
prefix = var.prefix
tags = var.lifecycle_tags
abort_incomplete_multipart_upload_days = var.abort_incomplete_multipart_upload_days

noncurrent_version_expiration {
days = var.noncurrent_version_expiration_days
}
dynamic "lifecycle_rule" {
jamengual marked this conversation as resolved.
Show resolved Hide resolved
jamengual marked this conversation as resolved.
Show resolved Hide resolved
for_each = var.lifecycle_rules
content {
enabled = lifecycle_rule.value.enabled
prefix = lifecycle_rule.value.prefix
tags = lifecycle_rule.value.tags
abort_incomplete_multipart_upload_days = lifecycle_rule.value.abort_incomplete_multipart_upload_days

noncurrent_version_expiration {
days = lifecycle_rule.value.noncurrent_version_expiration_days
}

dynamic "noncurrent_version_transition" {
for_each = var.enable_glacier_transition ? [1] : []
dynamic "noncurrent_version_transition" {
for_each = lifecycle_rule.value.enable_glacier_transition ? [1] : []

content {
days = var.noncurrent_version_glacier_transition_days
storage_class = "GLACIER"
content {
days = lifecycle_rule.value.noncurrent_version_glacier_transition_days
storage_class = "GLACIER"
}
}
}

dynamic "noncurrent_version_transition" {
for_each = var.enable_deeparchive_transition ? [1] : []
dynamic "noncurrent_version_transition" {
for_each = lifecycle_rule.value.enable_deeparchive_transition ? [1] : []

content {
days = var.noncurrent_version_deeparchive_transition_days
storage_class = "DEEP_ARCHIVE"
content {
days = lifecycle_rule.value.noncurrent_version_deeparchive_transition_days
storage_class = "DEEP_ARCHIVE"
}
}
}

dynamic "transition" {
for_each = var.enable_glacier_transition ? [1] : []
dynamic "transition" {
for_each = lifecycle_rule.value.enable_glacier_transition ? [1] : []

content {
days = var.glacier_transition_days
storage_class = "GLACIER"
content {
days = lifecycle_rule.value.glacier_transition_days
storage_class = "GLACIER"
}
}
}

dynamic "transition" {
for_each = var.enable_deeparchive_transition ? [1] : []
dynamic "transition" {
for_each = lifecycle_rule.value.enable_deeparchive_transition ? [1] : []

content {
days = var.deeparchive_transition_days
storage_class = "DEEP_ARCHIVE"
content {
days = lifecycle_rule.value.deeparchive_transition_days
storage_class = "DEEP_ARCHIVE"
}
}
}



dynamic "transition" {
for_each = var.enable_standard_ia_transition ? [1] : []
dynamic "transition" {
for_each = lifecycle_rule.value.enable_standard_ia_transition ? [1] : []

content {
days = var.standard_transition_days
storage_class = "STANDARD_IA"
content {
days = lifecycle_rule.value.standard_transition_days
storage_class = "STANDARD_IA"
}
}
}

dynamic "expiration" {
for_each = var.enable_current_object_expiration ? [1] : []
dynamic "expiration" {
for_each = lifecycle_rule.value.enable_current_object_expiration ? [1] : []

content {
days = var.expiration_days
content {
days = lifecycle_rule.value.expiration_days
}
}
}
}
Expand Down
43 changes: 43 additions & 0 deletions test/src/examples_complete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,46 @@ func TestExamplesCompleteWithGrants(t *testing.T) {
// Verify we're getting back the outputs we expect
assert.Equal(t, expectedS3BucketId, s3BucketId)
}

// Test the Terraform module in examples/complete using Terratest for grants.
func TestExamplesCompleteWithLifecycleRules(t *testing.T) {
rand.Seed(time.Now().UnixNano())

attributes := []string{strconv.Itoa(rand.Intn(100000))}
rootFolder := "../../"
terraformFolderRelativeToRoot := "examples/complete"
varFiles := []string{"lifecycle.us-west-1.tfvars"}

tempTestFolder := test_structure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot)

terraformOptions := &terraform.Options{
// The path to where our Terraform code is located
TerraformDir: tempTestFolder,
Upgrade: true,
// Variables to pass to our Terraform code using -var-file options
VarFiles: varFiles,
Vars: map[string]interface{}{
"attributes": attributes,
},
}

// At the end of the test, run `terraform destroy` to clean up any resources that were created
defer terraform.Destroy(t, terraformOptions)

// This will run `terraform init` and `terraform apply` and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)

// Run `terraform output` to get the value of an output variable
userName := terraform.Output(t, terraformOptions, "user_name")

expectedUserName := "eg-test-s3-grants-test-" + attributes[0]
// Verify we're getting back the outputs we expect
assert.Equal(t, expectedUserName, userName)

// Run `terraform output` to get the value of an output variable
s3BucketId := terraform.Output(t, terraformOptions, "bucket_id")

expectedS3BucketId := "eg-test-s3-grants-test-" + attributes[0]
// Verify we're getting back the outputs we expect
assert.Equal(t, expectedS3BucketId, s3BucketId)
}
104 changes: 23 additions & 81 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -79,34 +79,29 @@ variable "allow_ssl_requests_only" {
description = "Set to `true` to require requests to use Secure Socket Layer (HTTPS/SSL). This will explicitly deny access to HTTP requests"
}

variable "lifecycle_rule_enabled" {
type = bool
default = false
description = "Enable or disable lifecycle rule"
}

variable "prefix" {
type = string
default = ""
description = "Prefix identifying one or more objects to which the rule applies"
}

variable "noncurrent_version_glacier_transition_days" {
type = number
default = 30
description = "Number of days to persist in the standard storage tier before moving to the glacier infrequent access tier"
}

variable "noncurrent_version_deeparchive_transition_days" {
type = number
default = 60
description = "Number of days to persist in the standard storage tier before moving to the glacier deeparchive access tier"
}

variable "noncurrent_version_expiration_days" {
type = number
default = 90
description = "Specifies when noncurrent object versions expire"
variable "lifecycle_rules" {
type = list(object({
prefix = string
enabled = bool
tags = map(string)

enable_glacier_transition = bool
enable_deeparchive_transition = bool
enable_standard_ia_transition = bool
enable_current_object_expiration = bool

abort_incomplete_multipart_upload_days = number
noncurrent_version_glacier_transition_days = number
noncurrent_version_deeparchive_transition_days = number
noncurrent_version_expiration_days = number

standard_transition_days = number
glacier_transition_days = number
deeparchive_transition_days = number
expiration_days = number
}))
default = []
description = "A list of lifecycle rules"
maeghan-porter marked this conversation as resolved.
Show resolved Hide resolved
}

variable "cors_rule_inputs" {
Expand All @@ -122,65 +117,12 @@ variable "cors_rule_inputs" {
description = "Specifies the allowed headers, methods, origins and exposed headers when using CORS on this bucket"
}

variable "standard_transition_days" {
type = number
default = 30
description = "Number of days to persist in the standard storage tier before moving to the infrequent access tier"
}

variable "glacier_transition_days" {
type = number
default = 60
description = "Number of days after which to move the data to the glacier storage tier"
}

variable "deeparchive_transition_days" {
type = number
default = 90
description = "Number of days after which to move the data to the glacier deep archive storage tier"
}

variable "enable_glacier_transition" {
type = bool
default = true
description = "Enables the transition to AWS Glacier which can cause unnecessary costs for huge amount of small files"
}

variable "enable_deeparchive_transition" {
type = bool
default = false
description = "Enables the transition to AWS Glacier Deep Archive which can cause unnecessary costs for huge amount of small files"
}
variable "enable_standard_ia_transition" {
type = bool
default = false
description = "Enables the transition to STANDARD_IA"
}

variable "enable_current_object_expiration" {
type = bool
default = true
description = "Enables the expiration of current objects"
}

variable "expiration_days" {
type = number
default = 90
description = "Number of days after which to expunge the objects"
}

variable "abort_incomplete_multipart_upload_days" {
type = number
default = 5
description = "Maximum time (in days) that you want to allow multipart uploads to remain in progress"
}

variable "lifecycle_tags" {
type = map(string)
description = "Tags filter. Used to manage object lifecycle events"
default = {}
}

variable "block_public_acls" {
type = bool
default = true
Expand Down