diff --git a/modules/vmseries/README.md b/modules/vmseries/README.md index 30e160b..ee2dd5c 100644 --- a/modules/vmseries/README.md +++ b/modules/vmseries/README.md @@ -32,7 +32,9 @@ No modules. | Name | Type | |------|------| | [google_compute_address.private](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_address) | resource | +| [google_compute_address.private_ipv6](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_address) | resource | | [google_compute_address.public](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_address) | resource | +| [google_compute_address.public_ipv6](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_address) | resource | | [google_compute_instance.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance) | resource | | [google_compute_instance_group.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance_group) | resource | | [null_resource.dependency_getter](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | @@ -56,7 +58,7 @@ No modules. | [min\_cpu\_platform](#input\_min\_cpu\_platform) | Minimum CPU platform for the compute instance. Up to date version can be found [here](https://cloud.google.com/compute/docs/instances/specify-min-cpu-platform). | `string` | `"Intel Cascade Lake"` | no | | [name](#input\_name) | Name of the VM-Series instance. | `string` | n/a | yes | | [named\_ports](#input\_named\_ports) | The list of named ports to create in the instance group:
named_ports = [
{
name = "http"
port = "80"
},
{
name = "app42"
port = "4242"
},
]
The name identifies the backend port to receive the traffic from the global load balancers.
Practically, tcp port 80 named "http" works even when not defined here, but it's not a documented provider's behavior. | `list` | `[]` | no | -| [network\_interfaces](#input\_network\_interfaces) | List of the network interface specifications.
Available options:
- `subnetwork` - (Required\|string) Self-link of a subnetwork to create interface in.
- `private_ip_name` - (Optional\|string) Name for a private address to reserve.
- `private_ip` - (Optional\|string) Private address to reserve.
- `create_public_ip` - (Optional\|boolean) Whether to reserve public IP for the interface. Ignored if `public_ip` is provided. Defaults to 'false'.
- `public_ip_name` - (Optional\|string) Name for a public address to reserve.
- `public_ip` - (Optional\|string) Existing public IP to use.
- `public_ptr_domain_name` - (Optional\|string) Existing public PTR name to use.
- `alias_ip_ranges` - (Optional\|list) List of objects that define additional IP ranges for an interface, as specified [here](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#ip_cidr_range) | `list(any)` | n/a | yes | +| [network\_interfaces](#input\_network\_interfaces) | List of the network interface specifications.
Available options:
- `subnetwork` - (Required\|string) Self-link of a subnetwork to create interface in.
- `stack_type` - (Optional\|string) IP stack to use: IPV4\_ONLY (default) or IPV4\_IPV6.
- `private_ip_name` - (Optional\|string) Name for a private IPv4 address to reserve.
- `private_ip` - (Optional\|string) Private IPv4 address to reserve.
- `create_public_ip` - (Optional\|boolean) Whether to reserve public IPv4 address for the interface. Ignored if `public_ip` is provided. Defaults to 'false'.
- `public_ip_name` - (Optional\|string) Name for a public IPv4 address to reserve.
- `public_ip` - (Optional\|string) Existing public IPv4 address to use.
- `public_ptr_domain_name` - (Optional\|string) Existing public IPv4 address PTR name to use.
- `alias_ip_ranges` - (Optional\|list) List of objects that define additional IP ranges for an interface, as specified [here](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#ip_cidr_range)
- `create_public_ipv6` - (Optional\|boolean) Whether to reserve public IPv6 address for the interface. Ignored if `public_ipv6` is provided. Defaults to 'false'.
- `private_ipv6_name` - (Optional\|string) Name for a private IPv6 address to reserve. Is relevant when a VPC has IPv6 ULA range.
- `create_private_ipv6` - (Optional\|boolean) Whether to reserve private IPv6 address for the interface. Is relevant when a VPC has IPv6 ULA range. If 'false' an ephemeral IPv6 address is assigned to the interface. Default is 'true'.
- `public_ipv6_name` - (Optional\|string) Name for a public IPv6 address to reserve.
- `public_ipv6` - (Optional\|string) Existing public IPv6 address to use. Specify address with a netmask, for example: 2600:1900:4020:bd2:8000:1::/96.
- `public_ipv6_ptr_domain_name` - (Optional\|string) Existing public IPv6 address PTR name to use. | `list(any)` | n/a | yes | | [project](#input\_project) | n/a | `string` | `null` | no | | [resource\_policies](#input\_resource\_policies) | n/a | `list(string)` | `[]` | no | | [scopes](#input\_scopes) | n/a | `list(string)` |
[
"https://www.googleapis.com/auth/compute.readonly",
"https://www.googleapis.com/auth/cloud.useraccounts.readonly",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write"
]
| no | @@ -73,6 +75,8 @@ No modules. | [instance](#output\_instance) | n/a | | [instance\_group](#output\_instance\_group) | n/a | | [instance\_group\_self\_link](#output\_instance\_group\_self\_link) | n/a | +| [ipv6\_private\_ips](#output\_ipv6\_private\_ips) | n/a | +| [ipv6\_public\_ips](#output\_ipv6\_public\_ips) | n/a | | [private\_ips](#output\_private\_ips) | n/a | | [public\_ips](#output\_public\_ips) | n/a | | [self\_link](#output\_self\_link) | n/a | diff --git a/modules/vmseries/main.tf b/modules/vmseries/main.tf index a0dffe5..3d61617 100644 --- a/modules/vmseries/main.tf +++ b/modules/vmseries/main.tf @@ -9,6 +9,17 @@ locals { } if try(v.public_ip, null) != null || local.create_public_ip[k] } + create_public_ipv6 = { + for k, v in var.network_interfaces : k => try(v.create_public_ipv6, false) + } + ipv6_access_configs = { + for k, v in var.network_interfaces : k => { + external_ipv6 = try(split("/", v.public_ipv6)[0], google_compute_address.public_ipv6[k].address, null) + external_ipv6_prefix_length = try(split("/", v.public_ipv6)[1], google_compute_address.public_ipv6[k].prefix_length, null) + public_ptr_domain_name = try(v.public_ipv6_ptr_domain_name, null) + } + if try(v.public_ipv6, null) != null || local.create_public_ipv6[k] + } } data "google_compute_image" "vmseries" { @@ -41,6 +52,21 @@ resource "google_compute_address" "private" { region = data.google_compute_subnetwork.this[each.key].region } +resource "google_compute_address" "private_ipv6" { + for_each = { for k, v in var.network_interfaces : k => v if + try(v.stack_type, "IPV4_ONLY") == "IPV4_IPV6" && + try(v.create_private_ipv6, true) == true && + local.create_public_ipv6[k] == false + } + + name = try(each.value.private_ipv6_name, "${var.name}-${each.key}-private-ipv6") + address_type = "INTERNAL" + ip_version = "IPV6" + project = var.project + subnetwork = each.value.subnetwork + region = data.google_compute_subnetwork.this[each.key].region +} + resource "google_compute_address" "public" { for_each = { for k, v in var.network_interfaces : k => v if local.create_public_ip[k] && try(v.public_ip, null) == null } @@ -50,6 +76,18 @@ resource "google_compute_address" "public" { region = data.google_compute_subnetwork.this[each.key].region } +resource "google_compute_address" "public_ipv6" { + for_each = { for k, v in var.network_interfaces : k => v if local.create_public_ipv6[k] && try(v.public_ipv6, null) == null } + + name = try(each.value.public_ipv6_name, "${var.name}-${each.key}-public-ipv6") + address_type = "EXTERNAL" + ip_version = "IPV6" + ipv6_endpoint_type = "VM" + subnetwork = each.value.subnetwork + project = var.project + region = data.google_compute_subnetwork.this[each.key].region +} + resource "google_compute_instance" "this" { name = var.name @@ -82,8 +120,10 @@ resource "google_compute_instance" "this" { for_each = var.network_interfaces content { - network_ip = google_compute_address.private[network_interface.key].address - subnetwork = network_interface.value.subnetwork + stack_type = try(network_interface.value.stack_type, "IPV4_ONLY") + network_ip = google_compute_address.private[network_interface.key].address + ipv6_address = try(google_compute_address.private_ipv6[network_interface.key].address, null) + subnetwork = network_interface.value.subnetwork dynamic "access_config" { for_each = try(local.access_configs[network_interface.key] != null, false) ? ["one"] : [] @@ -100,6 +140,16 @@ resource "google_compute_instance" "this" { subnetwork_range_name = try(alias_ip_range.value.subnetwork_range_name, null) } } + + dynamic "ipv6_access_config" { + for_each = try(local.ipv6_access_configs[network_interface.key] != null, false) ? ["one"] : [] + content { + external_ipv6 = try(local.ipv6_access_configs[network_interface.key].external_ipv6, null) + external_ipv6_prefix_length = try(local.ipv6_access_configs[network_interface.key].external_ipv6_prefix_length, null) + network_tier = "PREMIUM" + public_ptr_domain_name = try(local.ipv6_access_configs[network_interface.key].public_ptr_domain_name, null) + } + } } } diff --git a/modules/vmseries/outputs.tf b/modules/vmseries/outputs.tf index a6c866f..25ae2e6 100644 --- a/modules/vmseries/outputs.tf +++ b/modules/vmseries/outputs.tf @@ -18,6 +18,16 @@ output "private_ips" { value = { for k, v in google_compute_instance.this.network_interface : k => v.network_ip } } +output "ipv6_private_ips" { + value = { for k, v in google_compute_instance.this.network_interface : k => v.ipv6_address } +} + output "public_ips" { value = { for k, v in google_compute_instance.this.network_interface : k => v.access_config[0].nat_ip if length(v.access_config) != 0 } } + +output "ipv6_public_ips" { + value = { for k, v in google_compute_instance.this.network_interface : + k => "${v.ipv6_access_config[0].external_ipv6}/${v.ipv6_access_config[0].external_ipv6_prefix_length}" if length(v.ipv6_access_config) != 0 + } +} \ No newline at end of file diff --git a/modules/vmseries/variables.tf b/modules/vmseries/variables.tf index 104f466..cd00d3d 100644 --- a/modules/vmseries/variables.tf +++ b/modules/vmseries/variables.tf @@ -17,14 +17,21 @@ variable "network_interfaces" { description = <<-EOF List of the network interface specifications. Available options: - - `subnetwork` - (Required|string) Self-link of a subnetwork to create interface in. - - `private_ip_name` - (Optional|string) Name for a private address to reserve. - - `private_ip` - (Optional|string) Private address to reserve. - - `create_public_ip` - (Optional|boolean) Whether to reserve public IP for the interface. Ignored if `public_ip` is provided. Defaults to 'false'. - - `public_ip_name` - (Optional|string) Name for a public address to reserve. - - `public_ip` - (Optional|string) Existing public IP to use. - - `public_ptr_domain_name` - (Optional|string) Existing public PTR name to use. - - `alias_ip_ranges` - (Optional|list) List of objects that define additional IP ranges for an interface, as specified [here](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#ip_cidr_range) + - `subnetwork` - (Required|string) Self-link of a subnetwork to create interface in. + - `stack_type` - (Optional|string) IP stack to use: IPV4_ONLY (default) or IPV4_IPV6. + - `private_ip_name` - (Optional|string) Name for a private IPv4 address to reserve. + - `private_ip` - (Optional|string) Private IPv4 address to reserve. + - `create_public_ip` - (Optional|boolean) Whether to reserve public IPv4 address for the interface. Ignored if `public_ip` is provided. Defaults to 'false'. + - `public_ip_name` - (Optional|string) Name for a public IPv4 address to reserve. + - `public_ip` - (Optional|string) Existing public IPv4 address to use. + - `public_ptr_domain_name` - (Optional|string) Existing public IPv4 address PTR name to use. + - `alias_ip_ranges` - (Optional|list) List of objects that define additional IP ranges for an interface, as specified [here](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#ip_cidr_range) + - `create_public_ipv6` - (Optional|boolean) Whether to reserve public IPv6 address for the interface. Ignored if `public_ipv6` is provided. Defaults to 'false'. + - `private_ipv6_name` - (Optional|string) Name for a private IPv6 address to reserve. Is relevant when a VPC has IPv6 ULA range. + - `create_private_ipv6` - (Optional|boolean) Whether to reserve private IPv6 address for the interface. Is relevant when a VPC has IPv6 ULA range. If 'false' an ephemeral IPv6 address is assigned to the interface. Default is 'true'. + - `public_ipv6_name` - (Optional|string) Name for a public IPv6 address to reserve. + - `public_ipv6` - (Optional|string) Existing public IPv6 address to use. Specify address with a netmask, for example: 2600:1900:4020:bd2:8000:1::/96. + - `public_ipv6_ptr_domain_name` - (Optional|string) Existing public IPv6 address PTR name to use. EOF type = list(any) }