diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index b8f1b8a5..adea23e0 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -71,6 +71,14 @@ jobs: id: minMax uses: clowdhaus/terraform-min-max@v1.0.3 + - name: Install hcledit (for terraform_wrapper_module_for_each hook) + shell: bash + run: | + curl -L "$(curl -s https://api.github.com/repos/minamijoyo/hcledit/releases/latest | grep -o -E -m 1 "https://.+?_linux_amd64.tar.gz")" > hcledit.tgz + sudo tar -xzf hcledit.tgz -C /usr/bin/ hcledit + rm -f hcledit.tgz 2> /dev/null + hcledit version + - name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }} uses: clowdhaus/terraform-composite-actions/pre-commit@v1.3.0 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 39a8b594..954c5373 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,9 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.66.0 + rev: v1.71.0 hooks: - id: terraform_fmt + - id: terraform_wrapper_module_for_each - id: terraform_validate - id: terraform_docs args: diff --git a/README.md b/README.md index 8fe6badc..4c05bcf1 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,14 @@ inputs = { } ``` + +## Module wrappers + +Users of this Terraform module can create multiple similar resources by using [`for_each` meta-argument within `module` block](https://www.terraform.io/language/meta-arguments/for_each) which became available in Terraform 0.13. + +Users of Terragrunt can achieve similar results by using modules provided in the [wrappers](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/wrappers) directory, if they prefer to reduce amount of configuration files. + + ## Examples: - [Complete](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/complete) - Complete S3 bucket with most of supported features enabled diff --git a/wrappers/README.md b/wrappers/README.md index d0e1c4b2..9aa15fce 100644 --- a/wrappers/README.md +++ b/wrappers/README.md @@ -12,10 +12,20 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers" + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers" } inputs = { + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + items = { my-item = { # omitted... can be any argument supported by the module @@ -34,6 +44,14 @@ inputs = { module "wrapper" { source = "terraform-aws-modules/s3-bucket/aws//wrappers" + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + items = { my-item = { # omitted... can be any argument supported by the module @@ -52,18 +70,30 @@ module "wrapper" { ```hcl terraform { - source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers" + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers" } inputs = { + defaults = { + force_destroy = true + + attach_elb_log_delivery_policy = true + attach_lb_log_delivery_policy = true + attach_deny_insecure_transport_policy = true + attach_require_latest_tls_policy = true + } + items = { bucket1 = { - bucket = "my-random-bucket-1" - force_destroy = true + bucket = "my-random-bucket-1" } bucket2 = { - bucket = "my-random-bucket-2" - force_destroy = true + bucket = "my-random-bucket-2" + tags = { + Secure = "probably" + } } } } diff --git a/wrappers/main.tf b/wrappers/main.tf index 6a750d83..ea8315c2 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -3,37 +3,38 @@ module "wrapper" { for_each = var.items - create_bucket = try(each.value.create_bucket, true) - attach_elb_log_delivery_policy = try(each.value.attach_elb_log_delivery_policy, false) - attach_lb_log_delivery_policy = try(each.value.attach_lb_log_delivery_policy, false) - attach_deny_insecure_transport_policy = try(each.value.attach_deny_insecure_transport_policy, false) - attach_require_latest_tls_policy = try(each.value.attach_require_latest_tls_policy, false) - attach_policy = try(each.value.attach_policy, false) - attach_public_policy = try(each.value.attach_public_policy, true) - bucket = try(each.value.bucket, null) - bucket_prefix = try(each.value.bucket_prefix, null) - acl = try(each.value.acl, null) - policy = try(each.value.policy, null) - tags = try(each.value.tags, {}) - force_destroy = try(each.value.force_destroy, false) - acceleration_status = try(each.value.acceleration_status, null) - request_payer = try(each.value.request_payer, null) - website = try(each.value.website, {}) - cors_rule = try(each.value.cors_rule, []) - versioning = try(each.value.versioning, {}) - logging = try(each.value.logging, {}) - grant = try(each.value.grant, []) - owner = try(each.value.owner, {}) - expected_bucket_owner = try(each.value.expected_bucket_owner, null) - lifecycle_rule = try(each.value.lifecycle_rule, []) - replication_configuration = try(each.value.replication_configuration, {}) - server_side_encryption_configuration = try(each.value.server_side_encryption_configuration, {}) - object_lock_configuration = try(each.value.object_lock_configuration, {}) - block_public_acls = try(each.value.block_public_acls, false) - block_public_policy = try(each.value.block_public_policy, false) - ignore_public_acls = try(each.value.ignore_public_acls, false) - restrict_public_buckets = try(each.value.restrict_public_buckets, false) - control_object_ownership = try(each.value.control_object_ownership, false) - object_ownership = try(each.value.object_ownership, "ObjectWriter") - putin_khuylo = try(each.value.putin_khuylo, true) + create_bucket = try(each.value.create_bucket, var.defaults.create_bucket, true) + attach_elb_log_delivery_policy = try(each.value.attach_elb_log_delivery_policy, var.defaults.attach_elb_log_delivery_policy, false) + attach_lb_log_delivery_policy = try(each.value.attach_lb_log_delivery_policy, var.defaults.attach_lb_log_delivery_policy, false) + attach_deny_insecure_transport_policy = try(each.value.attach_deny_insecure_transport_policy, var.defaults.attach_deny_insecure_transport_policy, false) + attach_require_latest_tls_policy = try(each.value.attach_require_latest_tls_policy, var.defaults.attach_require_latest_tls_policy, false) + attach_policy = try(each.value.attach_policy, var.defaults.attach_policy, false) + attach_public_policy = try(each.value.attach_public_policy, var.defaults.attach_public_policy, true) + bucket = try(each.value.bucket, var.defaults.bucket, null) + bucket_prefix = try(each.value.bucket_prefix, var.defaults.bucket_prefix, null) + acl = try(each.value.acl, var.defaults.acl, null) + policy = try(each.value.policy, var.defaults.policy, null) + tags = try(each.value.tags, var.defaults.tags, {}) + force_destroy = try(each.value.force_destroy, var.defaults.force_destroy, false) + acceleration_status = try(each.value.acceleration_status, var.defaults.acceleration_status, null) + request_payer = try(each.value.request_payer, var.defaults.request_payer, null) + website = try(each.value.website, var.defaults.website, {}) + cors_rule = try(each.value.cors_rule, var.defaults.cors_rule, []) + versioning = try(each.value.versioning, var.defaults.versioning, {}) + logging = try(each.value.logging, var.defaults.logging, {}) + grant = try(each.value.grant, var.defaults.grant, []) + owner = try(each.value.owner, var.defaults.owner, {}) + expected_bucket_owner = try(each.value.expected_bucket_owner, var.defaults.expected_bucket_owner, null) + lifecycle_rule = try(each.value.lifecycle_rule, var.defaults.lifecycle_rule, []) + replication_configuration = try(each.value.replication_configuration, var.defaults.replication_configuration, {}) + server_side_encryption_configuration = try(each.value.server_side_encryption_configuration, var.defaults.server_side_encryption_configuration, {}) + object_lock_configuration = try(each.value.object_lock_configuration, var.defaults.object_lock_configuration, {}) + object_lock_enabled = try(each.value.object_lock_enabled, var.defaults.object_lock_enabled, false) + block_public_acls = try(each.value.block_public_acls, var.defaults.block_public_acls, false) + block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, false) + ignore_public_acls = try(each.value.ignore_public_acls, var.defaults.ignore_public_acls, false) + restrict_public_buckets = try(each.value.restrict_public_buckets, var.defaults.restrict_public_buckets, false) + control_object_ownership = try(each.value.control_object_ownership, var.defaults.control_object_ownership, false) + object_ownership = try(each.value.object_ownership, var.defaults.object_ownership, "ObjectWriter") + putin_khuylo = try(each.value.putin_khuylo, var.defaults.putin_khuylo, true) } diff --git a/wrappers/notification/README.md b/wrappers/notification/README.md index cf3e1cad..f9690b41 100644 --- a/wrappers/notification/README.md +++ b/wrappers/notification/README.md @@ -12,10 +12,20 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers/notification" + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers/notification" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers/notification" } inputs = { + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + items = { my-item = { # omitted... can be any argument supported by the module @@ -34,6 +44,14 @@ inputs = { module "wrapper" { source = "terraform-aws-modules/s3-bucket/aws//wrappers/notification" + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + items = { my-item = { # omitted... can be any argument supported by the module @@ -52,18 +70,30 @@ module "wrapper" { ```hcl terraform { - source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers" + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers" } inputs = { + defaults = { + force_destroy = true + + attach_elb_log_delivery_policy = true + attach_lb_log_delivery_policy = true + attach_deny_insecure_transport_policy = true + attach_require_latest_tls_policy = true + } + items = { bucket1 = { - bucket = "my-random-bucket-1" - force_destroy = true + bucket = "my-random-bucket-1" } bucket2 = { - bucket = "my-random-bucket-2" - force_destroy = true + bucket = "my-random-bucket-2" + tags = { + Secure = "probably" + } } } } diff --git a/wrappers/notification/main.tf b/wrappers/notification/main.tf index eb6045ee..ddd2cbba 100644 --- a/wrappers/notification/main.tf +++ b/wrappers/notification/main.tf @@ -3,13 +3,13 @@ module "wrapper" { for_each = var.items - create = try(each.value.create, true) - create_sns_policy = try(each.value.create_sns_policy, true) - create_sqs_policy = try(each.value.create_sqs_policy, true) - bucket = try(each.value.bucket, "") - bucket_arn = try(each.value.bucket_arn, null) - eventbridge = try(each.value.eventbridge, null) - lambda_notifications = try(each.value.lambda_notifications, {}) - sqs_notifications = try(each.value.sqs_notifications, {}) - sns_notifications = try(each.value.sns_notifications, {}) + create = try(each.value.create, var.defaults.create, true) + create_sns_policy = try(each.value.create_sns_policy, var.defaults.create_sns_policy, true) + create_sqs_policy = try(each.value.create_sqs_policy, var.defaults.create_sqs_policy, true) + bucket = try(each.value.bucket, var.defaults.bucket, "") + bucket_arn = try(each.value.bucket_arn, var.defaults.bucket_arn, null) + eventbridge = try(each.value.eventbridge, var.defaults.eventbridge, null) + lambda_notifications = try(each.value.lambda_notifications, var.defaults.lambda_notifications, {}) + sqs_notifications = try(each.value.sqs_notifications, var.defaults.sqs_notifications, {}) + sns_notifications = try(each.value.sns_notifications, var.defaults.sns_notifications, {}) } diff --git a/wrappers/notification/outputs.tf b/wrappers/notification/outputs.tf index d4602543..5da7c09b 100644 --- a/wrappers/notification/outputs.tf +++ b/wrappers/notification/outputs.tf @@ -1,4 +1,5 @@ output "wrapper" { description = "Map of outputs of a wrapper." value = module.wrapper + # sensitive = false # No sensitive module output found } diff --git a/wrappers/notification/variables.tf b/wrappers/notification/variables.tf index 9c7d9234..a6ea0962 100644 --- a/wrappers/notification/variables.tf +++ b/wrappers/notification/variables.tf @@ -1,3 +1,9 @@ +variable "defaults" { + description = "Map of default values which will be used for each item." + type = any + default = {} +} + variable "items" { description = "Maps of items to create a wrapper from. Values are passed through to the module." type = any diff --git a/wrappers/object/README.md b/wrappers/object/README.md index b852ec15..f4e6f0e5 100644 --- a/wrappers/object/README.md +++ b/wrappers/object/README.md @@ -12,10 +12,20 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers/object" + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers/object" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers/object" } inputs = { + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + items = { my-item = { # omitted... can be any argument supported by the module @@ -34,6 +44,14 @@ inputs = { module "wrapper" { source = "terraform-aws-modules/s3-bucket/aws//wrappers/object" + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + items = { my-item = { # omitted... can be any argument supported by the module @@ -52,18 +70,30 @@ module "wrapper" { ```hcl terraform { - source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers" + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers" } inputs = { + defaults = { + force_destroy = true + + attach_elb_log_delivery_policy = true + attach_lb_log_delivery_policy = true + attach_deny_insecure_transport_policy = true + attach_require_latest_tls_policy = true + } + items = { bucket1 = { - bucket = "my-random-bucket-1" - force_destroy = true + bucket = "my-random-bucket-1" } bucket2 = { - bucket = "my-random-bucket-2" - force_destroy = true + bucket = "my-random-bucket-2" + tags = { + Secure = "probably" + } } } } diff --git a/wrappers/object/main.tf b/wrappers/object/main.tf index b6ee08f3..b0e94a71 100644 --- a/wrappers/object/main.tf +++ b/wrappers/object/main.tf @@ -3,28 +3,28 @@ module "wrapper" { for_each = var.items - create = try(each.value.create, true) - bucket = try(each.value.bucket, "") - key = try(each.value.key, "") - file_source = try(each.value.file_source, null) - content = try(each.value.content, null) - content_base64 = try(each.value.content_base64, null) - acl = try(each.value.acl, null) - cache_control = try(each.value.cache_control, null) - content_disposition = try(each.value.content_disposition, null) - content_encoding = try(each.value.content_encoding, null) - content_language = try(each.value.content_language, null) - content_type = try(each.value.content_type, null) - website_redirect = try(each.value.website_redirect, null) - storage_class = try(each.value.storage_class, null) - etag = try(each.value.etag, null) - server_side_encryption = try(each.value.server_side_encryption, null) - kms_key_id = try(each.value.kms_key_id, null) - bucket_key_enabled = try(each.value.bucket_key_enabled, null) - metadata = try(each.value.metadata, {}) - tags = try(each.value.tags, {}) - force_destroy = try(each.value.force_destroy, false) - object_lock_legal_hold_status = try(each.value.object_lock_legal_hold_status, null) - object_lock_mode = try(each.value.object_lock_mode, null) - object_lock_retain_until_date = try(each.value.object_lock_retain_until_date, null) + create = try(each.value.create, var.defaults.create, true) + bucket = try(each.value.bucket, var.defaults.bucket, "") + key = try(each.value.key, var.defaults.key, "") + file_source = try(each.value.file_source, var.defaults.file_source, null) + content = try(each.value.content, var.defaults.content, null) + content_base64 = try(each.value.content_base64, var.defaults.content_base64, null) + acl = try(each.value.acl, var.defaults.acl, null) + cache_control = try(each.value.cache_control, var.defaults.cache_control, null) + content_disposition = try(each.value.content_disposition, var.defaults.content_disposition, null) + content_encoding = try(each.value.content_encoding, var.defaults.content_encoding, null) + content_language = try(each.value.content_language, var.defaults.content_language, null) + content_type = try(each.value.content_type, var.defaults.content_type, null) + website_redirect = try(each.value.website_redirect, var.defaults.website_redirect, null) + storage_class = try(each.value.storage_class, var.defaults.storage_class, null) + etag = try(each.value.etag, var.defaults.etag, null) + server_side_encryption = try(each.value.server_side_encryption, var.defaults.server_side_encryption, null) + kms_key_id = try(each.value.kms_key_id, var.defaults.kms_key_id, null) + bucket_key_enabled = try(each.value.bucket_key_enabled, var.defaults.bucket_key_enabled, null) + metadata = try(each.value.metadata, var.defaults.metadata, {}) + tags = try(each.value.tags, var.defaults.tags, {}) + force_destroy = try(each.value.force_destroy, var.defaults.force_destroy, false) + object_lock_legal_hold_status = try(each.value.object_lock_legal_hold_status, var.defaults.object_lock_legal_hold_status, null) + object_lock_mode = try(each.value.object_lock_mode, var.defaults.object_lock_mode, null) + object_lock_retain_until_date = try(each.value.object_lock_retain_until_date, var.defaults.object_lock_retain_until_date, null) } diff --git a/wrappers/object/outputs.tf b/wrappers/object/outputs.tf index d4602543..5da7c09b 100644 --- a/wrappers/object/outputs.tf +++ b/wrappers/object/outputs.tf @@ -1,4 +1,5 @@ output "wrapper" { description = "Map of outputs of a wrapper." value = module.wrapper + # sensitive = false # No sensitive module output found } diff --git a/wrappers/object/variables.tf b/wrappers/object/variables.tf index 9c7d9234..a6ea0962 100644 --- a/wrappers/object/variables.tf +++ b/wrappers/object/variables.tf @@ -1,3 +1,9 @@ +variable "defaults" { + description = "Map of default values which will be used for each item." + type = any + default = {} +} + variable "items" { description = "Maps of items to create a wrapper from. Values are passed through to the module." type = any diff --git a/wrappers/outputs.tf b/wrappers/outputs.tf index d4602543..5da7c09b 100644 --- a/wrappers/outputs.tf +++ b/wrappers/outputs.tf @@ -1,4 +1,5 @@ output "wrapper" { description = "Map of outputs of a wrapper." value = module.wrapper + # sensitive = false # No sensitive module output found } diff --git a/wrappers/variables.tf b/wrappers/variables.tf index 9c7d9234..a6ea0962 100644 --- a/wrappers/variables.tf +++ b/wrappers/variables.tf @@ -1,3 +1,9 @@ +variable "defaults" { + description = "Map of default values which will be used for each item." + type = any + default = {} +} + variable "items" { description = "Maps of items to create a wrapper from. Values are passed through to the module." type = any