diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dabb150..e65e6ea 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.80.0 + rev: v1.81.2 hooks: - id: terraform_fmt + - id: terraform_wrapper_module_for_each - id: terraform_validate - id: terraform_docs args: diff --git a/wrappers/README.md b/wrappers/README.md new file mode 100644 index 0000000..109bf78 --- /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/appsync/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-appsync.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/appsync/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..4613965 --- /dev/null +++ b/wrappers/main.tf @@ -0,0 +1,70 @@ +module "wrapper" { + source = "../" + + for_each = var.items + + create_graphql_api = try(each.value.create_graphql_api, var.defaults.create_graphql_api, true) + logging_enabled = try(each.value.logging_enabled, var.defaults.logging_enabled, false) + domain_name_association_enabled = try(each.value.domain_name_association_enabled, var.defaults.domain_name_association_enabled, false) + caching_enabled = try(each.value.caching_enabled, var.defaults.caching_enabled, false) + xray_enabled = try(each.value.xray_enabled, var.defaults.xray_enabled, false) + name = try(each.value.name, var.defaults.name, "") + schema = try(each.value.schema, var.defaults.schema, "") + visibility = try(each.value.visibility, var.defaults.visibility, null) + authentication_type = try(each.value.authentication_type, var.defaults.authentication_type, "API_KEY") + create_logs_role = try(each.value.create_logs_role, var.defaults.create_logs_role, true) + logs_role_name = try(each.value.logs_role_name, var.defaults.logs_role_name, null) + log_cloudwatch_logs_role_arn = try(each.value.log_cloudwatch_logs_role_arn, var.defaults.log_cloudwatch_logs_role_arn, null) + log_field_log_level = try(each.value.log_field_log_level, var.defaults.log_field_log_level, null) + log_exclude_verbose_content = try(each.value.log_exclude_verbose_content, var.defaults.log_exclude_verbose_content, false) + lambda_authorizer_config = try(each.value.lambda_authorizer_config, var.defaults.lambda_authorizer_config, {}) + openid_connect_config = try(each.value.openid_connect_config, var.defaults.openid_connect_config, {}) + user_pool_config = try(each.value.user_pool_config, var.defaults.user_pool_config, {}) + additional_authentication_provider = try(each.value.additional_authentication_provider, var.defaults.additional_authentication_provider, {}) + graphql_api_tags = try(each.value.graphql_api_tags, var.defaults.graphql_api_tags, {}) + logs_role_tags = try(each.value.logs_role_tags, var.defaults.logs_role_tags, {}) + tags = try(each.value.tags, var.defaults.tags, {}) + domain_name = try(each.value.domain_name, var.defaults.domain_name, "") + domain_name_description = try(each.value.domain_name_description, var.defaults.domain_name_description, null) + certificate_arn = try(each.value.certificate_arn, var.defaults.certificate_arn, "") + caching_behavior = try(each.value.caching_behavior, var.defaults.caching_behavior, "FULL_REQUEST_CACHING") + cache_type = try(each.value.cache_type, var.defaults.cache_type, "SMALL") + cache_ttl = try(each.value.cache_ttl, var.defaults.cache_ttl, 1) + cache_at_rest_encryption_enabled = try(each.value.cache_at_rest_encryption_enabled, var.defaults.cache_at_rest_encryption_enabled, false) + cache_transit_encryption_enabled = try(each.value.cache_transit_encryption_enabled, var.defaults.cache_transit_encryption_enabled, false) + api_keys = try(each.value.api_keys, var.defaults.api_keys, {}) + lambda_allowed_actions = try(each.value.lambda_allowed_actions, var.defaults.lambda_allowed_actions, ["lambda:invokeFunction"]) + dynamodb_allowed_actions = try(each.value.dynamodb_allowed_actions, var.defaults.dynamodb_allowed_actions, ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:DeleteItem", "dynamodb:UpdateItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem"]) + elasticsearch_allowed_actions = try(each.value.elasticsearch_allowed_actions, var.defaults.elasticsearch_allowed_actions, ["es:ESHttpDelete", "es:ESHttpHead", "es:ESHttpGet", "es:ESHttpPost", "es:ESHttpPut"]) + iam_permissions_boundary = try(each.value.iam_permissions_boundary, var.defaults.iam_permissions_boundary, null) + direct_lambda_request_template = try(each.value.direct_lambda_request_template, var.defaults.direct_lambda_request_template, <<-EOF + { + "version" : "2017-02-28", + "operation": "Invoke", + "payload": { + "arguments": $util.toJson($ctx.arguments), + "identity": $util.toJson($ctx.identity), + "source": $util.toJson($ctx.source), + "request": $util.toJson($ctx.request), + "prev": $util.toJson($ctx.prev), + "info": { + "selectionSetList": $util.toJson($ctx.info.selectionSetList), + "selectionSetGraphQL": $util.toJson($ctx.info.selectionSetGraphQL), + "parentTypeName": $util.toJson($ctx.info.parentTypeName), + "fieldName": $util.toJson($ctx.info.fieldName), + "variables": $util.toJson($ctx.info.variables) + }, + "stash": $util.toJson($ctx.stash) + } + } + EOF + ) + direct_lambda_response_template = try(each.value.direct_lambda_response_template, var.defaults.direct_lambda_response_template, <<-EOF + $util.toJson($ctx.result) + EOF + ) + resolver_caching_ttl = try(each.value.resolver_caching_ttl, var.defaults.resolver_caching_ttl, 60) + datasources = try(each.value.datasources, var.defaults.datasources, {}) + resolvers = try(each.value.resolvers, var.defaults.resolvers, {}) + functions = try(each.value.functions, var.defaults.functions, {}) +} diff --git a/wrappers/outputs.tf b/wrappers/outputs.tf new file mode 100644 index 0000000..a5e5dd1 --- /dev/null +++ b/wrappers/outputs.tf @@ -0,0 +1,5 @@ +output "wrapper" { + description = "Map of outputs of a wrapper." + value = module.wrapper + sensitive = true # At least one sensitive module output (appsync_api_key_key) found (requires Terraform 0.14+) +} 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..51cad10 --- /dev/null +++ b/wrappers/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 0.13.1" +}