mirror of
https://github.com/Sea-Haven-Industries/meal-order-manager.git
synced 2026-09-30 04:13:12 +00:00
fix(infra): share the afterhours VPC in prod (PLAT-215) (#203)
* fix(infra): share the afterhours VPC when existing_vpc_id is set Prod is at the account VPC quota, so the v1.0.0 apply destroyed Lambda/API Gateway then failed on CreateVpc. Skip creating a sixth VPC when the workspace supplies afterhours subnets. * style(test): format the VPC terraform assertion for ruff
This commit is contained in:
parent
697deb94fd
commit
3efff5e784
6 changed files with 114 additions and 21 deletions
|
|
@ -68,3 +68,26 @@ check "dev_has_no_custom_domain" {
|
||||||
error_message = "attach_custom_domain must be false in non-prod; use the CloudFront distribution domain."
|
error_message = "attach_custom_domain must be false in non-prod; use the CloudFront distribution domain."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check "existing_vpc_pair" {
|
||||||
|
assert {
|
||||||
|
condition = (var.existing_vpc_id == "") == (length(var.existing_public_subnet_ids) == 0)
|
||||||
|
error_message = "existing_vpc_id and existing_public_subnet_ids must both be set or both be empty."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check "existing_vpc_two_az" {
|
||||||
|
assert {
|
||||||
|
condition = var.existing_vpc_id == "" || length(var.existing_public_subnet_ids) >= 2
|
||||||
|
error_message = "existing_public_subnet_ids must include at least two subnets."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check "existing_subnets_in_vpc" {
|
||||||
|
assert {
|
||||||
|
condition = alltrue([
|
||||||
|
for subnet in data.aws_subnet.existing_public : subnet.vpc_id == var.existing_vpc_id
|
||||||
|
])
|
||||||
|
error_message = "Every existing_public_subnet_ids value must belong to existing_vpc_id."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ resource "aws_ecr_lifecycle_policy" "api" {
|
||||||
resource "aws_security_group" "alb" {
|
resource "aws_security_group" "alb" {
|
||||||
name = "${local.project}-alb"
|
name = "${local.project}-alb"
|
||||||
description = "Public ALB for meal-order-manager"
|
description = "Public ALB for meal-order-manager"
|
||||||
vpc_id = aws_vpc.this.id
|
vpc_id = local.vpc_id
|
||||||
|
|
||||||
ingress {
|
ingress {
|
||||||
# CloudFront prefix lists cannot cover GitHub-hosted weekly-menu HMAC
|
# CloudFront prefix lists cannot cover GitHub-hosted weekly-menu HMAC
|
||||||
|
|
@ -63,7 +63,7 @@ resource "aws_security_group" "alb" {
|
||||||
resource "aws_security_group" "api" {
|
resource "aws_security_group" "api" {
|
||||||
name = "${local.project}-api"
|
name = "${local.project}-api"
|
||||||
description = "Fargate tasks for meal-order-manager"
|
description = "Fargate tasks for meal-order-manager"
|
||||||
vpc_id = aws_vpc.this.id
|
vpc_id = local.vpc_id
|
||||||
|
|
||||||
ingress {
|
ingress {
|
||||||
description = "From ALB"
|
description = "From ALB"
|
||||||
|
|
@ -86,7 +86,7 @@ resource "aws_lb" "api" {
|
||||||
load_balancer_type = "application"
|
load_balancer_type = "application"
|
||||||
idle_timeout = 120
|
idle_timeout = 120
|
||||||
security_groups = [aws_security_group.alb.id]
|
security_groups = [aws_security_group.alb.id]
|
||||||
subnets = aws_subnet.public[*].id
|
subnets = local.public_subnet_ids
|
||||||
|
|
||||||
drop_invalid_header_fields = true
|
drop_invalid_header_fields = true
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +95,7 @@ resource "aws_lb_target_group" "api" {
|
||||||
name = "${local.project}-api"
|
name = "${local.project}-api"
|
||||||
port = 8080
|
port = 8080
|
||||||
protocol = "HTTP"
|
protocol = "HTTP"
|
||||||
vpc_id = aws_vpc.this.id
|
vpc_id = local.vpc_id
|
||||||
target_type = "ip"
|
target_type = "ip"
|
||||||
|
|
||||||
health_check {
|
health_check {
|
||||||
|
|
@ -202,7 +202,7 @@ resource "aws_ecs_service" "api" {
|
||||||
launch_type = "FARGATE"
|
launch_type = "FARGATE"
|
||||||
|
|
||||||
network_configuration {
|
network_configuration {
|
||||||
subnets = aws_subnet.public[*].id
|
subnets = local.public_subnet_ids
|
||||||
security_groups = [aws_security_group.api.id]
|
security_groups = [aws_security_group.api.id]
|
||||||
assign_public_ip = true
|
assign_public_ip = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ locals {
|
||||||
|
|
||||||
github_oidc_provider_arn = "arn:aws:iam::${local.account_id}:oidc-provider/token.actions.githubusercontent.com"
|
github_oidc_provider_arn = "arn:aws:iam::${local.account_id}:oidc-provider/token.actions.githubusercontent.com"
|
||||||
|
|
||||||
# Prod has no default VPC. 10.60 is unused in 011934824531
|
# Created only when existing_vpc_id is empty. 10.60 is unused in 011934824531.
|
||||||
# (10.0 proposal-system, 10.20 payments-dashboard, 10.40 syslog, 10.80 apm-wo).
|
manage_vpc = var.existing_vpc_id == ""
|
||||||
vpc_cidr = "10.60.0.0/16"
|
vpc_cidr = "10.60.0.0/16"
|
||||||
public_subnet_cidrs = ["10.60.0.0/24", "10.60.1.0/24"]
|
public_subnet_cidrs = ["10.60.0.0/24", "10.60.1.0/24"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,3 +91,15 @@ variable "checkcomponents_queue_arn" {
|
||||||
type = string
|
type = string
|
||||||
default = "arn:aws:sqs:us-east-1:011934824531:paychex-checkcomponents"
|
default = "arn:aws:sqs:us-east-1:011934824531:paychex-checkcomponents"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "existing_vpc_id" {
|
||||||
|
description = "When set, place the ALB and Fargate tasks in this VPC instead of creating one."
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "existing_public_subnet_ids" {
|
||||||
|
description = "Public subnet IDs in existing_vpc_id. Required with existing_vpc_id; ignored when that variable is empty."
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
data "aws_availability_zones" "available" {
|
data "aws_availability_zones" "available" {
|
||||||
|
count = local.manage_vpc ? 1 : 0
|
||||||
state = "available"
|
state = "available"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data "aws_vpc" "existing" {
|
||||||
|
count = local.manage_vpc ? 0 : 1
|
||||||
|
id = var.existing_vpc_id
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_subnet" "existing_public" {
|
||||||
|
for_each = toset(var.existing_public_subnet_ids)
|
||||||
|
id = each.value
|
||||||
|
}
|
||||||
|
|
||||||
resource "aws_vpc" "this" {
|
resource "aws_vpc" "this" {
|
||||||
|
count = local.manage_vpc ? 1 : 0
|
||||||
|
|
||||||
cidr_block = local.vpc_cidr
|
cidr_block = local.vpc_cidr
|
||||||
enable_dns_support = true
|
enable_dns_support = true
|
||||||
enable_dns_hostnames = true
|
enable_dns_hostnames = true
|
||||||
|
|
@ -19,7 +32,9 @@ resource "aws_vpc" "this" {
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_internet_gateway" "this" {
|
resource "aws_internet_gateway" "this" {
|
||||||
vpc_id = aws_vpc.this.id
|
count = local.manage_vpc ? 1 : 0
|
||||||
|
|
||||||
|
vpc_id = aws_vpc.this[0].id
|
||||||
|
|
||||||
tags = {
|
tags = {
|
||||||
Name = "${local.project}-igw"
|
Name = "${local.project}-igw"
|
||||||
|
|
@ -27,11 +42,11 @@ resource "aws_internet_gateway" "this" {
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_subnet" "public" {
|
resource "aws_subnet" "public" {
|
||||||
count = length(local.public_subnet_cidrs)
|
count = local.manage_vpc ? length(local.public_subnet_cidrs) : 0
|
||||||
|
|
||||||
vpc_id = aws_vpc.this.id
|
vpc_id = aws_vpc.this[0].id
|
||||||
cidr_block = local.public_subnet_cidrs[count.index]
|
cidr_block = local.public_subnet_cidrs[count.index]
|
||||||
availability_zone = data.aws_availability_zones.available.names[count.index]
|
availability_zone = data.aws_availability_zones.available[0].names[count.index]
|
||||||
map_public_ip_on_launch = true
|
map_public_ip_on_launch = true
|
||||||
|
|
||||||
tags = {
|
tags = {
|
||||||
|
|
@ -40,7 +55,9 @@ resource "aws_subnet" "public" {
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_route_table" "public" {
|
resource "aws_route_table" "public" {
|
||||||
vpc_id = aws_vpc.this.id
|
count = local.manage_vpc ? 1 : 0
|
||||||
|
|
||||||
|
vpc_id = aws_vpc.this[0].id
|
||||||
|
|
||||||
tags = {
|
tags = {
|
||||||
Name = "${local.project}-public"
|
Name = "${local.project}-public"
|
||||||
|
|
@ -48,14 +65,46 @@ resource "aws_route_table" "public" {
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_route" "public_default" {
|
resource "aws_route" "public_default" {
|
||||||
route_table_id = aws_route_table.public.id
|
count = local.manage_vpc ? 1 : 0
|
||||||
|
|
||||||
|
route_table_id = aws_route_table.public[0].id
|
||||||
destination_cidr_block = "0.0.0.0/0"
|
destination_cidr_block = "0.0.0.0/0"
|
||||||
gateway_id = aws_internet_gateway.this.id
|
gateway_id = aws_internet_gateway.this[0].id
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_route_table_association" "public" {
|
resource "aws_route_table_association" "public" {
|
||||||
count = length(local.public_subnet_cidrs)
|
count = local.manage_vpc ? length(local.public_subnet_cidrs) : 0
|
||||||
|
|
||||||
subnet_id = aws_subnet.public[count.index].id
|
subnet_id = aws_subnet.public[count.index].id
|
||||||
route_table_id = aws_route_table.public.id
|
route_table_id = aws_route_table.public[0].id
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
vpc_id = local.manage_vpc ? aws_vpc.this[0].id : data.aws_vpc.existing[0].id
|
||||||
|
public_subnet_ids = local.manage_vpc ? aws_subnet.public[*].id : var.existing_public_subnet_ids
|
||||||
|
}
|
||||||
|
|
||||||
|
moved {
|
||||||
|
from = aws_vpc.this
|
||||||
|
to = aws_vpc.this[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
moved {
|
||||||
|
from = aws_internet_gateway.this
|
||||||
|
to = aws_internet_gateway.this[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
moved {
|
||||||
|
from = aws_route_table.public
|
||||||
|
to = aws_route_table.public[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
moved {
|
||||||
|
from = aws_route.public_default
|
||||||
|
to = aws_route.public_default[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
moved {
|
||||||
|
from = data.aws_availability_zones.available
|
||||||
|
to = data.aws_availability_zones.available[0]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Meals owns a dedicated VPC. Prod has no default VPC."""
|
"""Meals creates a VPC unless existing_vpc_id is set (prod shares afterhours)."""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
@ -14,13 +14,22 @@ def test_meals_owns_a_vpc_instead_of_looking_up_default():
|
||||||
vpc = _read("vpc.tf")
|
vpc = _read("vpc.tf")
|
||||||
ecs = _read("ecs.tf")
|
ecs = _read("ecs.tf")
|
||||||
locals_tf = _read("locals.tf")
|
locals_tf = _read("locals.tf")
|
||||||
|
variables = _read("variables.tf")
|
||||||
|
data = _read("data.tf")
|
||||||
|
|
||||||
assert 'resource "aws_vpc" "this"' in vpc
|
assert 'resource "aws_vpc" "this"' in vpc
|
||||||
assert "cidr_block = local.vpc_cidr" in vpc
|
assert "count = local.manage_vpc ? 1 : 0" in vpc
|
||||||
assert 'vpc_cidr = "10.60.0.0/16"' in locals_tf
|
assert 'variable "existing_vpc_id"' in variables
|
||||||
|
assert 'variable "existing_public_subnet_ids"' in variables
|
||||||
|
assert 'manage_vpc = var.existing_vpc_id == ""' in locals_tf
|
||||||
assert 'data "aws_vpc" "default"' not in ecs
|
assert 'data "aws_vpc" "default"' not in ecs
|
||||||
assert "data.aws_vpc.default" not in ecs
|
assert "data.aws_vpc.default" not in ecs
|
||||||
assert "data.aws_subnets.default" not in ecs
|
assert "data.aws_subnets.default" not in ecs
|
||||||
assert "aws_vpc.this.id" in ecs
|
assert "vpc_id = local.vpc_id" in ecs
|
||||||
assert "aws_subnet.public[*].id" in ecs
|
assert "subnets = local.public_subnet_ids" in ecs
|
||||||
|
assert "subnets = local.public_subnet_ids" in ecs
|
||||||
assert "ec2:CreateVpc" in _read("hcp_iam.tf")
|
assert "ec2:CreateVpc" in _read("hcp_iam.tf")
|
||||||
|
assert 'check "existing_vpc_pair"' in data
|
||||||
|
assert 'check "existing_subnets_in_vpc"' in data
|
||||||
|
assert "from = aws_vpc.this" in vpc
|
||||||
|
assert "to = aws_vpc.this[0]" in vpc
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue