Skip to content

Commit f0c5b08

Browse files
feat: added support to create resources in existing VPC and use existing subnets. See [Existing VPC and subnets Example](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/tree/main/examples/existing_vpc) (#638)
1 parent a09804b commit f0c5b08

File tree

21 files changed

+357
-51
lines changed

21 files changed

+357
-51
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ To attach access management tags to resources in this module, you need the follo
8383

8484
- [ Basic Example](examples/basic)
8585
- [ Default Example](examples/default)
86+
- [ Existing VPC and subnets Example](examples/existing_vpc)
8687
- [ Hub and Spoke VPC Example](examples/hub-spoke-delegated-resolver)
8788
- [ Hub and Spoke VPC with manual DNS resolver Example](examples/hub-spoke-manual-resolver)
8889
- [ Landing Zone example](examples/landing_zone)
@@ -126,6 +127,8 @@ To attach access management tags to resources in this module, you need the follo
126127
| [ibm_is_vpc_routing_table_route.routing_table_routes](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_vpc_routing_table_route) | resource |
127128
| [ibm_resource_instance.dns_instance_hub](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) | resource |
128129
| [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource |
130+
| [ibm_is_subnet.subnet](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_subnet) | data source |
131+
| [ibm_is_vpc.vpc](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_vpc) | data source |
129132
| [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 |
130133

131134
### Inputs
@@ -137,6 +140,8 @@ To attach access management tags to resources in this module, you need the follo
137140
| <a name="input_classic_access"></a> [classic\_access](#input\_classic\_access) | OPTIONAL - Classic Access to the VPC | `bool` | `false` | no |
138141
| <a name="input_clean_default_sg_acl"></a> [clean\_default\_sg\_acl](#input\_clean\_default\_sg\_acl) | Remove all rules from the default VPC security group and VPC ACL (less permissive) | `bool` | `false` | no |
139142
| <a name="input_create_authorization_policy_vpc_to_cos"></a> [create\_authorization\_policy\_vpc\_to\_cos](#input\_create\_authorization\_policy\_vpc\_to\_cos) | Create authorisation policy for VPC to access COS. Set as false if authorization policy exists already | `bool` | `false` | no |
143+
| <a name="input_create_subnets"></a> [create\_subnets](#input\_create\_subnets) | Indicates whether user wants to use existing subnets or create new. Set it to true to create new subnets. | `bool` | `true` | no |
144+
| <a name="input_create_vpc"></a> [create\_vpc](#input\_create\_vpc) | Indicates whether user wants to use an existing vpc or create a new one. Set it to true to create a new vpc | `bool` | `true` | no |
140145
| <a name="input_default_network_acl_name"></a> [default\_network\_acl\_name](#input\_default\_network\_acl\_name) | OPTIONAL - Name of the Default ACL. If null, a name will be automatically generated | `string` | `null` | no |
141146
| <a name="input_default_routing_table_name"></a> [default\_routing\_table\_name](#input\_default\_routing\_table\_name) | OPTIONAL - Name of the Default Routing Table. If null, a name will be automatically generated | `string` | `null` | no |
142147
| <a name="input_default_security_group_name"></a> [default\_security\_group\_name](#input\_default\_security\_group\_name) | OPTIONAL - Name of the Default Security Group. If null, a name will be automatically generated | `string` | `null` | no |
@@ -149,15 +154,17 @@ To attach access management tags to resources in this module, you need the follo
149154
| <a name="input_existing_cos_instance_guid"></a> [existing\_cos\_instance\_guid](#input\_existing\_cos\_instance\_guid) | GUID of the COS instance to create Flow log collector | `string` | `null` | no |
150155
| <a name="input_existing_dns_instance_id"></a> [existing\_dns\_instance\_id](#input\_existing\_dns\_instance\_id) | Id of an existing dns instance in which the custom resolver is created. Only relevant if enable\_hub is set to true. | `string` | `null` | no |
151156
| <a name="input_existing_storage_bucket_name"></a> [existing\_storage\_bucket\_name](#input\_existing\_storage\_bucket\_name) | Name of the COS bucket to collect VPC flow logs | `string` | `null` | no |
157+
| <a name="input_existing_subnet_ids"></a> [existing\_subnet\_ids](#input\_existing\_subnet\_ids) | The IDs of the existing subnets. Required if 'create\_subnets' is false. | `list(string)` | `null` | no |
158+
| <a name="input_existing_vpc_id"></a> [existing\_vpc\_id](#input\_existing\_vpc\_id) | The ID of the existing vpc. Required if 'create\_vpc' is false. | `string` | `null` | no |
152159
| <a name="input_hub_vpc_crn"></a> [hub\_vpc\_crn](#input\_hub\_vpc\_crn) | Indicates the crn of the hub VPC for DNS resolution. See https://cloud.ibm.com/docs/vpc?topic=vpc-hub-spoke-model. Mutually exclusive with hub\_vpc\_id. | `string` | `null` | no |
153160
| <a name="input_hub_vpc_id"></a> [hub\_vpc\_id](#input\_hub\_vpc\_id) | Indicates the id of the hub VPC for DNS resolution. See https://cloud.ibm.com/docs/vpc?topic=vpc-hub-spoke-model. Mutually exclusive with hub\_vpc\_crn. | `string` | `null` | no |
154161
| <a name="input_ibmcloud_api_visibility"></a> [ibmcloud\_api\_visibility](#input\_ibmcloud\_api\_visibility) | IBM Cloud API visibility used by scripts run in this module. Must be 'public', 'private', or 'public-and-private' | `string` | `"public"` | no |
155162
| <a name="input_is_flow_log_collector_active"></a> [is\_flow\_log\_collector\_active](#input\_is\_flow\_log\_collector\_active) | Indicates whether the collector is active. If false, this collector is created in inactive mode. | `bool` | `true` | no |
156163
| <a name="input_manual_servers"></a> [manual\_servers](#input\_manual\_servers) | The DNS server addresses to use for the VPC, replacing any existing servers. All the entries must either have a unique zone\_affinity, or not have a zone\_affinity. | <pre>list(object({<br> address = string<br> zone_affinity = optional(string)<br> }))</pre> | `[]` | no |
157-
| <a name="input_name"></a> [name](#input\_name) | Name for VPC | `string` | n/a | yes |
164+
| <a name="input_name"></a> [name](#input\_name) | The name to give the newly provisioned VPC. Only used if 'create\_vpc' is true. | `string` | `"dev"` | no |
158165
| <a name="input_network_acls"></a> [network\_acls](#input\_network\_acls) | The list of ACLs to create. Provide at least one rule for each ACL. | <pre>list(<br> object({<br> name = string<br> add_ibm_cloud_internal_rules = optional(bool)<br> add_vpc_connectivity_rules = optional(bool)<br> prepend_ibm_rules = optional(bool)<br> rules = list(<br> object({<br> name = string<br> action = string<br> destination = string<br> direction = string<br> source = string<br> tcp = optional(<br> object({<br> port_max = optional(number)<br> port_min = optional(number)<br> source_port_max = optional(number)<br> source_port_min = optional(number)<br> })<br> )<br> udp = optional(<br> object({<br> port_max = optional(number)<br> port_min = optional(number)<br> source_port_max = optional(number)<br> source_port_min = optional(number)<br> })<br> )<br> icmp = optional(<br> object({<br> type = optional(number)<br> code = optional(number)<br> })<br> )<br> })<br> )<br> })<br> )</pre> | <pre>[<br> {<br> "add_ibm_cloud_internal_rules": true,<br> "add_vpc_connectivity_rules": true,<br> "name": "vpc-acl",<br> "prepend_ibm_rules": true,<br> "rules": []<br> }<br>]</pre> | no |
159166
| <a name="input_network_cidrs"></a> [network\_cidrs](#input\_network\_cidrs) | List of Network CIDRs for the VPC. This is used to manage network ACL rules for cluster provisioning. | `list(string)` | <pre>[<br> "10.0.0.0/8"<br>]</pre> | no |
160-
| <a name="input_prefix"></a> [prefix](#input\_prefix) | The prefix that you would like to append to your resources. Explicitly set to null if you do not wish to use a prefix. | `string` | n/a | yes |
167+
| <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. | `string` | `null` | no |
161168
| <a name="input_region"></a> [region](#input\_region) | The region to which to deploy the VPC | `string` | n/a | yes |
162169
| <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 |
163170
| <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 |

default_security_group.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ locals {
1212

1313
resource "ibm_is_security_group_rule" "default_vpc_rule" {
1414
for_each = local.security_group_rule_object
15-
group = ibm_is_vpc.vpc.default_security_group
15+
group = var.create_vpc == true ? ibm_is_vpc.vpc[0].default_security_group : data.ibm_is_vpc.vpc[0].default_security_group
1616
direction = each.value.direction
1717
remote = each.value.remote
1818

examples/existing_vpc/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Existing VPC and subnets Example
2+
3+
An example of calling the module with an existing VPC and subnets.

examples/existing_vpc/main.tf

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
##############################################################################
2+
# Resource Group
3+
##############################################################################
4+
5+
module "resource_group" {
6+
source = "terraform-ibm-modules/resource-group/ibm"
7+
version = "1.1.0"
8+
# if an existing resource group is not set (null) create a new one using prefix
9+
existing_resource_group_name = var.existing_resource_group_name
10+
}
11+
12+
module "slz_vpc" {
13+
source = "../../"
14+
resource_group_id = module.resource_group.resource_group_id
15+
region = var.region
16+
create_vpc = false
17+
existing_vpc_id = var.vpc_id
18+
create_subnets = false
19+
existing_subnet_ids = var.subnet_ids
20+
}

examples/existing_vpc/outputs.tf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
##############################################################################
2+
# Outputs
3+
##############################################################################
4+
5+
output "vpc_data" {
6+
value = module.slz_vpc
7+
description = "Details of the VPC"
8+
}

examples/existing_vpc/provider.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
provider "ibm" {
2+
ibmcloud_api_key = var.ibmcloud_api_key
3+
region = var.region
4+
}

examples/existing_vpc/variables.tf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
variable "ibmcloud_api_key" {
2+
description = "APIkey that's associated with the account to provision resources to"
3+
type = string
4+
sensitive = true
5+
}
6+
7+
variable "region" {
8+
description = "The region to which to deploy the VPC"
9+
type = string
10+
default = "us-south"
11+
}
12+
variable "vpc_id" {
13+
description = "The ID of the VPC where the VSI will be created."
14+
type = string
15+
}
16+
variable "subnet_ids" {
17+
description = "The ID of the VPC where the VSI will be created."
18+
type = list(string)
19+
}
20+
21+
variable "existing_resource_group_name" {
22+
type = string
23+
description = "An existing resource group name to use for this example."
24+
}

examples/existing_vpc/version.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.3.0, <1.6.0"
3+
required_providers {
4+
# Pin to the lowest provider version of the range defined in the main module's version.tf to ensure lowest version still works
5+
ibm = {
6+
source = "IBM-Cloud/ibm"
7+
version = "1.59.0"
8+
}
9+
}
10+
}

main.tf

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ locals {
55
# input variable validation
66
# tflint-ignore: terraform_unused_declarations
77
validate_default_secgroup_rules = var.clean_default_sg_acl && (var.security_group_rules != null && length(var.security_group_rules) > 0) ? tobool("var.clean_default_sg_acl is true and var.security_group_rules are not empty, which are in direct conflict of each other. If you would like the default VPC Security Group to be empty, you must remove default rules from var.security_group_rules.") : true
8+
# tflint-ignore: terraform_unused_declarations
9+
validate_existing_vpc_id = !var.create_vpc && var.existing_vpc_id == null ? tobool("If var.create_vpc is false, then provide a value for var.existing_vpc_id to create vpc.") : true
10+
# tflint-ignore: terraform_unused_declarations
11+
validate_existing_subnet_id = !var.create_subnets && var.existing_subnet_ids == null ? tobool("If var.create_subnet is false, then provide a value for var.existing_subnet_ids to create subnets.") : true
12+
# tflint-ignore: terraform_unused_declarations
13+
validate_existing_vpc_and_subnet = var.create_vpc == true && var.create_subnets == false ? tobool("If user is not providing a vpc then they should also not be providing a subnet") : true
814

915
# tflint-ignore: terraform_unused_declarations
1016
validate_hub_vpc_input = (var.hub_vpc_id != null && var.hub_vpc_crn != null) ? tobool("var.hub_vpc_id and var.hub_vpc_crn are mutually exclusive. Hence cannot have values at the same time.") : true
@@ -33,6 +39,7 @@ locals {
3339
##############################################################################
3440

3541
resource "ibm_is_vpc" "vpc" {
42+
count = var.create_vpc == true ? 1 : 0
3643
name = var.prefix != null ? "${var.prefix}-${var.name}-vpc" : "${var.name}-vpc"
3744
resource_group = var.resource_group_id
3845
classic_access = var.classic_access
@@ -94,7 +101,7 @@ resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" {
94101
count = (var.enable_hub == false && var.enable_hub_vpc_id) ? 1 : 0
95102

96103
name = "${var.prefix}-dns-binding"
97-
vpc_id = ibm_is_vpc.vpc.id # Source VPC
104+
vpc_id = local.vpc_id # Source VPC
98105
vpc {
99106
id = var.hub_vpc_id # Target VPC ID
100107
}
@@ -103,12 +110,21 @@ resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" {
103110
resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_crn" {
104111
count = (var.enable_hub == false && var.enable_hub_vpc_crn) ? 1 : 0
105112
name = "${var.prefix}-dns-binding"
106-
vpc_id = ibm_is_vpc.vpc.id # Source VPC
113+
vpc_id = local.vpc_id # Source VPC
107114
vpc {
108115
crn = var.hub_vpc_crn # Target VPC CRN
109116
}
110117
}
111118

119+
data "ibm_is_vpc" "vpc" {
120+
count = var.create_vpc == false ? 1 : 0
121+
identifier = var.existing_vpc_id
122+
}
123+
124+
locals {
125+
vpc_id = var.create_vpc ? ibm_is_vpc.vpc[0].id : var.existing_vpc_id
126+
}
127+
112128
# Configure custom resolver on the hub vpc
113129
resource "ibm_resource_instance" "dns_instance_hub" {
114130
count = var.enable_hub && !var.skip_custom_resolver_hub_creation && !var.use_existing_dns_instance ? 1 : 0
@@ -127,7 +143,7 @@ resource "ibm_dns_custom_resolver" "custom_resolver_hub" {
127143
enabled = true
128144

129145
dynamic "locations" {
130-
for_each = ibm_is_subnet.subnet
146+
for_each = local.subnets
131147
content {
132148
subnet_crn = locations.value.crn
133149
enabled = true
@@ -153,21 +169,21 @@ locals {
153169
resource "ibm_is_vpc_address_prefix" "address_prefixes" {
154170
for_each = local.address_prefixes
155171
name = each.value.name
156-
vpc = ibm_is_vpc.vpc.id
172+
vpc = local.vpc_id
157173
zone = each.value.zone
158174
cidr = each.value.cidr
159175
}
160176

161177
data "ibm_is_vpc_address_prefixes" "get_address_prefixes" {
162178
depends_on = [ibm_is_vpc_address_prefix.address_prefixes, ibm_is_vpc_address_prefix.subnet_prefix]
163-
vpc = ibm_is_vpc.vpc.id
179+
vpc = local.vpc_id
164180
}
165181
##############################################################################
166182

167183
# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
168184
resource "time_sleep" "wait_for_authorization_policy" {
169-
depends_on = [ibm_iam_authorization_policy.policy]
170-
185+
depends_on = [ibm_iam_authorization_policy.policy]
186+
count = (var.enable_vpc_flow_logs) ? ((var.create_authorization_policy_vpc_to_cos) ? 1 : 0) : 0
171187
create_duration = "30s"
172188
}
173189

@@ -178,15 +194,15 @@ resource "time_sleep" "wait_for_authorization_policy" {
178194
resource "ibm_is_vpc_routing_table" "route_table" {
179195
for_each = module.dynamic_values.routing_table_map
180196
name = var.prefix != null ? "${var.prefix}-${var.name}-route-${each.value.name}" : "${var.name}-route-${each.value.name}"
181-
vpc = ibm_is_vpc.vpc.id
197+
vpc = local.vpc_id
182198
route_direct_link_ingress = each.value.route_direct_link_ingress
183199
route_transit_gateway_ingress = each.value.route_transit_gateway_ingress
184200
route_vpc_zone_ingress = each.value.route_vpc_zone_ingress
185201
}
186202

187203
resource "ibm_is_vpc_routing_table_route" "routing_table_routes" {
188204
for_each = module.dynamic_values.routing_table_route_map
189-
vpc = ibm_is_vpc.vpc.id
205+
vpc = local.vpc_id
190206
routing_table = ibm_is_vpc_routing_table.route_table[each.value.route_table].routing_table
191207
zone = "${var.region}-${each.value.zone}"
192208
name = each.key
@@ -213,7 +229,7 @@ locals {
213229
resource "ibm_is_public_gateway" "gateway" {
214230
for_each = local.gateway_object
215231
name = var.prefix != null ? "${var.prefix}-${var.name}-public-gateway-${each.key}" : "${var.name}-public-gateway-${each.key}"
216-
vpc = ibm_is_vpc.vpc.id
232+
vpc = local.vpc_id
217233
resource_group = var.resource_group_id
218234
zone = each.value
219235
tags = var.tags
@@ -247,7 +263,7 @@ resource "ibm_is_flow_log" "flow_logs" {
247263
count = (var.enable_vpc_flow_logs) ? 1 : 0
248264

249265
name = var.prefix != null ? "${var.prefix}-${var.name}-logs" : "${var.name}-logs"
250-
target = ibm_is_vpc.vpc.id
266+
target = local.vpc_id
251267
active = var.is_flow_log_collector_active
252268
storage_bucket = var.existing_storage_bucket_name
253269
resource_group = var.resource_group_id

0 commit comments

Comments
 (0)