Skip to content

Commit

Permalink
Merge pull request #107 from drewmullen/docs-outputs
Browse files Browse the repository at this point in the history
include docs on how to use outputs
  • Loading branch information
tlindsay42 authored Apr 26, 2023
2 parents 62b1991 + 2a6d5fe commit 0fb3bfe
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 13 deletions.
8 changes: 5 additions & 3 deletions .header.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This module can be used to deploy a pragmatic VPC with various subnets types in # AZs. Common deployment examples can be found in [examples/](https://github.com/aws-ia/terraform-aws-vpc/tree/main/examples).

__Note: For information regarding the 4.0 upgrade see our [upgrade guide](https://github.com/aws-ia/terraform-aws-vpc/blob/main/UPGRADE-GUIDE-4.0.md).__
<i>Note: For information regarding the 4.0 upgrade see our [upgrade guide](https://github.com/aws-ia/terraform-aws-vpc/blob/main/docs/UPGRADE-GUIDE-4.0.md).</i>

## Usage

Expand Down Expand Up @@ -88,8 +88,8 @@ transit_gateway_ipv6_routes = {
}
subnets = {
private = {
netmask = 24
private = {
netmask = 24
assign_ipv6_cidr = true
}
vpce = { netmask = 24}
Expand Down Expand Up @@ -192,6 +192,8 @@ The above example will cause only creating 2 new subnets in az `c` of the region

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:

For more examples and explanation see [output docs]((https://github.com/aws-ia/terraform-aws-vpc/blob/main/docs/how-to-use-module-outputs.md)

### Extracting subnet IDs for private subnets

Example Configuration:
Expand Down
7 changes: 5 additions & 2 deletions README.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions data.tf
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ locals {
create_acceptance = (local.require_acceptance == true && local.accept_attachment == true)
create_cwan_routes = (local.require_acceptance == false) || local.create_acceptance

# default value for var.subnets.public.connect_to_igw (default to true)
connect_to_igw = try(var.subnets.public.connect_to_igw, true)

##################################################################
# NAT configurations options, maps user string input to HCL usable values. selected based on nat_gateway_configuration
# null = none
Expand Down
99 changes: 99 additions & 0 deletions docs/How-to-use-module-outputs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Why our Outputs are so different and how you can use them

The Outputs from this module are designed differently than many other popular modules. Most have 100+ outputs that export individual values for specific uses. This is great because it is simple, straight-forward approach to creating and using output values from a module. This module takes a different design approach, an opinionated one that may cause you to turn your head on first glance but, we believe, is more useful and maintainable in the long run.

## TL;DR How do I use these things?

[See here](#using-the-console-to-explore)

## Implementation details:

Outputs are provided at the _resource_ level and grouped in the most logical way we have considered (please suggest others!). Let us look at a few examples:

- [nat_gateway_attributes_by_az](https://github.com/aws-ia/terraform-aws-vpc/#output_nat_gateway_attributes_by_az):
* description: Map of nat gateway resource attributes by AZ.

The name of the output explains exactly what you'll get. The attributes of a nat gateway and they're grouped by the name of the availability zone theyre in. You will see this design in most of the outputs. This is because when users make multi-az vpcs the attributes of those resources are most relevant with regard to the AZ theyre in.

### Using the Console to explore

After building the [public_private_flow_logs example](https://registry.terraform.io/modules/aws-ia/vpc/aws/latest/examples/public_private_flow_logs) drop into the [console](https://developer.hashicorp.com/terraform/cli/commands/console).

```shell
terraform console
> module.vpc.nat_gateway_attributes_by_az
{
"us-east-2a" = {
"allocation_id" = "eipalloc-0ae0e24ffe193f2a1"
"association_id" = "eipassoc-0d714a2e4a1f43c46"
"connectivity_type" = "public"
"id" = "nat-076e272ecaff6fce0"
"network_interface_id" = "eni-07d0d8f11fc3380b5"
"private_ip" = "10.0.2.19"
"public_ip" = "<>"
"subnet_id" = "subnet-005519f1eb2ca5e9d"
"tags" = tomap({
"Name" = "nat-my-public-us-east-2a"
"subnet_type" = "public"
})
"tags_all" = tomap({
"Name" = "nat-my-public-us-east-2a"
"subnet_type" = "public"
})
}
"us-east-2b" = {
"allocation_id" = "eipalloc-0a0e69ff06847b9cc"
"association_id" = "eipassoc-00ae0cc78566f5ad9"
"connectivity_type" = "public"
"id" = "nat-063181ad924968f92"
"network_interface_id" = "eni-04bc3f3eb3ac6ce77"
"private_ip" = "10.0.3.102"
"public_ip" = "<>"
"subnet_id" = "subnet-04c0b573d8937853d"
"tags" = tomap({
"Name" = "nat-my-public-us-east-2b"
"subnet_type" = "public"
})
"tags_all" = tomap({
"Name" = "nat-my-public-us-east-2b"
"subnet_type" = "public"
})
}
}
```

You can see that the vpc is in 2 AZs and since `nat_gateway_configuration = "all_azs"` nat gateways were built per AZ. The output object is a nested map and can be referenced with `.` notiation.

```hcl
> module.vpc.nat_gateway_attributes_by_az.us-east-2a.id
"nat-076e272ecaff6fce0"
> module.vpc.nat_gateway_attributes_by_az.us-east-2a.public_ip
"3.21.81.83"
```

Since it is a map you can also use expressions to grab values from each nat gateway and even construct them into another useful map:

```hcl
> { for az, attrs in module.vpc.nat_gateway_attributes_by_az: az => { id : attrs.id, private_ip : attrs.private_ip } }
{
"us-east-2a" = {
"id" = "nat-076e272ecaff6fce0"
"private_ip" = "10.0.2.19"
}
"us-east-2b" = {
"id" = "nat-063181ad924968f92"
"private_ip" = "10.0.3.102"
}
}
```

Finally, they can be passed to another resource as the parameter to `for_each`. The result would be 2 new resources who's [block label](https://developer.hashicorp.com/terraform/docs/glossary#block) corresponds to the AZ those resources are in

```hcl
resource "aws_route" "new_route_to_nat_gateway" {
for_each = module.vpc.nat_gateway_attributes_by_az
route_table_id = aws_route_table.new_route_table[each.key].id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = each.value.id
}
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion examples/public_private_flow_logs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ At this point, only cloud-watch logs are support, pending: https://github.com/aw

| Name | Source | Version |
|------|--------|---------|
| <a name="module_vpc"></a> [vpc](#module\_vpc) | ../.. | n/a |
| <a name="module_vpc"></a> [vpc](#module\_vpc) | aws-ia/vpc/aws | >= 4.2.0 |

## Resources

Expand Down
5 changes: 2 additions & 3 deletions examples/public_private_flow_logs/main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
data "aws_availability_zones" "current" {}

module "vpc" {
# source = "aws-ia/vpc/aws"
# version = ">= 3.0.2"
source = "../.."
source = "aws-ia/vpc/aws"
version = ">= 4.2.0"

name = "flowlogs"
cidr_block = "10.0.0.0/20"
Expand Down
8 changes: 5 additions & 3 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ module "calculate_subnets_ipv6" {
}

# ---------- VPC RESOURCE ----------
# flow logs optionally enabled by standalone resource
#tfsec:ignore:aws-ec2-require-vpc-flow-logs-for-all-vpcs
resource "aws_vpc" "main" {
count = local.create_vpc ? 1 : 0

Expand Down Expand Up @@ -146,7 +148,7 @@ resource "aws_egress_only_internet_gateway" "eigw" {

# Route: 0.0.0.0/0 from public subnets to the Internet gateway
resource "aws_route" "public_to_igw" {
for_each = contains(local.subnet_keys, "public") && !local.public_ipv6only ? toset(local.azs) : toset([])
for_each = contains(local.subnet_keys, "public") && !local.public_ipv6only && local.connect_to_igw ? toset(local.azs) : toset([])

route_table_id = aws_route_table.public[each.key].id
destination_cidr_block = "0.0.0.0/0"
Expand All @@ -155,7 +157,7 @@ resource "aws_route" "public_to_igw" {

# Route: ::/0 from public subnets to the Internet gateway
resource "aws_route" "public_ipv6_to_igw" {
for_each = contains(local.subnet_keys, "public") && (local.public_ipv6only || local.public_dualstack) ? toset(local.azs) : toset([])
for_each = contains(local.subnet_keys, "public") && (local.public_ipv6only || local.public_dualstack) && local.connect_to_igw ? toset(local.azs) : toset([])

route_table_id = aws_route_table.public[each.key].id
destination_ipv6_cidr_block = "::/0"
Expand Down Expand Up @@ -505,4 +507,4 @@ module "flow_logs" {
vpc_id = local.vpc.id

tags = module.tags.tags_aws
}
}
File renamed without changes.
5 changes: 5 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ output "natgw_id_per_az" {
EOF
}

output "internet_gateway" {
value = try(aws_internet_gateway.main, null)
description = "Internet gateway attributes. Full output of aws_internet_gateway."
}

output "egress_only_internet_gateway" {
value = try(aws_egress_only_internet_gateway.eigw, null)
description = "Egress-only Internet gateway attributes. Full output of aws_egress_only_internet_gateway."
Expand Down
4 changes: 3 additions & 1 deletion variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ variable "subnets" {
**public subnet type options:**
- All shared keys above
- `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.connect_to_public_natgw = true`.
- `connect_to_igw` = (Optional|bool) Determines if the default route (0.0.0.0/0 or ::/0) is created in the public subnets with destination the Internet gateway. Defaults to `true`.
- `ipv6_native` = (Optional|bool) Indicates whether to create an IPv6-ony subnet. Either `var.assign_ipv6_cidr` or `var.ipv6_cidrs` should be defined to allocate an IPv6 CIDR block.
**transit_gateway subnet type options:**
Expand Down Expand Up @@ -184,11 +185,12 @@ EOF

# All var.subnets.public valid keys
validation {
error_message = "Invalid key in public subnets. Valid options include: \"cidrs\", \"netmask\", \"name_prefix\", \"nat_gateway_configuration\", \"ipv6_native\", \"assign_ipv6_cidr\", \"ipv6_cidrs\", \"tags\"."
error_message = "Invalid key in public subnets. Valid options include: \"cidrs\", \"netmask\", \"name_prefix\", \"connect_to_igw\", \"nat_gateway_configuration\", \"ipv6_native\", \"assign_ipv6_cidr\", \"ipv6_cidrs\", \"tags\"."
condition = length(setsubtract(keys(try(var.subnets.public, {})), [
"cidrs",
"netmask",
"name_prefix",
"connect_to_igw",
"nat_gateway_configuration",
"ipv6_native",
"assign_ipv6_cidr",
Expand Down

0 comments on commit 0fb3bfe

Please sign in to comment.