Skip to content

Commit 270db88

Browse files
fix: fixed bug which was causing the error 'CreateVPCDnsResolutionBindingWithContext failed: This VPC already contains DNS Resolution Bindings' (#1010)
BREAKING CHANGE: See [Upgrade notice for Hub-and-Spoke topology users (version 8.0.0 and above)](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/tree/main?tab=readme-ov-file#upgrade-notice-for-hub-and-spoke-topology-users-version-800-and-above)
1 parent e211201 commit 270db88

File tree

8 files changed

+67
-33
lines changed

8 files changed

+67
-33
lines changed

README.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@ This module creates the following IBM Cloud® Virtual Private Cloud (VPC) net
1818

1919
![vpc-module](https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/main/.docs/vpc-module.png)
2020

21+
22+
23+
### Upgrade notice for Hub-and-Spoke topology users (version 8.0.0 and above)
24+
25+
> **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.
26+
27+
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.
28+
29+
- Upgrade to the latest module (>= `v8.0.0`).
30+
- 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:
31+
32+
```bash
33+
terraform apply -var="update_delegated_resolver=true"
34+
```
35+
36+
Expected network connectivity downtime of typically around 20 seconds.
37+
2138
<!-- Below content is automatically populated via pre-commit hook -->
2239
<!-- BEGIN OVERVIEW HOOK -->
2340
## Overview
@@ -177,6 +194,7 @@ To attach access management tags to resources in this module, you need the follo
177194
| [ibm_is_subnet.subnet](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_subnet) | data source |
178195
| [ibm_is_vpc.vpc](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_vpc) | data source |
179196
| [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 |
197+
| [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 |
180198

181199
### Inputs
182200

@@ -220,7 +238,7 @@ To attach access management tags to resources in this module, you need the follo
220238
| <a name="input_prefix"></a> [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 |
221239
| <a name="input_public_gateway_name"></a> [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 |
222240
| <a name="input_region"></a> [region](#input\_region) | The region to which to deploy the VPC | `string` | n/a | yes |
223-
| <a name="input_resolver_type"></a> [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 |
241+
| <a name="input_resolver_type"></a> [resolver\_type](#input\_resolver\_type) | Resolver type. Can be system or manual or delegated. | `string` | `null` | no |
224242
| <a name="input_resource_group_id"></a> [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where the VPC to be created | `string` | n/a | yes |
225243
| <a name="input_routes"></a> [routes](#input\_routes) | OPTIONAL - Allows you to specify the next hop for packets based on their destination address | <pre>list(<br/> object({<br/> name = string<br/> route_direct_link_ingress = optional(bool)<br/> route_transit_gateway_ingress = optional(bool)<br/> route_vpc_zone_ingress = optional(bool)<br/> routes = optional(<br/> list(<br/> object({<br/> action = optional(string)<br/> zone = number<br/> destination = string<br/> next_hop = string<br/> })<br/> ))<br/> })<br/> )</pre> | `[]` | no |
226244
| <a name="input_routing_table_name"></a> [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
242260
| <a name="output_cidr_blocks"></a> [cidr\_blocks](#output\_cidr\_blocks) | List of CIDR blocks present in VPC stack |
243261
| <a name="output_custom_resolver_hub"></a> [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. |
244262
| <a name="output_dns_custom_resolver_id"></a> [dns\_custom\_resolver\_id](#output\_dns\_custom\_resolver\_id) | The ID of the DNS Custom Resolver. |
245-
| <a name="output_dns_endpoint_gateways_by_crn"></a> [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. |
246-
| <a name="output_dns_endpoint_gateways_by_id"></a> [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. |
263+
| <a name="output_dns_endpoint_gateways_by_crn"></a> [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. |
264+
| <a name="output_dns_endpoint_gateways_by_id"></a> [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. |
247265
| <a name="output_dns_instance_id"></a> [dns\_instance\_id](#output\_dns\_instance\_id) | The ID of the DNS instance. |
248266
| <a name="output_dns_record_ids"></a> [dns\_record\_ids](#output\_dns\_record\_ids) | List of all the domain resource records. |
249267
| <a name="output_dns_zone"></a> [dns\_zone](#output\_dns\_zone) | A map representing DNS zone information. |

examples/hub-spoke-delegated-resolver/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,4 @@ This example demonstrates how to deploy hub and spoke VPCs, inclusive of enablin
1212
1. The first terraform apply lay down all of the topology, but does not configure the DNS resolver to delegated in the spoke
1313
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```
1414

15-
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
16-
1715
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.

examples/hub-spoke-delegated-resolver/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ module "spoke_vpc" {
7979
hub_account_id = data.ibm_iam_account_settings.iam_account_settings.account_id
8080
hub_vpc_crn = module.hub_vpc.vpc_crn
8181
enable_hub_vpc_crn = true
82+
resolver_type = "delegated"
8283
update_delegated_resolver = var.update_delegated_resolver
8384
subnets = {
8485
zone-1 = [

main.tf

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,15 @@ resource "ibm_is_vpc" "vpc" {
4545

4646
# Delegated resolver
4747
dynamic "resolver" {
48-
for_each = (var.enable_hub_vpc_id || var.enable_hub_vpc_crn) && var.update_delegated_resolver ? [1] : []
48+
for_each = (var.enable_hub_vpc_id || var.enable_hub_vpc_crn) && var.update_delegated_resolver && var.resolver_type == "delegated" ? [1] : []
4949
content {
5050
type = "delegated"
5151
vpc_id = var.hub_vpc_id != null ? var.hub_vpc_id : null
5252
vpc_crn = var.hub_vpc_crn != null ? var.hub_vpc_crn : null
53+
dns_binding_name = coalesce(
54+
var.dns_binding_name,
55+
"${var.prefix != null ? "${var.prefix}-${var.name}" : var.name}-dns-binding"
56+
)
5357
}
5458
}
5559

@@ -78,6 +82,11 @@ resource "ibm_is_vpc" "vpc" {
7882
}
7983
}
8084

85+
data "ibm_is_vpc_dns_resolution_bindings" "dns_bindings" {
86+
count = (!var.enable_hub && (var.enable_hub_vpc_id || var.enable_hub_vpc_crn)) ? 1 : 0
87+
vpc_id = local.vpc_id
88+
}
89+
8190
###############################################################################
8291

8392
##############################################################################
@@ -124,9 +133,9 @@ resource "ibm_iam_authorization_policy" "vpc_dns_resolution_auth_policy" {
124133
}
125134
}
126135

127-
# Enable Hub to dns resolve in spoke VPC
136+
# Set up separate DNS resolution binding in case the resolver type is NOT delegated.
128137
resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" {
129-
count = (var.enable_hub == false && var.enable_hub_vpc_id) ? 1 : 0
138+
count = (var.enable_hub == false && var.enable_hub_vpc_id) && var.resolver_type != "delegated" ? 1 : 0
130139
# Depends on required as the authorization policy cannot be directly referenced
131140
depends_on = [ibm_iam_authorization_policy.vpc_dns_resolution_auth_policy]
132141

@@ -141,8 +150,9 @@ resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" {
141150
}
142151
}
143152

153+
# Set up separate DNS resolution binding in case the resolver type is NOT delegated.
144154
resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_crn" {
145-
count = (var.enable_hub == false && var.enable_hub_vpc_crn) ? 1 : 0
155+
count = (var.enable_hub == false && var.enable_hub_vpc_crn) && var.resolver_type != "delegated" ? 1 : 0
146156
# Depends on required as the authorization policy cannot be directly referenced
147157
depends_on = [ibm_iam_authorization_policy.vpc_dns_resolution_auth_policy]
148158

outputs.tf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,13 @@ output "custom_resolver_hub" {
158158
}
159159

160160
output "dns_endpoint_gateways_by_id" {
161-
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."
162-
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
161+
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."
162+
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)
163163
}
164164

165165
output "dns_endpoint_gateways_by_crn" {
166-
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."
167-
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
166+
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."
167+
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)
168168
}
169169

170170
output "dns_instance_id" {

tests/other_test.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,6 @@ func TestRunBasicExample(t *testing.T) {
2424
assert.NotNil(t, output, "Expected some output")
2525
}
2626

27-
func TestRunHubAndSpokeDelegatedExample(t *testing.T) {
28-
t.Parallel()
29-
30-
options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{
31-
Testing: t,
32-
TerraformDir: hubAndSpokeDelegatedExampleTerraformDir,
33-
Prefix: "has-slz",
34-
ResourceGroup: resourceGroup,
35-
Region: "us-south",
36-
})
37-
38-
output, err := options.RunTestConsistency()
39-
assert.Nil(t, err, "This should not have errored")
40-
assert.NotNil(t, output, "Expected some output")
41-
}
42-
4327
func TestRunSpecificZoneExample(t *testing.T) {
4428
t.Parallel()
4529

tests/pr_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,3 +322,25 @@ func TestRunUpgradeFullyConfigurable(t *testing.T) {
322322
assert.Nil(t, err, "This should not have errored")
323323
}
324324
}
325+
326+
func TestRunHubAndSpokeDelegatedExample(t *testing.T) {
327+
t.Parallel()
328+
329+
options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{
330+
Testing: t,
331+
TerraformDir: hubAndSpokeDelegatedExampleTerraformDir,
332+
Prefix: "has-slz",
333+
ResourceGroup: resourceGroup,
334+
Region: "us-south",
335+
PostApplyHook: func(options *testhelper.TestOptions) error {
336+
terraformOptions := options.TerraformOptions
337+
terraformOptions.Vars["update_delegated_resolver"] = true
338+
_, err := terraform.ApplyE(options.Testing, terraformOptions)
339+
return err
340+
},
341+
})
342+
343+
output, err := options.RunTestConsistency()
344+
assert.Nil(t, err, "This should not have errored")
345+
assert.NotNil(t, output, "Expected some output")
346+
}

variables.tf

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,8 @@ variable "update_delegated_resolver" {
641641
default = false
642642

643643
validation {
644-
condition = !(var.update_delegated_resolver == true && var.resolver_type != null)
645-
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."
644+
condition = !(var.update_delegated_resolver == true && var.resolver_type != "delegated")
645+
error_message = "If var.update_delegated_resolver is true then var.resolver_type must be set to 'delegated'."
646646
}
647647
}
648648

@@ -665,16 +665,17 @@ variable "use_existing_dns_instance" {
665665
}
666666

667667
variable "resolver_type" {
668-
description = "Resolver type. Can be system or manual. For delegated resolver type, see the update_delegated_resolver variable instead. "
668+
description = "Resolver type. Can be system or manual or delegated."
669669
type = string
670670
default = null
671671
validation {
672672
condition = anytrue([
673673
var.resolver_type == null,
674674
var.resolver_type == "system",
675675
var.resolver_type == "manual",
676+
var.resolver_type == "delegated"
676677
])
677-
error_message = "`resolver_type` can either be null, or set to the string 'system' or 'manual'."
678+
error_message = "`resolver_type` can either be null, or set to the string 'system', 'delegated' or 'manual'."
678679
}
679680
}
680681

0 commit comments

Comments
 (0)