diff --git a/modules/capacity-reservation/README.md b/modules/capacity-reservation/README.md new file mode 100644 index 00000000..1b7da203 --- /dev/null +++ b/modules/capacity-reservation/README.md @@ -0,0 +1,106 @@ +# capacity-reservation + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.7.0 | +| [aws](#requirement\_aws) | ~> 5.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | ~> 5.0 | +| [terraform](#provider\_terraform) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_ec2_capacity_reservation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_capacity_reservation) | resource | +| [terraform_data.describe_capacity_reservation](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource | +| [aws_availability_zone.zone_ids](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zone) | data source | +| [aws_ec2_instance_type_offerings.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ec2_instance_type_offerings) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [instance\_capacity](#input\_instance\_capacity) | Creates a capacity reservation for each instance\_type on each zone.
instance\_types = List of instance types to create a capacity reservation for.
capacity = Number of instances to reserve
availability\_zone\_ids = List of azs to create a capacity reservation in.
} |
map(object({
instance_types = list(string)
capacity = number
availability_zone_ids = list(string)
}))
| `{}` | no | +| [region](#input\_region) | AWS region for the deployment | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [capacity\_reservation](#output\_capacity\_reservation) | Capacity Reservations information. | + + +## Usage + +Create the following files: +* `main.tf`. :warning: Update with intended module version(using `main` in the example below). +* `capacity.auto.tfvars`. :warning: Update with appropriate values. + +`main.tf` + +```hcl +variable "instance_capacity" { + description = "Additional EKS managed node groups definition." + type = map(object({ + instance_types = list(string) + capacity = number + availability_zone_ids = list(string) + })) + default = {} +} + +variable "region" { + default = "us-west-2" +} + + +module "capacity_reservation" { + source = "github.com/dominodatalab/terraform-aws-eks.git//modules/capacity-reservation?ref=main" + instance_capacity = var.instance_capacity + region = var.region +} + +output "capacity_reservation" { + + value = module.capacity_reservation.capacity_reservation +} + +provider "aws" { + region = var.region +} +``` + +`capacity.auto.tfvars` + +```hcl +region = "us-west-2" +instance_capacity = { + custom_1 = { + availability_zone_ids = ["usw2-az1", "usw2-az4"] + capacity = 4 + instance_types = ["trn1.2xlarge"] + } + custom_2 = { + availability_zone_ids = ["usw2-az1", "usw2-az4"] + capacity = 4 + instance_types = ["i4i.32xlarge"] + } + custom_3 = { + availability_zone_ids = ["usw2-az1", "usw2-az3"] + capacity = 4 + instance_types = ["p3.8xlarge"] + } +} +``` diff --git a/modules/capacity-reservation/main.tf b/modules/capacity-reservation/main.tf new file mode 100644 index 00000000..7407ceb2 --- /dev/null +++ b/modules/capacity-reservation/main.tf @@ -0,0 +1,67 @@ +locals { + capacity_reservations = merge(flatten([ + for ng_name, ng in var.instance_capacity : [ + for az_id in ng.availability_zone_ids : { + for type in ng.instance_types : "${type}-${az_id}" => { + capacity = ng.capacity + instance_type = type + az = data.aws_availability_zone.zone_ids[az_id].name + } + } + ] + ])...) + zone_ids = toset(flatten([for ng in var.instance_capacity : + ng.availability_zone_ids + ])) + + instance_types = toset([for cr in local.capacity_reservations : cr.instance_type]) +} + +data "aws_availability_zone" "zone_ids" { + for_each = local.zone_ids + zone_id = each.key +} + + +data "aws_ec2_instance_type_offerings" "this" { + for_each = local.instance_types + + filter { + name = "instance-type" + values = [each.key] + } + + location_type = "availability-zone" +} + + +resource "aws_ec2_capacity_reservation" "this" { + for_each = local.capacity_reservations + instance_type = each.value.instance_type + instance_platform = "Linux/UNIX" + availability_zone = each.value.az + instance_count = each.value.capacity + + lifecycle { + precondition { + condition = contains(data.aws_ec2_instance_type_offerings.this[each.value.instance_type].locations, each.value.az) + error_message = <<-EOM + Instance type ${each.value.instance_type} is NOT available in availability_zone ${each.value.az}. + available = ${jsonencode(data.aws_ec2_instance_type_offerings.this[each.value.instance_type].locations)} + EOM + } + } +} + +resource "terraform_data" "describe_capacity_reservation" { + for_each = aws_ec2_capacity_reservation.this + + provisioner "local-exec" { + command = <