diff --git a/README.md b/README.md index 7be9f6f..2fba1ab 100644 --- a/README.md +++ b/README.md @@ -113,13 +113,13 @@ The IPAM `operating_region` variable must be set for the primary Region in your | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.0 | -| [aws](#requirement\_aws) | >= 3.73.0 | +| [aws](#requirement\_aws) | >= 4.53.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 3.73.0 | +| [aws](#provider\_aws) | >= 4.53.0 | ## Modules @@ -146,12 +146,13 @@ The IPAM `operating_region` variable must be set for the primary Region in your | [create\_ipam](#input\_create\_ipam) | Determines whether to create an IPAM. If `false`, you must also provide a var.ipam\_scope\_id. | `bool` | `true` | no | | [ipam\_scope\_id](#input\_ipam\_scope\_id) | (Optional) Required if `var.ipam_id` is set. Determines which scope to deploy pools into. | `string` | `null` | no | | [ipam\_scope\_type](#input\_ipam\_scope\_type) | Which scope type to use. Valid inputs include `public` or `private`. You can alternatively provide your own scope ID. | `string` | `"private"` | no | -| [pool\_configurations](#input\_pool\_configurations) | A multi-level, nested map describing nested IPAM pools. Can nest up to three levels with the top level being outside the `pool_configurations` in vars prefixed `top_`. If arugument descriptions are omitted, you can find them in the [official documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipam_pool#argument-reference).

- `ram_share_principals` = (optional, list(string)) of valid organization principals to create ram shares to.
- `name` = (optional, string) name to give the pool, the key of your map in var.pool\_configurations will be used if omitted.
- `description` = (optional, string) description to give the pool, the key of your map in var.pool\_configurations will be used if omitted.
- `cidr` = (optional, list(string)) list of CIDRs to provision into pool.

- `locale` = (optional, string) locale to set for pool.
- `auto_import` = (optional, string)
- `tags` = (optional, map(string))
- `allocation_default_netmask_length` = (optional, string)
- `allocation_max_netmask_length` = (optional, string)
- `allocation_min_netmask_length` = (optional, string)
- `allocation_resource_tags` = (optional, map(string))

The following arguments are available but only relevant for public ips
- `cidr_authorization_context` = (optional, map(string)) Details found in [official documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipam_pool_cidr#cidr_authorization_context).
- `aws_service` = (optional, string)
- `publicly_advertisable` = (optional, bool)

- `sub_pools` = (nested repeats of pool\_configuration object above) | `any` | `{}` | no | +| [pool\_configurations](#input\_pool\_configurations) | A multi-level, nested map describing nested IPAM pools. Can nest up to three levels with the top level being outside the `pool_configurations` in vars prefixed `top_`. If arugument descriptions are omitted, you can find them in the [official documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipam_pool#argument-reference).

- `ram_share_principals` = (optional, list(string)) of valid organization principals to create ram shares to.
- `name` = (optional, string) name to give the pool, the key of your map in var.pool\_configurations will be used if omitted.
- `description` = (optional, string) description to give the pool, the key of your map in var.pool\_configurations will be used if omitted.
- `cidr` = (optional, list(string)) list of CIDRs to provision into pool. Conflicts with `netmask_length`.
- `netmask_length` = (optional, number) netmask length to request provisioned into pool. Conflicts with `cidr`.

- `locale` = (optional, string) locale to set for pool.
- `auto_import` = (optional, string)
- `tags` = (optional, map(string))
- `allocation_default_netmask_length` = (optional, string)
- `allocation_max_netmask_length` = (optional, string)
- `allocation_min_netmask_length` = (optional, string)
- `allocation_resource_tags` = (optional, map(string))

The following arguments are available but only relevant for public ips
- `cidr_authorization_context` = (optional, map(string)) Details found in [official documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipam_pool_cidr#cidr_authorization_context).
- `aws_service` = (optional, string)
- `publicly_advertisable` = (optional, bool)

- `sub_pools` = (nested repeats of pool\_configuration object above) | `any` | `{}` | no | | [tags](#input\_tags) | Tags to add to the aws\_vpc\_ipam resource. | `any` | `{}` | no | | [top\_auto\_import](#input\_top\_auto\_import) | `auto_import` setting for top-level pool. | `bool` | `null` | no | | [top\_cidr\_authorization\_context](#input\_top\_cidr\_authorization\_context) | A signed document that proves that you are authorized to bring the specified IP address range to Amazon using BYOIP. Document is not stored in the state file. For more information, refer to https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipam_pool_cidr#cidr_authorization_context. | `any` | `null` | no | | [top\_description](#input\_top\_description) | Description of top-level pool. | `string` | `""` | no | | [top\_name](#input\_top\_name) | Name of top-level pool. | `string` | `null` | no | +| [top\_netmask\_length](#input\_top\_netmask\_length) | Top-level netmask length to request. Not possible to use for IPv4. Only possible to use with amazon provided ipv6. | `number` | `null` | no | | [top\_ram\_share\_principals](#input\_top\_ram\_share\_principals) | Principals to create RAM shares for top-level pool. | `list(string)` | `null` | no | ## Outputs diff --git a/examples/single_scope_ipv4/README.md b/examples/single_scope_ipv4/README.md index 9174a32..17dc434 100644 --- a/examples/single_scope_ipv4/README.md +++ b/examples/single_scope_ipv4/README.md @@ -9,10 +9,7 @@ The example code shows you how to deploy IPAM with pools in 2 regions. The compa ## Requirements -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | >= 0.15.0 | -| [aws](#requirement\_aws) | >= 3.73.0 | +No requirements. ## Providers diff --git a/examples/single_scope_ipv4/main.tf b/examples/single_scope_ipv4/main.tf index 644a801..d36053c 100644 --- a/examples/single_scope_ipv4/main.tf +++ b/examples/single_scope_ipv4/main.tf @@ -27,17 +27,17 @@ module "basic" { } } dev = { - cidr = ["10.1.0.0/20"] + netmask_length = 20 sub_pools = { team_a = { - cidr = ["10.1.0.0/24"] + netmask_length = 24 ram_share_principals = var.prod_account # prod account locale = "us-west-2" } team_b = { - cidr = ["10.1.1.0/24"] + netmask_length = 26 ram_share_principals = var.prod_account # prod account } } diff --git a/main.tf b/main.tf index ed5f5e3..c788beb 100644 --- a/main.tf +++ b/main.tf @@ -53,6 +53,7 @@ module "level_zero" { description = var.top_description cidr_authorization_context = var.top_cidr_authorization_context name = var.top_name + netmask_length = var.top_netmask_length } } diff --git a/modules/sub_pool/README.md b/modules/sub_pool/README.md index 92cb350..682c0a4 100644 --- a/modules/sub_pool/README.md +++ b/modules/sub_pool/README.md @@ -4,13 +4,13 @@ | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.0 | -| [aws](#requirement\_aws) | >= 3.73.0 | +| [aws](#requirement\_aws) | >= 4.53.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 3.73.0 | +| [aws](#provider\_aws) | >= 4.53.0 | ## Modules @@ -32,7 +32,7 @@ No modules. |------|-------------|------|---------|:--------:| | [address\_family](#input\_address\_family) | IPv4/6 address family. | `string` | n/a | yes | | [ipam\_scope\_id](#input\_ipam\_scope\_id) | IPAM Scope ID to attach the pool to. | `string` | n/a | yes | -| [pool\_config](#input\_pool\_config) | Configuration of the Pool you want to deploy. All aws\_vpc\_ipam\_pool arguments are available as well as ram\_share\_principals list and sub\_pools map (up to 3 levels). |
object({
cidr = list(string)
ram_share_principals = optional(list(string))

locale = optional(string)
allocation_default_netmask_length = optional(string)
allocation_max_netmask_length = optional(string)
allocation_min_netmask_length = optional(string)
auto_import = optional(string)
aws_service = optional(string)
description = optional(string)
name = optional(string)
publicly_advertisable = optional(bool)

allocation_resource_tags = optional(map(string))
tags = optional(map(string))
cidr_authorization_context = optional(map(string))

sub_pools = optional(any)
})
| n/a | yes | +| [pool\_config](#input\_pool\_config) | Configuration of the Pool you want to deploy. All aws\_vpc\_ipam\_pool arguments are available as well as ram\_share\_principals list and sub\_pools map (up to 3 levels). |
object({
cidr = optional(list(string))
ram_share_principals = optional(list(string))

locale = optional(string)
allocation_default_netmask_length = optional(string)
allocation_max_netmask_length = optional(string)
allocation_min_netmask_length = optional(string)
auto_import = optional(string)
aws_service = optional(string)
description = optional(string)
name = optional(string)
netmask_length = optional(number)
publicly_advertisable = optional(bool)

allocation_resource_tags = optional(map(string))
tags = optional(map(string))
cidr_authorization_context = optional(map(string))

sub_pools = optional(any)
})
| n/a | yes | | [source\_ipam\_pool\_id](#input\_source\_ipam\_pool\_id) | IPAM parent pool ID to attach the pool to. | `string` | n/a | yes | | [implied\_description](#input\_implied\_description) | Description is implied from the pool tree name / unless specified on the pool\_config. | `string` | `null` | no | | [implied\_locale](#input\_implied\_locale) | Locale is implied from a parent pool even if another is specified. Its not possible to set child pools to different locales. | `string` | `"None"` | no | diff --git a/modules/sub_pool/main.tf b/modules/sub_pool/main.tf index 17d5445..0767856 100644 --- a/modules/sub_pool/main.tf +++ b/modules/sub_pool/main.tf @@ -7,6 +7,7 @@ locals { ) ram_share_enabled = try(length(var.pool_config.ram_share_principals), 0) > 0 + pool_cidrs = var.pool_config.cidr == null ? [var.pool_config.netmask_length] : var.pool_config.cidr } resource "aws_vpc_ipam_pool" "sub" { @@ -28,10 +29,11 @@ resource "aws_vpc_ipam_pool" "sub" { } resource "aws_vpc_ipam_pool_cidr" "sub" { - for_each = toset(var.pool_config.cidr) + for_each = toset(local.pool_cidrs) - ipam_pool_id = aws_vpc_ipam_pool.sub.id - cidr = each.key + ipam_pool_id = aws_vpc_ipam_pool.sub.id + cidr = length(regexall("/", each.key)) > 0 ? each.key : null + netmask_length = length(regexall("/", each.key)) == 0 ? each.key : null dynamic "cidr_authorization_context" { for_each = var.pool_config.cidr_authorization_context == null ? [] : [1] diff --git a/examples/single_scope_ipv4/versions.tf b/modules/sub_pool/providers.tf similarity index 81% rename from examples/single_scope_ipv4/versions.tf rename to modules/sub_pool/providers.tf index 7f884e2..e0c44d5 100644 --- a/examples/single_scope_ipv4/versions.tf +++ b/modules/sub_pool/providers.tf @@ -3,7 +3,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 3.73.0" + version = ">= 4.53.0" } } } diff --git a/modules/sub_pool/variables.tf b/modules/sub_pool/variables.tf index 2e6b1df..983a963 100644 --- a/modules/sub_pool/variables.tf +++ b/modules/sub_pool/variables.tf @@ -1,7 +1,7 @@ variable "pool_config" { description = "Configuration of the Pool you want to deploy. All aws_vpc_ipam_pool arguments are available as well as ram_share_principals list and sub_pools map (up to 3 levels)." type = object({ - cidr = list(string) + cidr = optional(list(string)) ram_share_principals = optional(list(string)) locale = optional(string) @@ -12,6 +12,7 @@ variable "pool_config" { aws_service = optional(string) description = optional(string) name = optional(string) + netmask_length = optional(number) publicly_advertisable = optional(bool) allocation_resource_tags = optional(map(string)) @@ -21,18 +22,13 @@ variable "pool_config" { sub_pools = optional(any) }) - # Validation to ensure keys - # if specify type = object() keys are silently dropped, no validation required but also no error if improper keys - # if speicy type = any we can validate which provides an error opportunity BUT values are not defaulted, makes code complex - # validation { - # condition = (length(setsubtract(keys(var.pool_config), [ - # "name", "cidr", "locale", "ram_share_principals", "auto_import", "aws_service", "description", - # "publicly_advertisable", "allocation_resource_tags", "tags", "cidr_authorization_context", - # "sub_pools", "allocation_default_netmask_length", "allocation_max_netmask_length", - # "allocation_min_netmask_length"] - # )) == 0) - # error_message = "Can only accept certain parameters. See modules/sub_pool/variables.tf for `pool_config` options." - # } + validation { + condition = anytrue([ + (var.pool_config.cidr != null && var.pool_config.netmask_length == null), + (var.pool_config.cidr == null && var.pool_config.netmask_length != null) + ]) + error_message = "Pool Name: ${var.pool_config.name == null ? "Unamed" : var.pool_config.name} - must define exactly one of `cidr` or `netmask_length`." + } } variable "implied_locale" { diff --git a/modules/sub_pool/versions.tf b/providers.tf similarity index 81% rename from modules/sub_pool/versions.tf rename to providers.tf index 7f884e2..e0c44d5 100644 --- a/modules/sub_pool/versions.tf +++ b/providers.tf @@ -3,7 +3,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 3.73.0" + version = ">= 4.53.0" } } } diff --git a/test/examples_single_scope_ipv4_test.go b/test/examples_single_scope_ipv4_test.go index dd843a1..e254de1 100644 --- a/test/examples_single_scope_ipv4_test.go +++ b/test/examples_single_scope_ipv4_test.go @@ -32,4 +32,5 @@ func TestExamplesIPv4Basic(t *testing.T) { defer terraform.Destroy(t, terraformOptions) terraform.InitAndApply(t, terraformOptions) + terraform.ApplyAndIdempotent(t, terraformOptions) } diff --git a/variables.tf b/variables.tf index 515b850..b95a554 100644 --- a/variables.tf +++ b/variables.tf @@ -7,7 +7,8 @@ variable "pool_configurations" { - `ram_share_principals` = (optional, list(string)) of valid organization principals to create ram shares to. - `name` = (optional, string) name to give the pool, the key of your map in var.pool_configurations will be used if omitted. - `description` = (optional, string) description to give the pool, the key of your map in var.pool_configurations will be used if omitted. - - `cidr` = (optional, list(string)) list of CIDRs to provision into pool. + - `cidr` = (optional, list(string)) list of CIDRs to provision into pool. Conflicts with `netmask_length`. + - `netmask_length` = (optional, number) netmask length to request provisioned into pool. Conflicts with `cidr`. - `locale` = (optional, string) locale to set for pool. - `auto_import` = (optional, string) @@ -31,6 +32,12 @@ variable "top_cidr" { type = list(string) } +variable "top_netmask_length" { + description = "Top-level netmask length to request. Not possible to use for IPv4. Only possible to use with amazon provided ipv6." + type = number + default = null +} + variable "top_ram_share_principals" { description = "Principals to create RAM shares for top-level pool." type = list(string) diff --git a/versions.tf b/versions.tf deleted file mode 100644 index 7f884e2..0000000 --- a/versions.tf +++ /dev/null @@ -1,9 +0,0 @@ -terraform { - required_version = ">= 1.3.0" - required_providers { - aws = { - source = "hashicorp/aws" - version = ">= 3.73.0" - } - } -}