From e6052ec3e135943e464dc2e03f7c4aeb390d1759 Mon Sep 17 00:00:00 2001 From: flora-five <72858916+flora-five@users.noreply.github.com> Date: Mon, 29 Sep 2025 09:47:06 +0000 Subject: [PATCH] feat: Add wrappers --- .pre-commit-config.yaml | 3 +- wrappers/README.md | 100 +++++++++++++++++++++++++ wrappers/main.tf | 79 +++++++++++++++++++ wrappers/outputs.tf | 5 ++ wrappers/serverless-cache/README.md | 100 +++++++++++++++++++++++++ wrappers/serverless-cache/main.tf | 21 ++++++ wrappers/serverless-cache/outputs.tf | 5 ++ wrappers/serverless-cache/variables.tf | 11 +++ wrappers/serverless-cache/versions.tf | 10 +++ wrappers/user-group/README.md | 100 +++++++++++++++++++++++++ wrappers/user-group/main.tf | 15 ++++ wrappers/user-group/outputs.tf | 5 ++ wrappers/user-group/variables.tf | 11 +++ wrappers/user-group/versions.tf | 10 +++ wrappers/variables.tf | 11 +++ wrappers/versions.tf | 14 ++++ 16 files changed, 499 insertions(+), 1 deletion(-) create mode 100644 wrappers/README.md create mode 100644 wrappers/main.tf create mode 100644 wrappers/outputs.tf create mode 100644 wrappers/serverless-cache/README.md create mode 100644 wrappers/serverless-cache/main.tf create mode 100644 wrappers/serverless-cache/outputs.tf create mode 100644 wrappers/serverless-cache/variables.tf create mode 100644 wrappers/serverless-cache/versions.tf create mode 100644 wrappers/user-group/README.md create mode 100644 wrappers/user-group/main.tf create mode 100644 wrappers/user-group/outputs.tf create mode 100644 wrappers/user-group/variables.tf create mode 100644 wrappers/user-group/versions.tf create mode 100644 wrappers/variables.tf create mode 100644 wrappers/versions.tf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 11084f7..52fd864 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.100.0 + rev: v1.100.1 hooks: - id: terraform_fmt + - id: terraform_wrapper_module_for_each - id: terraform_docs args: - '--args=--lockfile=false' diff --git a/wrappers/README.md b/wrappers/README.md new file mode 100644 index 0000000..4f9fb89 --- /dev/null +++ b/wrappers/README.md @@ -0,0 +1,100 @@ +# Wrapper for the root module + +The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt). + +You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module. + +This wrapper does not implement any extra functionality. + +## Usage with Terragrunt + +`terragrunt.hcl`: + +```hcl +terraform { + source = "tfr:///terraform-aws-modules/elasticache/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-elasticache.git//wrappers?ref=master" +} + +inputs = { + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + + items = { + my-item = { + # omitted... can be any argument supported by the module + } + my-second-item = { + # omitted... can be any argument supported by the module + } + # omitted... + } +} +``` + +## Usage with Terraform + +```hcl +module "wrapper" { + source = "terraform-aws-modules/elasticache/aws//wrappers" + + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + + items = { + my-item = { + # omitted... can be any argument supported by the module + } + my-second-item = { + # omitted... can be any argument supported by the module + } + # omitted... + } +} +``` + +## Example: Manage multiple S3 buckets in one Terragrunt layer + +`eu-west-1/s3-buckets/terragrunt.hcl`: + +```hcl +terraform { + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master" +} + +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" + } + bucket2 = { + bucket = "my-random-bucket-2" + tags = { + Secure = "probably" + } + } + } +} +``` diff --git a/wrappers/main.tf b/wrappers/main.tf new file mode 100644 index 0000000..d53ac58 --- /dev/null +++ b/wrappers/main.tf @@ -0,0 +1,79 @@ +module "wrapper" { + source = "../" + + for_each = var.items + + apply_immediately = try(each.value.apply_immediately, var.defaults.apply_immediately, null) + at_rest_encryption_enabled = try(each.value.at_rest_encryption_enabled, var.defaults.at_rest_encryption_enabled, true) + auth_token = try(each.value.auth_token, var.defaults.auth_token, null) + auth_token_update_strategy = try(each.value.auth_token_update_strategy, var.defaults.auth_token_update_strategy, null) + auto_minor_version_upgrade = try(each.value.auto_minor_version_upgrade, var.defaults.auto_minor_version_upgrade, null) + automatic_failover_enabled = try(each.value.automatic_failover_enabled, var.defaults.automatic_failover_enabled, null) + availability_zone = try(each.value.availability_zone, var.defaults.availability_zone, null) + az_mode = try(each.value.az_mode, var.defaults.az_mode, null) + cluster_id = try(each.value.cluster_id, var.defaults.cluster_id, "") + cluster_mode = try(each.value.cluster_mode, var.defaults.cluster_mode, null) + cluster_mode_enabled = try(each.value.cluster_mode_enabled, var.defaults.cluster_mode_enabled, false) + create = try(each.value.create, var.defaults.create, true) + create_cluster = try(each.value.create_cluster, var.defaults.create_cluster, false) + create_parameter_group = try(each.value.create_parameter_group, var.defaults.create_parameter_group, false) + create_primary_global_replication_group = try(each.value.create_primary_global_replication_group, var.defaults.create_primary_global_replication_group, false) + create_replication_group = try(each.value.create_replication_group, var.defaults.create_replication_group, true) + create_secondary_global_replication_group = try(each.value.create_secondary_global_replication_group, var.defaults.create_secondary_global_replication_group, false) + create_security_group = try(each.value.create_security_group, var.defaults.create_security_group, true) + create_subnet_group = try(each.value.create_subnet_group, var.defaults.create_subnet_group, true) + data_tiering_enabled = try(each.value.data_tiering_enabled, var.defaults.data_tiering_enabled, null) + description = try(each.value.description, var.defaults.description, null) + engine = try(each.value.engine, var.defaults.engine, "redis") + engine_version = try(each.value.engine_version, var.defaults.engine_version, null) + final_snapshot_identifier = try(each.value.final_snapshot_identifier, var.defaults.final_snapshot_identifier, null) + global_replication_group_id = try(each.value.global_replication_group_id, var.defaults.global_replication_group_id, null) + global_replication_group_id_suffix = try(each.value.global_replication_group_id_suffix, var.defaults.global_replication_group_id_suffix, null) + ip_discovery = try(each.value.ip_discovery, var.defaults.ip_discovery, null) + kms_key_arn = try(each.value.kms_key_arn, var.defaults.kms_key_arn, null) + log_delivery_configuration = try(each.value.log_delivery_configuration, var.defaults.log_delivery_configuration, { + slow-log = { + destination_type = "cloudwatch-logs" + log_format = "json" + } + }) + maintenance_window = try(each.value.maintenance_window, var.defaults.maintenance_window, null) + multi_az_enabled = try(each.value.multi_az_enabled, var.defaults.multi_az_enabled, false) + network_type = try(each.value.network_type, var.defaults.network_type, null) + node_type = try(each.value.node_type, var.defaults.node_type, null) + notification_topic_arn = try(each.value.notification_topic_arn, var.defaults.notification_topic_arn, null) + num_cache_clusters = try(each.value.num_cache_clusters, var.defaults.num_cache_clusters, null) + num_cache_nodes = try(each.value.num_cache_nodes, var.defaults.num_cache_nodes, 1) + num_node_groups = try(each.value.num_node_groups, var.defaults.num_node_groups, null) + outpost_mode = try(each.value.outpost_mode, var.defaults.outpost_mode, null) + parameter_group_description = try(each.value.parameter_group_description, var.defaults.parameter_group_description, null) + parameter_group_family = try(each.value.parameter_group_family, var.defaults.parameter_group_family, "") + parameter_group_name = try(each.value.parameter_group_name, var.defaults.parameter_group_name, null) + parameters = try(each.value.parameters, var.defaults.parameters, []) + port = try(each.value.port, var.defaults.port, null) + preferred_availability_zones = try(each.value.preferred_availability_zones, var.defaults.preferred_availability_zones, []) + preferred_cache_cluster_azs = try(each.value.preferred_cache_cluster_azs, var.defaults.preferred_cache_cluster_azs, []) + preferred_outpost_arn = try(each.value.preferred_outpost_arn, var.defaults.preferred_outpost_arn, null) + replicas_per_node_group = try(each.value.replicas_per_node_group, var.defaults.replicas_per_node_group, null) + replication_group_id = try(each.value.replication_group_id, var.defaults.replication_group_id, null) + security_group_description = try(each.value.security_group_description, var.defaults.security_group_description, null) + security_group_ids = try(each.value.security_group_ids, var.defaults.security_group_ids, []) + security_group_name = try(each.value.security_group_name, var.defaults.security_group_name, null) + security_group_names = try(each.value.security_group_names, var.defaults.security_group_names, []) + security_group_rules = try(each.value.security_group_rules, var.defaults.security_group_rules, {}) + security_group_tags = try(each.value.security_group_tags, var.defaults.security_group_tags, {}) + security_group_use_name_prefix = try(each.value.security_group_use_name_prefix, var.defaults.security_group_use_name_prefix, true) + snapshot_arns = try(each.value.snapshot_arns, var.defaults.snapshot_arns, []) + snapshot_name = try(each.value.snapshot_name, var.defaults.snapshot_name, null) + snapshot_retention_limit = try(each.value.snapshot_retention_limit, var.defaults.snapshot_retention_limit, null) + snapshot_window = try(each.value.snapshot_window, var.defaults.snapshot_window, null) + subnet_group_description = try(each.value.subnet_group_description, var.defaults.subnet_group_description, null) + subnet_group_name = try(each.value.subnet_group_name, var.defaults.subnet_group_name, null) + subnet_ids = try(each.value.subnet_ids, var.defaults.subnet_ids, []) + tags = try(each.value.tags, var.defaults.tags, {}) + timeouts = try(each.value.timeouts, var.defaults.timeouts, {}) + transit_encryption_enabled = try(each.value.transit_encryption_enabled, var.defaults.transit_encryption_enabled, true) + transit_encryption_mode = try(each.value.transit_encryption_mode, var.defaults.transit_encryption_mode, null) + user_group_ids = try(each.value.user_group_ids, var.defaults.user_group_ids, null) + vpc_id = try(each.value.vpc_id, var.defaults.vpc_id, null) +} diff --git a/wrappers/outputs.tf b/wrappers/outputs.tf new file mode 100644 index 0000000..ec6da5f --- /dev/null +++ b/wrappers/outputs.tf @@ -0,0 +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/serverless-cache/README.md b/wrappers/serverless-cache/README.md new file mode 100644 index 0000000..03338a3 --- /dev/null +++ b/wrappers/serverless-cache/README.md @@ -0,0 +1,100 @@ +# Wrapper for module: `modules/serverless-cache` + +The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt). + +You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module. + +This wrapper does not implement any extra functionality. + +## Usage with Terragrunt + +`terragrunt.hcl`: + +```hcl +terraform { + source = "tfr:///terraform-aws-modules/elasticache/aws//wrappers/serverless-cache" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-elasticache.git//wrappers/serverless-cache?ref=master" +} + +inputs = { + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + + items = { + my-item = { + # omitted... can be any argument supported by the module + } + my-second-item = { + # omitted... can be any argument supported by the module + } + # omitted... + } +} +``` + +## Usage with Terraform + +```hcl +module "wrapper" { + source = "terraform-aws-modules/elasticache/aws//wrappers/serverless-cache" + + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + + items = { + my-item = { + # omitted... can be any argument supported by the module + } + my-second-item = { + # omitted... can be any argument supported by the module + } + # omitted... + } +} +``` + +## Example: Manage multiple S3 buckets in one Terragrunt layer + +`eu-west-1/s3-buckets/terragrunt.hcl`: + +```hcl +terraform { + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master" +} + +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" + } + bucket2 = { + bucket = "my-random-bucket-2" + tags = { + Secure = "probably" + } + } + } +} +``` diff --git a/wrappers/serverless-cache/main.tf b/wrappers/serverless-cache/main.tf new file mode 100644 index 0000000..e46f1a1 --- /dev/null +++ b/wrappers/serverless-cache/main.tf @@ -0,0 +1,21 @@ +module "wrapper" { + source = "../../modules/serverless-cache" + + for_each = var.items + + cache_name = try(each.value.cache_name, var.defaults.cache_name, null) + cache_usage_limits = try(each.value.cache_usage_limits, var.defaults.cache_usage_limits, {}) + create = try(each.value.create, var.defaults.create, true) + daily_snapshot_time = try(each.value.daily_snapshot_time, var.defaults.daily_snapshot_time, null) + description = try(each.value.description, var.defaults.description, null) + engine = try(each.value.engine, var.defaults.engine, "redis") + kms_key_id = try(each.value.kms_key_id, var.defaults.kms_key_id, null) + major_engine_version = try(each.value.major_engine_version, var.defaults.major_engine_version, null) + security_group_ids = try(each.value.security_group_ids, var.defaults.security_group_ids, []) + snapshot_arns_to_restore = try(each.value.snapshot_arns_to_restore, var.defaults.snapshot_arns_to_restore, null) + snapshot_retention_limit = try(each.value.snapshot_retention_limit, var.defaults.snapshot_retention_limit, null) + subnet_ids = try(each.value.subnet_ids, var.defaults.subnet_ids, []) + tags = try(each.value.tags, var.defaults.tags, {}) + timeouts = try(each.value.timeouts, var.defaults.timeouts, {}) + user_group_id = try(each.value.user_group_id, var.defaults.user_group_id, null) +} diff --git a/wrappers/serverless-cache/outputs.tf b/wrappers/serverless-cache/outputs.tf new file mode 100644 index 0000000..ec6da5f --- /dev/null +++ b/wrappers/serverless-cache/outputs.tf @@ -0,0 +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/serverless-cache/variables.tf b/wrappers/serverless-cache/variables.tf new file mode 100644 index 0000000..a6ea096 --- /dev/null +++ b/wrappers/serverless-cache/variables.tf @@ -0,0 +1,11 @@ +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 + default = {} +} diff --git a/wrappers/serverless-cache/versions.tf b/wrappers/serverless-cache/versions.tf new file mode 100644 index 0000000..0f48a6c --- /dev/null +++ b/wrappers/serverless-cache/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.73" + } + } +} diff --git a/wrappers/user-group/README.md b/wrappers/user-group/README.md new file mode 100644 index 0000000..bd17f5f --- /dev/null +++ b/wrappers/user-group/README.md @@ -0,0 +1,100 @@ +# Wrapper for module: `modules/user-group` + +The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt). + +You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module. + +This wrapper does not implement any extra functionality. + +## Usage with Terragrunt + +`terragrunt.hcl`: + +```hcl +terraform { + source = "tfr:///terraform-aws-modules/elasticache/aws//wrappers/user-group" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-elasticache.git//wrappers/user-group?ref=master" +} + +inputs = { + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + + items = { + my-item = { + # omitted... can be any argument supported by the module + } + my-second-item = { + # omitted... can be any argument supported by the module + } + # omitted... + } +} +``` + +## Usage with Terraform + +```hcl +module "wrapper" { + source = "terraform-aws-modules/elasticache/aws//wrappers/user-group" + + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + + items = { + my-item = { + # omitted... can be any argument supported by the module + } + my-second-item = { + # omitted... can be any argument supported by the module + } + # omitted... + } +} +``` + +## Example: Manage multiple S3 buckets in one Terragrunt layer + +`eu-west-1/s3-buckets/terragrunt.hcl`: + +```hcl +terraform { + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master" +} + +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" + } + bucket2 = { + bucket = "my-random-bucket-2" + tags = { + Secure = "probably" + } + } + } +} +``` diff --git a/wrappers/user-group/main.tf b/wrappers/user-group/main.tf new file mode 100644 index 0000000..0af01d9 --- /dev/null +++ b/wrappers/user-group/main.tf @@ -0,0 +1,15 @@ +module "wrapper" { + source = "../../modules/user-group" + + for_each = var.items + + create = try(each.value.create, var.defaults.create, true) + create_default_user = try(each.value.create_default_user, var.defaults.create_default_user, true) + create_group = try(each.value.create_group, var.defaults.create_group, true) + default_user = try(each.value.default_user, var.defaults.default_user, {}) + default_user_id = try(each.value.default_user_id, var.defaults.default_user_id, "default") + engine = try(each.value.engine, var.defaults.engine, "redis") + tags = try(each.value.tags, var.defaults.tags, {}) + user_group_id = try(each.value.user_group_id, var.defaults.user_group_id, "") + users = try(each.value.users, var.defaults.users, {}) +} diff --git a/wrappers/user-group/outputs.tf b/wrappers/user-group/outputs.tf new file mode 100644 index 0000000..ec6da5f --- /dev/null +++ b/wrappers/user-group/outputs.tf @@ -0,0 +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/user-group/variables.tf b/wrappers/user-group/variables.tf new file mode 100644 index 0000000..a6ea096 --- /dev/null +++ b/wrappers/user-group/variables.tf @@ -0,0 +1,11 @@ +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 + default = {} +} diff --git a/wrappers/user-group/versions.tf b/wrappers/user-group/versions.tf new file mode 100644 index 0000000..0f48a6c --- /dev/null +++ b/wrappers/user-group/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.73" + } + } +} diff --git a/wrappers/variables.tf b/wrappers/variables.tf new file mode 100644 index 0000000..a6ea096 --- /dev/null +++ b/wrappers/variables.tf @@ -0,0 +1,11 @@ +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 + default = {} +} diff --git a/wrappers/versions.tf b/wrappers/versions.tf new file mode 100644 index 0000000..6dda813 --- /dev/null +++ b/wrappers/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.93" + } + random = { + source = "hashicorp/random" + version = ">= 3.0" + } + } +}