diff --git a/README.md b/README.md index cbef2a5d..69463978 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,23 @@ This module creates the following IBM Cloud® Virtual Private Cloud (VPC) net ![vpc-module](https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/main/.docs/vpc-module.png) + + +### Upgrade notice for Hub-and-Spoke topology users (version 8.0.0 and above) + +> **Note:** This upgrade notice applies **only** to users of the advanced Hub-and-Spoke VPC topology who are upgrading from a previous version of this module to v8.0.0 or later. If you are using the standard topology, or a new user starting with v8.0.0 or above, you can safely ignore this section. + +If you are upgrading, note that the `ibm_is_vpc_dns_resolution_binding` resources are no longer used for DNS resolution binding with the `Delegated` resolver type. + +- Upgrade to the latest module (>= `v8.0.0`). +- Set `update_delegated_resolver = true` in your Terraform configuration (along with any other input parameters you previously used) and run `terraform apply` to re-create the DNS resolution binding with the `Delegated` resolver type. For example: + +```bash +terraform apply -var="update_delegated_resolver=true" +``` + +Expected network connectivity downtime of typically around 20 seconds. + ## Overview @@ -177,6 +194,7 @@ To attach access management tags to resources in this module, you need the follo | [ibm_is_subnet.subnet](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_subnet) | data source | | [ibm_is_vpc.vpc](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_vpc) | data source | | [ibm_is_vpc_address_prefixes.get_address_prefixes](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_vpc_address_prefixes) | data source | +| [ibm_is_vpc_dns_resolution_bindings.dns_bindings](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_vpc_dns_resolution_bindings) | data source | ### Inputs @@ -220,7 +238,7 @@ To attach access management tags to resources in this module, you need the follo | [prefix](#input\_prefix) | The value that you would like to prefix to the name of the resources provisioned by this module. Explicitly set to null if you do not wish to use a prefix. This value is ignored if using one of the optional variables for explicit control over naming. | `string` | `null` | no | | [public\_gateway\_name](#input\_public\_gateway\_name) | The name to give the provisioned VPC public gateways. If not set, the module generates a name based on the `prefix` and `name` variables. | `string` | `null` | no | | [region](#input\_region) | The region to which to deploy the VPC | `string` | n/a | yes | -| [resolver\_type](#input\_resolver\_type) | Resolver type. Can be system or manual. For delegated resolver type, see the update\_delegated\_resolver variable instead. | `string` | `null` | no | +| [resolver\_type](#input\_resolver\_type) | Resolver type. Can be system or manual or delegated. | `string` | `null` | no | | [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where the VPC to be created | `string` | n/a | yes | | [routes](#input\_routes) | OPTIONAL - Allows you to specify the next hop for packets based on their destination address |
list(
object({
name = string
route_direct_link_ingress = optional(bool)
route_transit_gateway_ingress = optional(bool)
route_vpc_zone_ingress = optional(bool)
routes = optional(
list(
object({
action = optional(string)
zone = number
destination = string
next_hop = string
})
))
})
)
| `[]` | no | | [routing\_table\_name](#input\_routing\_table\_name) | The name to give the provisioned routing tables. If not set, the module generates a name based on the `prefix` and `name` variables. | `string` | `null` | no | @@ -242,8 +260,8 @@ To attach access management tags to resources in this module, you need the follo | [cidr\_blocks](#output\_cidr\_blocks) | List of CIDR blocks present in VPC stack | | [custom\_resolver\_hub](#output\_custom\_resolver\_hub) | The custom resolver created for the hub vpc. Only set if enable\_hub is set and skip\_custom\_resolver\_hub\_creation is false. | | [dns\_custom\_resolver\_id](#output\_dns\_custom\_resolver\_id) | The ID of the DNS Custom Resolver. | -| [dns\_endpoint\_gateways\_by\_crn](#output\_dns\_endpoint\_gateways\_by\_crn) | The list of VPEs that are made available for DNS resolution in the created VPC. Only set if enable\_hub is false and enable\_hub\_vpc\_id are true. | -| [dns\_endpoint\_gateways\_by\_id](#output\_dns\_endpoint\_gateways\_by\_id) | The list of VPEs that are made available for DNS resolution in the created VPC. Only set if enable\_hub is false and enable\_hub\_vpc\_id are true. | +| [dns\_endpoint\_gateways\_by\_crn](#output\_dns\_endpoint\_gateways\_by\_crn) | The list of VPEs that are made available for DNS resolution in the created Spoke VPC. Only set if enable\_hub is false and enable\_hub\_vpc\_id OR enable\_hub\_vpc\_crn are true. | +| [dns\_endpoint\_gateways\_by\_id](#output\_dns\_endpoint\_gateways\_by\_id) | The list of VPEs that are made available for DNS resolution in the created Spoke VPC. Only set if enable\_hub is false and enable\_hub\_vpc\_id OR enable\_hub\_vpc\_crn are true. | | [dns\_instance\_id](#output\_dns\_instance\_id) | The ID of the DNS instance. | | [dns\_record\_ids](#output\_dns\_record\_ids) | List of all the domain resource records. | | [dns\_zone](#output\_dns\_zone) | A map representing DNS zone information. | diff --git a/examples/hub-spoke-delegated-resolver/README.md b/examples/hub-spoke-delegated-resolver/README.md index c364b9bd..056435b8 100644 --- a/examples/hub-spoke-delegated-resolver/README.md +++ b/examples/hub-spoke-delegated-resolver/README.md @@ -12,6 +12,4 @@ This example demonstrates how to deploy hub and spoke VPCs, inclusive of enablin 1. The first terraform apply lay down all of the topology, but does not configure the DNS resolver to delegated in the spoke 2. The second terraform apply should have the update_delegated_resolver variable to true to configure the DNS resolver to be delegated ```terraform apply -var=update_delegated_resolver=true``` -In order to perform a successful destroy, please set to the resolver to "system" in the spoke VPC through the UI before issuing the terraform destroy - see https://cloud.ibm.com/docs/solution-tutorials?topic=solution-tutorials-vpc-transit2 - You may also be interested in the [Hub and Spoke VPC with manual DNS resolver Example](../hub-spoke-manual-resolver/) which does not exhibit those issues. diff --git a/examples/hub-spoke-delegated-resolver/main.tf b/examples/hub-spoke-delegated-resolver/main.tf index 9c65f95b..7005039a 100644 --- a/examples/hub-spoke-delegated-resolver/main.tf +++ b/examples/hub-spoke-delegated-resolver/main.tf @@ -79,6 +79,7 @@ module "spoke_vpc" { hub_account_id = data.ibm_iam_account_settings.iam_account_settings.account_id hub_vpc_crn = module.hub_vpc.vpc_crn enable_hub_vpc_crn = true + resolver_type = "delegated" update_delegated_resolver = var.update_delegated_resolver subnets = { zone-1 = [ diff --git a/main.tf b/main.tf index d908f2a0..b48a4911 100644 --- a/main.tf +++ b/main.tf @@ -45,11 +45,15 @@ resource "ibm_is_vpc" "vpc" { # Delegated resolver dynamic "resolver" { - for_each = (var.enable_hub_vpc_id || var.enable_hub_vpc_crn) && var.update_delegated_resolver ? [1] : [] + for_each = (var.enable_hub_vpc_id || var.enable_hub_vpc_crn) && var.update_delegated_resolver && var.resolver_type == "delegated" ? [1] : [] content { type = "delegated" vpc_id = var.hub_vpc_id != null ? var.hub_vpc_id : null vpc_crn = var.hub_vpc_crn != null ? var.hub_vpc_crn : null + dns_binding_name = coalesce( + var.dns_binding_name, + "${var.prefix != null ? "${var.prefix}-${var.name}" : var.name}-dns-binding" + ) } } @@ -78,6 +82,11 @@ resource "ibm_is_vpc" "vpc" { } } +data "ibm_is_vpc_dns_resolution_bindings" "dns_bindings" { + count = (!var.enable_hub && (var.enable_hub_vpc_id || var.enable_hub_vpc_crn)) ? 1 : 0 + vpc_id = local.vpc_id +} + ############################################################################### ############################################################################## @@ -124,9 +133,9 @@ resource "ibm_iam_authorization_policy" "vpc_dns_resolution_auth_policy" { } } -# Enable Hub to dns resolve in spoke VPC +# Set up separate DNS resolution binding in case the resolver type is NOT delegated. resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" { - count = (var.enable_hub == false && var.enable_hub_vpc_id) ? 1 : 0 + count = (var.enable_hub == false && var.enable_hub_vpc_id) && var.resolver_type != "delegated" ? 1 : 0 # Depends on required as the authorization policy cannot be directly referenced depends_on = [ibm_iam_authorization_policy.vpc_dns_resolution_auth_policy] @@ -141,8 +150,9 @@ resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" { } } +# Set up separate DNS resolution binding in case the resolver type is NOT delegated. resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_crn" { - count = (var.enable_hub == false && var.enable_hub_vpc_crn) ? 1 : 0 + count = (var.enable_hub == false && var.enable_hub_vpc_crn) && var.resolver_type != "delegated" ? 1 : 0 # Depends on required as the authorization policy cannot be directly referenced depends_on = [ibm_iam_authorization_policy.vpc_dns_resolution_auth_policy] diff --git a/outputs.tf b/outputs.tf index 6492835a..815e8af7 100644 --- a/outputs.tf +++ b/outputs.tf @@ -158,13 +158,13 @@ output "custom_resolver_hub" { } output "dns_endpoint_gateways_by_id" { - description = "The list of VPEs that are made available for DNS resolution in the created VPC. Only set if enable_hub is false and enable_hub_vpc_id are true." - value = length(ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_id) == 1 ? ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_id[0] : null + description = "The list of VPEs that are made available for DNS resolution in the created Spoke VPC. Only set if enable_hub is false and enable_hub_vpc_id OR enable_hub_vpc_crn are true." + value = try(length(data.ibm_is_vpc_dns_resolution_bindings.dns_bindings) == 1 ? data.ibm_is_vpc_dns_resolution_bindings.dns_bindings[0].dns_resolution_bindings[0].vpc[0].id : null, null) } output "dns_endpoint_gateways_by_crn" { - description = "The list of VPEs that are made available for DNS resolution in the created VPC. Only set if enable_hub is false and enable_hub_vpc_id are true." - value = length(ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_crn) == 1 ? ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_crn[0] : null + description = "The list of VPEs that are made available for DNS resolution in the created Spoke VPC. Only set if enable_hub is false and enable_hub_vpc_id OR enable_hub_vpc_crn are true." + value = try(length(data.ibm_is_vpc_dns_resolution_bindings.dns_bindings) == 1 ? data.ibm_is_vpc_dns_resolution_bindings.dns_bindings[0].dns_resolution_bindings[0].vpc[0].crn : null, null) } output "dns_instance_id" { diff --git a/tests/other_test.go b/tests/other_test.go index 8027efdb..058aae85 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -24,22 +24,6 @@ func TestRunBasicExample(t *testing.T) { assert.NotNil(t, output, "Expected some output") } -func TestRunHubAndSpokeDelegatedExample(t *testing.T) { - t.Parallel() - - options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ - Testing: t, - TerraformDir: hubAndSpokeDelegatedExampleTerraformDir, - Prefix: "has-slz", - ResourceGroup: resourceGroup, - Region: "us-south", - }) - - output, err := options.RunTestConsistency() - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") -} - func TestRunSpecificZoneExample(t *testing.T) { t.Parallel() diff --git a/tests/pr_test.go b/tests/pr_test.go index 260fb03d..d4036251 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -322,3 +322,25 @@ func TestRunUpgradeFullyConfigurable(t *testing.T) { assert.Nil(t, err, "This should not have errored") } } + +func TestRunHubAndSpokeDelegatedExample(t *testing.T) { + t.Parallel() + + options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ + Testing: t, + TerraformDir: hubAndSpokeDelegatedExampleTerraformDir, + Prefix: "has-slz", + ResourceGroup: resourceGroup, + Region: "us-south", + PostApplyHook: func(options *testhelper.TestOptions) error { + terraformOptions := options.TerraformOptions + terraformOptions.Vars["update_delegated_resolver"] = true + _, err := terraform.ApplyE(options.Testing, terraformOptions) + return err + }, + }) + + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") +} diff --git a/variables.tf b/variables.tf index ce79b4a4..40b9bafb 100644 --- a/variables.tf +++ b/variables.tf @@ -641,8 +641,8 @@ variable "update_delegated_resolver" { default = false validation { - condition = !(var.update_delegated_resolver == true && var.resolver_type != null) - error_message = "var.resolver_type cannot be set if var.update_delegated_resolver is true. Only one type of resolver can be created by VPC." + condition = !(var.update_delegated_resolver == true && var.resolver_type != "delegated") + error_message = "If var.update_delegated_resolver is true then var.resolver_type must be set to 'delegated'." } } @@ -665,7 +665,7 @@ variable "use_existing_dns_instance" { } variable "resolver_type" { - description = "Resolver type. Can be system or manual. For delegated resolver type, see the update_delegated_resolver variable instead. " + description = "Resolver type. Can be system or manual or delegated." type = string default = null validation { @@ -673,8 +673,9 @@ variable "resolver_type" { var.resolver_type == null, var.resolver_type == "system", var.resolver_type == "manual", + var.resolver_type == "delegated" ]) - error_message = "`resolver_type` can either be null, or set to the string 'system' or 'manual'." + error_message = "`resolver_type` can either be null, or set to the string 'system', 'delegated' or 'manual'." } }