From 6a123adb10393759fcdd18795fbf1484c5f44dde Mon Sep 17 00:00:00 2001 From: Samuel CHNIBER <75125134+schniber@users.noreply.github.com> Date: Wed, 31 May 2023 00:55:33 +0200 Subject: [PATCH] feat: Implementation of the cpu_options block and addition of support for AMD SEV-SNP (#334) Co-authored-by: Samuel CHNIBER --- README.md | 5 +- examples/complete/README.md | 6 ++- examples/complete/main.tf | 89 +++++++++++++++++++++++++++++++++-- examples/complete/versions.tf | 2 +- main.tf | 30 ++++++++++++ variables.tf | 6 +++ versions.tf | 2 +- wrappers/main.tf | 1 + 8 files changed, 130 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 33d8151c..62540a88 100644 --- a/README.md +++ b/README.md @@ -162,13 +162,13 @@ The following combinations are supported to conditionally create resources: | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.20 | +| [aws](#requirement\_aws) | >= 4.66 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.20 | +| [aws](#provider\_aws) | >= 4.66 | ## Modules @@ -199,6 +199,7 @@ No modules. | [capacity\_reservation\_specification](#input\_capacity\_reservation\_specification) | Describes an instance's Capacity Reservation targeting option | `any` | `{}` | no | | [cpu\_core\_count](#input\_cpu\_core\_count) | Sets the number of CPU cores for an instance | `number` | `null` | no | | [cpu\_credits](#input\_cpu\_credits) | The credit option for CPU usage (unlimited or standard) | `string` | `null` | no | +| [cpu\_options](#input\_cpu\_options) | Defines CPU options to apply to the instance at launch time. | `any` | `{}` | no | | [cpu\_threads\_per\_core](#input\_cpu\_threads\_per\_core) | Sets the number of CPU threads per core for an instance (has no effect unless cpu\_core\_count is also set) | `number` | `null` | no | | [create](#input\_create) | Whether to create an instance | `bool` | `true` | no | | [create\_iam\_instance\_profile](#input\_create\_iam\_instance\_profile) | Determines whether an IAM instance profile is created or to use an existing IAM instance profile | `bool` | `false` | no | diff --git a/examples/complete/README.md b/examples/complete/README.md index 63accd79..18d25d8e 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -20,19 +20,20 @@ Note that this example may create resources which can cost money. Run `terraform | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.20 | +| [aws](#requirement\_aws) | >= 4.66 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.20 | +| [aws](#provider\_aws) | >= 4.66 | ## Modules | Name | Source | Version | |------|--------|---------| | [ec2\_complete](#module\_ec2\_complete) | ../../ | n/a | +| [ec2\_cpu\_options](#module\_ec2\_cpu\_options) | ../../ | n/a | | [ec2\_disabled](#module\_ec2\_disabled) | ../../ | n/a | | [ec2\_metadata\_options](#module\_ec2\_metadata\_options) | ../../ | n/a | | [ec2\_multiple](#module\_ec2\_multiple) | ../../ | n/a | @@ -55,6 +56,7 @@ Note that this example may create resources which can cost money. Run `terraform | [aws_network_interface.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface) | resource | | [aws_placement_group.web](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/placement_group) | resource | | [aws_ami.amazon_linux](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | +| [aws_ami.amazon_linux_23](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | ## Inputs diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 4d181936..0cdd484f 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -54,9 +54,10 @@ module "ec2_complete" { user_data_base64 = base64encode(local.user_data) user_data_replace_on_change = true - cpu_core_count = 2 # default 4 - cpu_threads_per_core = 1 # default 2 - + cpu_options = { + core_count = 2 + threads_per_core = 1 + } enable_volume_tags = false root_block_device = [ { @@ -244,8 +245,10 @@ module "ec2_spot_instance" { user_data_base64 = base64encode(local.user_data) - cpu_core_count = 2 # default 4 - cpu_threads_per_core = 1 # default 2 + cpu_options = { + core_count = 2 + threads_per_core = 1 + } enable_volume_tags = false root_block_device = [ @@ -334,6 +337,72 @@ resource "aws_ec2_capacity_reservation" "targeted" { instance_match_criteria = "targeted" } +################################################################################ +# EC2 Module - CPU Options +################################################################################ +module "ec2_cpu_options" { + source = "../../" + + name = "${local.name}-cpu-options" + + ami = data.aws_ami.amazon_linux_23.id + instance_type = "c6a.xlarge" # used to set core count below and test amd_sev_snp attribute + availability_zone = element(module.vpc.azs, 0) + subnet_id = element(module.vpc.private_subnets, 0) + vpc_security_group_ids = [module.security_group.security_group_id] + placement_group = aws_placement_group.web.id + associate_public_ip_address = true + disable_api_stop = false + + create_iam_instance_profile = true + iam_role_description = "IAM role for EC2 instance" + iam_role_policies = { + AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" + } + + user_data_base64 = base64encode(local.user_data) + user_data_replace_on_change = true + + cpu_options = { + core_count = 2 + threads_per_core = 1 + amd_sev_snp = "enabled" + } + enable_volume_tags = false + root_block_device = [ + { + encrypted = true + volume_type = "gp3" + throughput = 200 + volume_size = 50 + tags = { + Name = "my-root-block" + } + }, + ] + + ebs_block_device = [ + { + device_name = "/dev/sdf" + volume_type = "gp3" + volume_size = 5 + throughput = 200 + encrypted = true + kms_key_id = aws_kms_key.this.arn + tags = { + MountPoint = "/mnt/data" + } + } + ] + + tags = merge( + local.tags, + { + Name = "${local.name}-cpu-options" + } + ) +} + ################################################################################ # Supporting Resources ################################################################################ @@ -362,6 +431,16 @@ data "aws_ami" "amazon_linux" { } } +data "aws_ami" "amazon_linux_23" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["al2023-ami-2023*-x86_64"] + } +} + module "security_group" { source = "terraform-aws-modules/security-group/aws" version = "~> 4.0" diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index eddf9d5b..fd4d1167 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.20" + version = ">= 4.66" } } } diff --git a/main.tf b/main.tf index 46b23b46..90669c21 100644 --- a/main.tf +++ b/main.tf @@ -46,6 +46,16 @@ resource "aws_instance" "this" { ebs_optimized = var.ebs_optimized + dynamic "cpu_options" { + for_each = length(var.cpu_options) > 0 ? [var.cpu_options] : [] + + content { + core_count = try(cpu_options.value.core_count, null) + threads_per_core = try(cpu_options.value.threads_per_core, null) + amd_sev_snp = try(cpu_options.value.amd_sev_snp, null) + } + } + dynamic "capacity_reservation_specification" { for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : [] @@ -204,6 +214,16 @@ resource "aws_instance" "ignore_ami" { ebs_optimized = var.ebs_optimized + dynamic "cpu_options" { + for_each = length(var.cpu_options) > 0 ? [var.cpu_options] : [] + + content { + core_count = try(cpu_options.value.core_count, null) + threads_per_core = try(cpu_options.value.threads_per_core, null) + amd_sev_snp = try(cpu_options.value.amd_sev_snp, null) + } + } + dynamic "capacity_reservation_specification" { for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : [] @@ -379,6 +399,16 @@ resource "aws_spot_instance_request" "this" { valid_from = var.spot_valid_from # End spot request specific attributes + dynamic "cpu_options" { + for_each = length(var.cpu_options) > 0 ? [var.cpu_options] : [] + + content { + core_count = try(cpu_options.value.core_count, null) + threads_per_core = try(cpu_options.value.threads_per_core, null) + amd_sev_snp = try(cpu_options.value.amd_sev_snp, null) + } + } + dynamic "capacity_reservation_specification" { for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : [] diff --git a/variables.tf b/variables.tf index b1b92dbf..2951625e 100644 --- a/variables.tf +++ b/variables.tf @@ -260,6 +260,12 @@ variable "timeouts" { default = {} } +variable "cpu_options" { + description = "Defines CPU options to apply to the instance at launch time." + type = any + default = {} +} + variable "cpu_core_count" { description = "Sets the number of CPU cores for an instance" # This option is only supported on creation of instance type that support CPU Options https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-optimize-cpu.html#cpu-options-supported-instances-values type = number diff --git a/versions.tf b/versions.tf index eddf9d5b..fd4d1167 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.20" + version = ">= 4.66" } } } diff --git a/wrappers/main.tf b/wrappers/main.tf index 12a4b59a..e8d0f591 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -50,6 +50,7 @@ module "wrapper" { enable_volume_tags = try(each.value.enable_volume_tags, var.defaults.enable_volume_tags, true) vpc_security_group_ids = try(each.value.vpc_security_group_ids, var.defaults.vpc_security_group_ids, null) timeouts = try(each.value.timeouts, var.defaults.timeouts, {}) + cpu_options = try(each.value.cpu_options, var.defaults.cpu_options, {}) cpu_core_count = try(each.value.cpu_core_count, var.defaults.cpu_core_count, null) cpu_threads_per_core = try(each.value.cpu_threads_per_core, var.defaults.cpu_threads_per_core, null) create_spot_instance = try(each.value.create_spot_instance, var.defaults.create_spot_instance, false)