Skip to content

Commit 26f0553

Browse files
authored
Merge pull request #53 from aws-ia/usage-doc-updates
Improve usage and development documentation
2 parents b7396f0 + af5e78e commit 26f0553

File tree

7 files changed

+361
-35
lines changed

7 files changed

+361
-35
lines changed

.header.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,63 @@ subnets = {
7878
```
7979

8080
The above example will cause only creating 2 new subnets in az `c` of the region being used.
81+
82+
## Output manipulation
83+
84+
The outputs in this module attempt to align to a methodology of outputting resource attributes in a reasonable collection. The benefit of this is that, most likely, attributes you want access to are already present without having to create new `output {}` for each possible attribute. The [potential] downside is that you will have to extract it yourself using HCL logic. Below are some common examples:
85+
86+
### Extracting subnet IDs for private subnets
87+
88+
Example Configuration:
89+
```terraform
90+
module "vpc" {
91+
source = "aws-ia/vpc/aws"
92+
version = ">= 1.0.0"
93+
94+
name = "multi-az-vpc"
95+
cidr_block = "10.0.0.0/20"
96+
az_count = 3
97+
98+
subnets = {
99+
private = { netmask = 24 }
100+
}
101+
}
102+
```
103+
104+
Extracting subnet_ids to a list (using `terraform console` for example output):
105+
```terraform
106+
> [ for _, value in module.vpc.private_subnet_attributes_by_az: value.id]
107+
[
108+
"subnet-04a86315c4839b519",
109+
"subnet-02a7249c8652a7136",
110+
"subnet-09af79b5329b3681f",
111+
]
112+
```
113+
114+
Alternatively, since these are maps, you can use key in another resource `for_each` loop. The benefit here is that your dependent resource will have keys that match the AZ the subnet is in:
115+
116+
```terraform
117+
resource "aws_route53recoveryreadiness_cell" "cell_per_az" {
118+
for_each = module.vpc.private_subnet_attributes_by_az
119+
120+
cell_name = "${each.key}-failover-cell-for-subnet-${each.value.id}"
121+
}
122+
...
123+
```
124+
125+
Terraform Plan:
126+
127+
```shell
128+
# aws_route53recoveryreadiness_cell.cell_per_az["us-east-1a"] will be created
129+
+ resource "aws_route53recoveryreadiness_cell" "cell_per_az" {
130+
+ cell_name = "us-east-1a-failover-cell-for-subnet-subnet-070696086c5864da1"
131+
...
132+
}
133+
134+
# aws_route53recoveryreadiness_cell.cell_per_az["us-east-1b"] will be created
135+
...
136+
```
137+
138+
## Contributing
139+
140+
Please see our [developer documentation](https://github.com/aws-ia/terraform-aws-vpc/contributing.md) for guidance on contributing to this module

README.md

Lines changed: 73 additions & 10 deletions
Large diffs are not rendered by default.

contributing.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Developer Documentation
2+
3+
## Outputs Methodology
4+
5+
This module organizes outputs by creating output collections of grouped entire resources. The benefit of this is that, most likely, attributes users want access to are already present without having to create new `output {}` for each possible attribute. The [potential] downside is that you will have to extract it yourself using HCL logic. See the [outputs.tf](https://github.com/aws-ia/terraform-aws-vpc/outputs.tf) for examples.
6+
7+
Our naming convetion attempts to make the output content clear. `route_table_attributes_by_type_by_az` is a nested map of route table resource attributes grouped by their subnet type then by the az. Example:
8+
```terraform
9+
route_table_attributes_by_type_by_az = {
10+
"private" = {
11+
"us-east-1a" = {
12+
"id" = "rtb-0e77040c0598df003"
13+
"route_table_id" = "rtb-0e77040c0598df003"
14+
"tags" = tolist([
15+
{
16+
"key" = "Name"
17+
"value" = "private-us-east-1a"
18+
},
19+
])
20+
"vpc_id" = "vpc-033e054f49409592a"
21+
}
22+
"us-east-1b" = {
23+
...
24+
}
25+
"public" = { ... }
26+
```
27+
28+
## Adding new subnet types
29+
30+
*Note: All subnet types **MUST** accept both `cidrs` and `netmask` arguments.*
31+
32+
1. Updates to variables.tf
33+
34+
1. Add new to `subnets` key variable validation:
35+
36+
```terraform
37+
validation {
38+
error_message = "Only valid key values \"public\", \"private\", or \"transit_gateway\"."
39+
condition = length(setsubtract(keys(var.subnets), [
40+
"public",
41+
"private",
42+
"transit_gateway",
43+
"<new type here>"
44+
])) == 0
45+
}
46+
```
47+
48+
1. Specify keys allowed in new variable type map. Copy an existing one and edit the keys to match what you expect users to input:
49+
50+
```terraform
51+
# All var.subnets.public valid keys
52+
validation {
53+
error_message = "Invalid key in public subnets. Valid options include: \"cidrs\", \"netmask\", \"name_prefix\", \"nat_gateway_configuration\", \"tags\"."
54+
condition = length(setsubtract(keys(try(var.subnets.public, {})), [
55+
"cidrs",
56+
"netmask",
57+
"name_prefix",
58+
"nat_gateway_configuration",
59+
"route_to_transit_gateway",
60+
"tags"
61+
])) == 0
62+
}
63+
```
64+
65+
1. Include in description:
66+
67+
```terraform
68+
**private subnet type options:**
69+
- All shared keys above
70+
- `route_to_nat` = (Optional|bool) <>
71+
- `route_to_transit_gateway` = (Optional|list(string)) <>
72+
```
73+
74+
2. Write configuration code
75+
76+
*Note: each for_each loop must account for if a user does not want to create the particular subnet type. Follow examples from other subnet types in main.tf*
77+
78+
* Create new `aws_subnet`
79+
* Create new `awscc_ec2_route_table`
80+
* Create new `awscc_ec2_subnet_route_table_association`
81+
* Consider and create appropriate `aws_route`
82+
83+
84+
3. Create appropriate outputs
85+
86+
1. `output "<new subnet type>_subnet_attributes_by_az"`
87+
1. add new type to `route_table_attributes_by_type_by_az`

examples/private_only/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ No inputs.
2929

3030
| Name | Description |
3131
|------|-------------|
32-
| <a name="output_subnet_attributes"></a> [subnet\_attributes](#output\_subnet\_attributes) | n/a |
32+
| <a name="output_private_subnet_attributes"></a> [private\_subnet\_attributes](#output\_private\_subnet\_attributes) | n/a |
3333
| <a name="output_subnets"></a> [subnets](#output\_subnets) | Map of subnet types with key/value az = cidr. |
34-
<!-- END_TF_DOCS -->
34+
<!-- END_TF_DOCS -->

examples/private_only/outputs.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ output "subnets" {
33
value = module.vpc.subnets
44
}
55

6-
output "subnet_attributes" {
6+
output "private_subnet_attributes" {
77
value = module.vpc.private_subnet_attributes_by_az
88
}

outputs.tf

Lines changed: 134 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,27 @@ output "vpc_attributes" {
33
value = local.vpc
44
}
55

6-
output "subnets" {
7-
description = "Map of subnets grouped by type with child map { az = cidr }."
6+
output "subnet_cidrs_by_type_by_az" {
87
value = module.calculate_subnets.subnets_by_type
9-
/* Example:
8+
description = <<-EOF
9+
Map of subnets grouped by type with child map { az = cidr }.
10+
11+
Example:
12+
```
1013
subnets = {
11-
private = {
12-
us-east-1a = "10.0.0.0/24"
13-
us-east-1b = "10.0.1.0/24"
14-
us-east-1c = "10.0.2.0/24"
15-
}
14+
private = {
15+
us-east-1a = "10.0.0.0/24"
16+
us-east-1b = "10.0.1.0/24"
17+
us-east-1c = "10.0.2.0/24"
18+
}
1619
public = {
17-
us-east-1a = "10.0.3.0/24"
18-
us-east-1b = "10.0.4.0/24"
19-
us-east-1c = "10.0.5.0/24"
20-
}
20+
us-east-1a = "10.0.3.0/24"
21+
us-east-1b = "10.0.4.0/24"
22+
us-east-1c = "10.0.5.0/24"
23+
}
2124
}
22-
*/
25+
```
26+
EOF
2327
}
2428

2529
output "transit_gateway_attachment_id" {
@@ -28,22 +32,134 @@ output "transit_gateway_attachment_id" {
2832
}
2933

3034
output "private_subnet_attributes_by_az" {
31-
description = "Map of all private subnets containing their attributes."
3235
value = try(aws_subnet.private, null)
36+
description = <<-EOF
37+
Map of all private subnets containing their attributes.
38+
39+
Example:
40+
```
41+
private_subnet_attributes = {
42+
"us-east-1a" = {
43+
"arn" = "arn:aws:ec2:us-east-1:<>:subnet/subnet-04a86315c4839b519"
44+
"assign_ipv6_address_on_creation" = false
45+
...
46+
<all attributes of subnet: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet#attributes-reference>
47+
}
48+
"us-east-1b" = {...)
49+
}
50+
```
51+
EOF
3352
}
3453

3554
output "public_subnet_attributes_by_az" {
36-
description = "Map of all public subnets containing their attributes."
3755
value = try(aws_subnet.public, null)
56+
description = <<-EOF
57+
Map of all public subnets containing their attributes.
58+
59+
Example:
60+
```
61+
public_subnet_attributes = {
62+
"us-east-1a" = {
63+
"arn" = "arn:aws:ec2:us-east-1:<>:subnet/subnet-04a86315c4839b519"
64+
"assign_ipv6_address_on_creation" = false
65+
...
66+
<all attributes of subnet: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet#attributes-reference>
67+
}
68+
"us-east-1b" = {...)
69+
}
70+
```
71+
EOF
3872
}
3973

4074
output "tgw_subnet_attributes_by_az" {
41-
description = "Map of all transit gateway subnets containing their attributes."
4275
value = try(aws_subnet.tgw, null)
76+
description = <<-EOF
77+
Map of all tgw subnets containing their attributes.
78+
79+
Example:
80+
```
81+
tgw_subnet_attributes = {
82+
"us-east-1a" = {
83+
"arn" = "arn:aws:ec2:us-east-1:<>:subnet/subnet-04a86315c4839b519"
84+
"assign_ipv6_address_on_creation" = false
85+
...
86+
<all attributes of subnet: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet#attributes-reference>
87+
}
88+
"us-east-1b" = {...)
89+
}
90+
```
91+
EOF
92+
}
93+
94+
output "route_table_attributes_by_type_by_az" {
95+
value = {
96+
# TODO: omit keys if value is null
97+
"private" = awscc_ec2_route_table.private,
98+
"public" = awscc_ec2_route_table.public
99+
"transit_gateway" = awscc_ec2_route_table.tgw
100+
}
101+
description = <<-EOF
102+
Map of route tables by type => az => route table attributes. Example usage: module.vpc.route_table_by_subnet_type.private.id
103+
104+
Example:
105+
```
106+
route_table_attributes_by_type_by_az = {
107+
"private" = {
108+
"us-east-1a" = {
109+
"id" = "rtb-0e77040c0598df003"
110+
"route_table_id" = "rtb-0e77040c0598df003"
111+
"tags" = tolist([
112+
{
113+
"key" = "Name"
114+
"value" = "private-us-east-1a"
115+
},
116+
])
117+
"vpc_id" = "vpc-033e054f49409592a"
118+
}
119+
"us-east-1b" = { ... }
120+
"public" = { ... }
121+
```
122+
EOF
123+
}
124+
125+
output "nat_gateway_attributes_by_az" {
126+
value = try(aws_nat_gateway.main, null)
127+
description = <<-EOF
128+
Map of nat gateway resource attributes by AZ.
129+
130+
Example:
131+
```
132+
nat_gateway_attributes_by_az = {
133+
"us-east-1a" = {
134+
"allocation_id" = "eipalloc-0e8b20303eea88b13"
135+
"connectivity_type" = "public"
136+
"id" = "nat-0fde39f9550f4abb5"
137+
"network_interface_id" = "eni-0d422727088bf9a86"
138+
"private_ip" = "10.0.3.40"
139+
"public_ip" = <>
140+
"subnet_id" = "subnet-0f11c92e439c8ab4a"
141+
"tags" = tomap({
142+
"Name" = "nat-my-public-us-east-1a"
143+
})
144+
"tags_all" = tomap({
145+
"Name" = "nat-my-public-us-east-1a"
146+
})
147+
}
148+
"us-east-1b" = { ... }
149+
}
150+
```
151+
EOF
152+
}
153+
154+
## DEPRECATED OUTPUTS
155+
156+
output "subnets" {
157+
description = "DEPRECATED OUTPUT: this output has been renamed to `subnet_cidrs_by_type_by_az`. Please transition to that output and see it for a proper description."
158+
value = module.calculate_subnets.subnets_by_type
43159
}
44160

45161
output "route_table_by_subnet_type" {
46-
description = "Map of route tables by type => az => route table attributes. Example usage: module.vpc.route_table_by_subnet_type.private.id"
162+
description = "DEPRECATED OUTPUT: this output has been renamed to `route_table_attributes_by_type_by_az`. Please transition to that output and see it for a proper description."
47163
value = {
48164
# TODO: omit keys if value is null
49165
"private" = awscc_ec2_route_table.private,
@@ -53,6 +169,6 @@ output "route_table_by_subnet_type" {
53169
}
54170

55171
output "nat_gateways_by_az" {
56-
description = "Map of nat gateway resource attributes by AZ."
172+
description = "DEPRECATED OUTPUT: this output has been renamed to `nat_gateway_attributes_by_az`. Please transition to that output and see it for a proper description."
57173
value = try(aws_nat_gateway.main, null)
58174
}

variables.tf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,23 +71,23 @@ variable "subnets" {
7171
description = <<-EOF
7272
Configuration of subnets to build in VPC. 1 Subnet per AZ is created. Subnet types are defined as maps with the available keys: "private", "public", "transit_gateway". Each Subnet type offers its own set of available arguments detailed below.
7373
74-
Attributes shared across subnet types:
74+
**Attributes shared across subnet types:**
7575
- `cidrs` = (Optional|list(string)) **Cannot set if `netmask` is set.** List of CIDRs to set to subnets. Count of CIDRs defined must match quatity of azs in `az_count`.
7676
- `netmask` = (Optional|Int) Netmask of the `var.cidr_block` to calculate for each subnet. **Cannot set if `cidrs` is set.**
7777
- `name_prefix` = (Optional|String) A string prefix to use for the name of your subnet and associated resources. Subnet type key name is used if omitted (aka private, public, transit_gateway). Example `name_prefix = "private"` for `var.subnets.private` is redundant.
7878
- `tags` = (Optional|map(string)) Tags to set on the subnet and associated resources.
7979
80-
`private` subnet type options:
80+
**private subnet type options:**
8181
- All shared keys above
8282
- `route_to_nat` = (Optional|bool) Determines if routes to NAT Gateways should be created. Default = false. Must also set `var.subnets.public.nat_gateway_configuration`.
8383
- `route_to_transit_gateway` = (Optional|list(string)) Optionally create routes from private subnets to transit gateway subnets.
8484
85-
`public` subnet type options:
85+
**public subnet type options:**
8686
- All shared keys above
8787
- `nat_gateway_configuration` = (Optional|string) Determines if NAT Gateways should be created and in how many AZs. Valid values = `"none"`, `"single_az"`, `"all_azs"`. Default = "none". Must also set `var.subnets.private.route_to_nat = true`.
8888
- `route_to_transit_gateway` = (Optional|list(string)) Optionally create routes from private subnets to transit gateway subnets.
8989
90-
`transit_gateway` subnet type options:
90+
**transit_gateway subnet type options:**
9191
- All shared keys above
9292
- `route_to_nat` = (Optional|bool) Determines if routes to NAT Gateways should be created. Default = false. Must also set `var.subnets.public.nat_gateway_configuration`.
9393
- `transit_gateway_id` = (Required|string) Transit gateway to attach VPC to.

0 commit comments

Comments
 (0)