diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 424b3710..b84d048d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
- rev: v1.98.0
+ rev: v1.99.4
hooks:
- id: terraform_fmt
- id: terraform_wrapper_module_for_each
diff --git a/README.md b/README.md
index 863555d1..c7d6bd04 100644
--- a/README.md
+++ b/README.md
@@ -14,11 +14,10 @@ module "ec2_instance" {
name = "single-instance"
- instance_type = "t2.micro"
- key_name = "user1"
- monitoring = true
- vpc_security_group_ids = ["sg-12345678"]
- subnet_id = "subnet-eddcdzz4"
+ instance_type = "t2.micro"
+ key_name = "user1"
+ monitoring = true
+ subnet_id = "subnet-eddcdzz4"
tags = {
Terraform = "true"
@@ -37,11 +36,10 @@ module "ec2_instance" {
name = "instance-${each.key}"
- instance_type = "t2.micro"
- key_name = "user1"
- monitoring = true
- vpc_security_group_ids = ["sg-12345678"]
- subnet_id = "subnet-eddcdzz4"
+ instance_type = "t2.micro"
+ key_name = "user1"
+ monitoring = true
+ subnet_id = "subnet-eddcdzz4"
tags = {
Terraform = "true"
@@ -62,11 +60,10 @@ module "ec2_instance" {
spot_price = "0.60"
spot_type = "persistent"
- instance_type = "t2.micro"
- key_name = "user1"
- monitoring = true
- vpc_security_group_ids = ["sg-12345678"]
- subnet_id = "subnet-eddcdzz4"
+ instance_type = "t2.micro"
+ key_name = "user1"
+ monitoring = true
+ subnet_id = "subnet-eddcdzz4"
tags = {
Terraform = "true"
@@ -75,23 +72,16 @@ module "ec2_instance" {
}
```
-## Module wrappers
-
-Users of this Terraform module can create multiple similar resources by using [`for_each` meta-argument within `module` block](https://www.terraform.io/language/meta-arguments/for_each) which became available in Terraform 0.13.
-
-Users of Terragrunt can achieve similar results by using modules provided in the [wrappers](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/wrappers) directory, if they prefer to reduce amount of configuration files.
-
## Examples
- [Complete EC2 instance](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete)
- [EC2 instance w/ private network access via Session Manager](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/session-manager)
-- [EC2 instance with EBS volume attachment](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/volume-attachment)
## Make an encrypted AMI for use
This module does not support encrypted AMI's out of the box however it is easy enough for you to generate one for use
-This example creates an encrypted image from the latest ubuntu 16.04 base image.
+This example creates an encrypted image from the latest ubuntu 20.04 base image.
```hcl
provider "aws" {
@@ -139,22 +129,32 @@ data "aws_ami" "encrypted-ami" {
The following combinations are supported to conditionally create resources:
-- Disable resource creation (no resources created):
-
```hcl
- create = false
-```
+module "ec2_instance" {
+ source = "terraform-aws-modules/ec2-instance/aws"
-- Create spot instance:
+ # Disable creation of EC2 and all resources
+ create = false
-```hcl
+ # Enable creation of spot instance
create_spot_instance = true
+
+ # Enable creation of EC2 IAM instance profile
+ create_iam_instance_profile = true
+
+ # Disable creation of security group
+ create_security_group = false
+
+ # Enable creation of elastic IP
+ create_eip = true
+
+ # ... omitted
+}
```
## Notes
- `network_interface` can't be specified together with `vpc_security_group_ids`, `associate_public_ip_address`, `subnet_id`. See [complete example](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete) for details.
-- Changes in `ebs_block_device` argument will be ignored. Use [aws_volume_attachment](https://www.terraform.io/docs/providers/aws/r/volume_attachment.html) resource to attach and detach volumes from AWS EC2 instances. See [this example](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/volume-attachment).
- In regards to spot instances, you must grant the `AWSServiceRoleForEC2Spot` service-linked role access to any custom KMS keys, otherwise your spot request and instances will fail with `bad parameters`. You can see more details about why the request failed by using the awscli and `aws ec2 describe-spot-instance-requests`
@@ -162,14 +162,14 @@ The following combinations are supported to conditionally create resources:
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 1.0 |
-| [aws](#requirement\_aws) | >= 4.66 |
+| [terraform](#requirement\_terraform) | >= 1.10 |
+| [aws](#requirement\_aws) | >= 6.0 |
## Providers
| Name | Version |
|------|---------|
-| [aws](#provider\_aws) | >= 4.66 |
+| [aws](#provider\_aws) | >= 6.0 |
## Modules
@@ -179,46 +179,54 @@ No modules.
| Name | Type |
|------|------|
+| [aws_ebs_volume.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume) | resource |
+| [aws_ec2_tag.spot_instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag) | resource |
| [aws_eip.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
| [aws_iam_instance_profile.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |
| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_instance.ignore_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
| [aws_instance.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
+| [aws_security_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_spot_instance_request.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/spot_instance_request) | resource |
+| [aws_volume_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/volume_attachment) | resource |
+| [aws_vpc_security_group_egress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource |
+| [aws_vpc_security_group_ingress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource |
| [aws_iam_policy_document.assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_ssm_parameter.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source |
+| [aws_subnet.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [ami](#input\_ami) | ID of AMI to use for the instance | `string` | `null` | no |
-| [ami\_ssm\_parameter](#input\_ami\_ssm\_parameter) | SSM parameter name for the AMI ID. For Amazon Linux AMI SSM parameters see [reference](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters-ami.html) | `string` | `"/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"` | no |
+| [ami\_ssm\_parameter](#input\_ami\_ssm\_parameter) | SSM parameter name for the AMI ID. For Amazon Linux AMI SSM parameters see [reference](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters-ami.html) | `string` | `"/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"` | no |
| [associate\_public\_ip\_address](#input\_associate\_public\_ip\_address) | Whether to associate a public IP address with an instance in a VPC | `bool` | `null` | no |
| [availability\_zone](#input\_availability\_zone) | AZ to start the instance in | `string` | `null` | no |
-| [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 |
+| [capacity\_reservation\_specification](#input\_capacity\_reservation\_specification) | Describes an instance's Capacity Reservation targeting option |
object({
capacity_reservation_preference = optional(string)
capacity_reservation_target = optional(object({
capacity_reservation_id = optional(string)
capacity_reservation_resource_group_arn = optional(string)
}))
})
| `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 |
+| [cpu\_options](#input\_cpu\_options) | Defines CPU options to apply to the instance at launch time. | object({
amd_sev_snp = optional(string)
core_count = optional(number)
threads_per_core = optional(number)
})
| `null` | no |
| [create](#input\_create) | Whether to create an instance | `bool` | `true` | no |
| [create\_eip](#input\_create\_eip) | Determines whether a public EIP will be created and associated with the instance. | `bool` | `false` | 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 |
+| [create\_security\_group](#input\_create\_security\_group) | Determines whether a security group will be created | `bool` | `true` | no |
| [create\_spot\_instance](#input\_create\_spot\_instance) | Depicts if the instance is a spot instance | `bool` | `false` | no |
| [disable\_api\_stop](#input\_disable\_api\_stop) | If true, enables EC2 Instance Stop Protection | `bool` | `null` | no |
| [disable\_api\_termination](#input\_disable\_api\_termination) | If true, enables EC2 Instance Termination Protection | `bool` | `null` | no |
-| [ebs\_block\_device](#input\_ebs\_block\_device) | Additional EBS block devices to attach to the instance | `list(any)` | `[]` | no |
| [ebs\_optimized](#input\_ebs\_optimized) | If true, the launched EC2 instance will be EBS-optimized | `bool` | `null` | no |
+| [ebs\_volumes](#input\_ebs\_volumes) | Additional EBS volumes to attach to the instance | map(object({
encrypted = optional(bool)
final_snapshot = optional(bool)
iops = optional(number)
kms_key_id = optional(string)
multi_attach_enabled = optional(bool)
outpost_arn = optional(string)
size = optional(number)
snapshot_id = optional(string)
tags = optional(map(string), {})
throughput = optional(number)
type = optional(string, "gp3")
# Attachment
device_name = optional(string) # Will fall back to use map key as device name
force_detach = optional(bool)
skip_destroy = optional(bool)
stop_instance_before_detaching = optional(bool)
}))
| `null` | no |
| [eip\_domain](#input\_eip\_domain) | Indicates if this EIP is for use in VPC | `string` | `"vpc"` | no |
| [eip\_tags](#input\_eip\_tags) | A map of additional tags to add to the eip | `map(string)` | `{}` | no |
+| [enable\_primary\_ipv6](#input\_enable\_primary\_ipv6) | Whether to assign a primary IPv6 Global Unicast Address (GUA) to the instance when launched in a dual-stack or IPv6-only subnet | `bool` | `null` | no |
| [enable\_volume\_tags](#input\_enable\_volume\_tags) | Whether to enable volume tags (if enabled it conflicts with root\_block\_device tags) | `bool` | `true` | no |
| [enclave\_options\_enabled](#input\_enclave\_options\_enabled) | Whether Nitro Enclaves will be enabled on the instance. Defaults to `false` | `bool` | `null` | no |
-| [ephemeral\_block\_device](#input\_ephemeral\_block\_device) | Customize Ephemeral (also known as Instance Store) volumes on the instance | `list(map(string))` | `[]` | no |
+| [ephemeral\_block\_device](#input\_ephemeral\_block\_device) | Customize Ephemeral (also known as Instance Store) volumes on the instance | map(object({
device_name = string
no_device = optional(bool)
virtual_name = optional(string)
}))
| `null` | no |
| [get\_password\_data](#input\_get\_password\_data) | If true, wait for password data to become available and retrieve it | `bool` | `null` | no |
| [hibernation](#input\_hibernation) | If true, the launched EC2 instance will support hibernation | `bool` | `null` | no |
| [host\_id](#input\_host\_id) | ID of a dedicated host that the instance will be assigned to. Use when an instance is to be launched on a specific dedicated host | `string` | `null` | no |
+| [host\_resource\_group\_arn](#input\_host\_resource\_group\_arn) | ARN of the host resource group in which to launch the instances. If you specify an ARN, omit the `tenancy` parameter or set it to `host` | `string` | `null` | no |
| [iam\_instance\_profile](#input\_iam\_instance\_profile) | IAM Instance Profile to launch the instance with. Specified as the name of the Instance Profile | `string` | `null` | no |
| [iam\_role\_description](#input\_iam\_role\_description) | Description of the role | `string` | `null` | no |
| [iam\_role\_name](#input\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no |
@@ -229,25 +237,34 @@ No modules.
| [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name` or `name`) is used as a prefix | `bool` | `true` | no |
| [ignore\_ami\_changes](#input\_ignore\_ami\_changes) | Whether changes to the AMI ID changes should be ignored by Terraform. Note - changing this value will result in the replacement of the instance | `bool` | `false` | no |
| [instance\_initiated\_shutdown\_behavior](#input\_instance\_initiated\_shutdown\_behavior) | Shutdown behavior for the instance. Amazon defaults this to stop for EBS-backed instances and terminate for instance-store instances. Cannot be set on instance-store instance | `string` | `null` | no |
+| [instance\_market\_options](#input\_instance\_market\_options) | The market (purchasing) option for the instance. If set, overrides the `create_spot_instance` variable | object({
market_type = optional(string)
spot_options = optional(object({
instance_interruption_behavior = optional(string)
max_price = optional(string)
spot_instance_type = optional(string)
valid_until = optional(string)
}))
})
| `null` | no |
| [instance\_tags](#input\_instance\_tags) | Additional tags for the instance | `map(string)` | `{}` | no |
| [instance\_type](#input\_instance\_type) | The type of instance to start | `string` | `"t3.micro"` | no |
| [ipv6\_address\_count](#input\_ipv6\_address\_count) | A number of IPv6 addresses to associate with the primary network interface. Amazon EC2 chooses the IPv6 addresses from the range of your subnet | `number` | `null` | no |
| [ipv6\_addresses](#input\_ipv6\_addresses) | Specify one or more IPv6 addresses from the range of the subnet to associate with the primary network interface | `list(string)` | `null` | no |
| [key\_name](#input\_key\_name) | Key name of the Key Pair to use for the instance; which can be managed using the `aws_key_pair` resource | `string` | `null` | no |
-| [launch\_template](#input\_launch\_template) | Specifies a Launch Template to configure the instance. Parameters configured on this resource will override the corresponding parameters in the Launch Template | `map(string)` | `{}` | no |
-| [maintenance\_options](#input\_maintenance\_options) | The maintenance options for the instance | `any` | `{}` | no |
-| [metadata\_options](#input\_metadata\_options) | Customize the metadata options of the instance | `map(string)` | {
"http_endpoint": "enabled",
"http_put_response_hop_limit": 1,
"http_tokens": "required"
}
| no |
+| [launch\_template](#input\_launch\_template) | Specifies a Launch Template to configure the instance. Parameters configured on this resource will override the corresponding parameters in the Launch Template | object({
id = optional(string)
name = optional(string)
version = optional(string)
})
| `null` | no |
+| [maintenance\_options](#input\_maintenance\_options) | The maintenance options for the instance | object({
auto_recovery = optional(string)
})
| `null` | no |
+| [metadata\_options](#input\_metadata\_options) | Customize the metadata options of the instance | object({
http_endpoint = optional(string, "enabled")
http_protocol_ipv6 = optional(string)
http_put_response_hop_limit = optional(number, 1)
http_tokens = optional(string, "required")
instance_metadata_tags = optional(string)
})
| {
"http_endpoint": "enabled",
"http_put_response_hop_limit": 1,
"http_tokens": "required"
}
| no |
| [monitoring](#input\_monitoring) | If true, the launched EC2 instance will have detailed monitoring enabled | `bool` | `null` | no |
| [name](#input\_name) | Name to be used on EC2 instance created | `string` | `""` | no |
-| [network\_interface](#input\_network\_interface) | Customize network interfaces to be attached at instance boot time | `list(map(string))` | `[]` | no |
+| [network\_interface](#input\_network\_interface) | Customize network interfaces to be attached at instance boot time | map(object({
delete_on_termination = optional(bool)
device_index = optional(number) # Will fall back to use map key as device index
network_card_index = optional(number)
network_interface_id = string
}))
| `null` | no |
| [placement\_group](#input\_placement\_group) | The Placement Group to start the instance in | `string` | `null` | no |
-| [private\_dns\_name\_options](#input\_private\_dns\_name\_options) | Customize the private DNS name options of the instance | `map(string)` | `{}` | no |
+| [placement\_partition\_number](#input\_placement\_partition\_number) | Number of the partition the instance is in. Valid only if the `aws_placement_group` resource's `strategy` argument is set to `partition` | `number` | `null` | no |
+| [private\_dns\_name\_options](#input\_private\_dns\_name\_options) | Customize the private DNS name options of the instance | object({
enable_resource_name_dns_a_record = optional(bool)
enable_resource_name_dns_aaaa_record = optional(bool)
hostname_type = optional(string)
})
| `null` | no |
| [private\_ip](#input\_private\_ip) | Private IP address to associate with the instance in a VPC | `string` | `null` | no |
| [putin\_khuylo](#input\_putin\_khuylo) | Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo! | `bool` | `true` | no |
-| [root\_block\_device](#input\_root\_block\_device) | Customize details about the root block device of the instance. See Block Devices below for details | `list(any)` | `[]` | no |
+| [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | `string` | `null` | no |
+| [root\_block\_device](#input\_root\_block\_device) | Customize details about the root block device of the instance. See Block Devices below for details | object({
delete_on_termination = optional(bool)
encrypted = optional(bool)
iops = optional(number)
kms_key_id = optional(string)
tags = optional(map(string), {})
throughput = optional(number)
size = optional(number)
type = optional(string)
})
| `null` | no |
| [secondary\_private\_ips](#input\_secondary\_private\_ips) | A list of secondary private IPv4 addresses to assign to the instance's primary network interface (eth0) in a VPC. Can only be assigned to the primary network interface (eth0) attached at instance creation, not a pre-existing network interface i.e. referenced in a `network_interface block` | `list(string)` | `null` | no |
+| [security\_group\_description](#input\_security\_group\_description) | Description of the security group | `string` | `null` | no |
+| [security\_group\_egress\_rules](#input\_security\_group\_egress\_rules) | Egress rules to add to the security group | map(object({
cidr_ipv4 = optional(string)
cidr_ipv6 = optional(string)
description = optional(string)
from_port = optional(number)
ip_protocol = optional(string, "tcp")
prefix_list_id = optional(string)
referenced_security_group_id = optional(string)
tags = optional(map(string), {})
to_port = optional(number)
}))
| {
"ipv4_default": {
"cidr_ipv4": "0.0.0.0/0",
"description": "Allow all IPv4 traffic",
"ip_protocol": "-1"
},
"ipv6_default": {
"cidr_ipv6": "::/0",
"description": "Allow all IPv6 traffic",
"ip_protocol": "-1"
}
}
| no |
+| [security\_group\_ingress\_rules](#input\_security\_group\_ingress\_rules) | Egress rules to add to the security group | map(object({
cidr_ipv4 = optional(string)
cidr_ipv6 = optional(string)
description = optional(string)
from_port = optional(number)
ip_protocol = optional(string, "tcp")
prefix_list_id = optional(string)
referenced_security_group_id = optional(string)
tags = optional(map(string), {})
to_port = optional(number)
}))
| `null` | no |
+| [security\_group\_name](#input\_security\_group\_name) | Name to use on security group created | `string` | `null` | no |
+| [security\_group\_tags](#input\_security\_group\_tags) | A map of additional tags to add to the security group created | `map(string)` | `{}` | no |
+| [security\_group\_use\_name\_prefix](#input\_security\_group\_use\_name\_prefix) | Determines whether the security group name (`security_group_name` or `name`) is used as a prefix | `bool` | `true` | no |
+| [security\_group\_vpc\_id](#input\_security\_group\_vpc\_id) | VPC ID to create the security group in. If not set, the security group will be created in the default VPC | `string` | `null` | no |
| [source\_dest\_check](#input\_source\_dest\_check) | Controls if traffic is routed to the instance when the destination address does not match the instance. Used for NAT or VPNs | `bool` | `null` | no |
-| [spot\_block\_duration\_minutes](#input\_spot\_block\_duration\_minutes) | The required duration for the Spot instances, in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, or 360) | `number` | `null` | no |
| [spot\_instance\_interruption\_behavior](#input\_spot\_instance\_interruption\_behavior) | Indicates Spot instance behavior when it is interrupted. Valid values are `terminate`, `stop`, or `hibernate` | `string` | `null` | no |
| [spot\_launch\_group](#input\_spot\_launch\_group) | A launch group is a group of spot instances that launch together and terminate together. If left empty instances are launched and terminated individually | `string` | `null` | no |
| [spot\_price](#input\_spot\_price) | The maximum price to request on the spot market. Defaults to on-demand price | `string` | `null` | no |
@@ -263,7 +280,7 @@ No modules.
| [user\_data\_base64](#input\_user\_data\_base64) | Can be used instead of user\_data to pass base64-encoded binary data directly. Use this instead of user\_data whenever the value is not a valid UTF-8 string. For example, gzip-encoded user data must be base64-encoded and passed via this argument to avoid corruption | `string` | `null` | no |
| [user\_data\_replace\_on\_change](#input\_user\_data\_replace\_on\_change) | When used in combination with user\_data or user\_data\_base64 will trigger a destroy and recreate when set to true. Defaults to false if not set | `bool` | `null` | no |
| [volume\_tags](#input\_volume\_tags) | A mapping of tags to assign to the devices created by the instance at launch time | `map(string)` | `{}` | no |
-| [vpc\_security\_group\_ids](#input\_vpc\_security\_group\_ids) | A list of security group IDs to associate with | `list(string)` | `null` | no |
+| [vpc\_security\_group\_ids](#input\_vpc\_security\_group\_ids) | A list of security group IDs to associate with | `list(string)` | `[]` | no |
## Outputs
@@ -274,6 +291,7 @@ No modules.
| [availability\_zone](#output\_availability\_zone) | The availability zone of the created instance |
| [capacity\_reservation\_specification](#output\_capacity\_reservation\_specification) | Capacity reservation specification of the instance |
| [ebs\_block\_device](#output\_ebs\_block\_device) | EBS block device information |
+| [ebs\_volumes](#output\_ebs\_volumes) | Map of EBS volumes created and their attributes |
| [ephemeral\_block\_device](#output\_ephemeral\_block\_device) | Ephemeral block device information |
| [iam\_instance\_profile\_arn](#output\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile |
| [iam\_instance\_profile\_id](#output\_iam\_instance\_profile\_id) | Instance profile's ID |
diff --git a/UPGRADE-3.0.md b/docs/UPGRADE-3.0.md
similarity index 96%
rename from UPGRADE-3.0.md
rename to docs/UPGRADE-3.0.md
index 46175fb0..7bdfea98 100644
--- a/UPGRADE-3.0.md
+++ b/docs/UPGRADE-3.0.md
@@ -3,7 +3,6 @@
If you have any questions regarding this upgrade process, please consult the `examples` directory:
- [Complete](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete)
-- [Volume Attachment](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/volume-attachment)
If you find a bug, please open an issue with supporting configuration to reproduce.
diff --git a/docs/UPGRADE-6.0.md b/docs/UPGRADE-6.0.md
new file mode 100644
index 00000000..72d96976
--- /dev/null
+++ b/docs/UPGRADE-6.0.md
@@ -0,0 +1,183 @@
+# Upgrade from v5.x to v6.x
+
+If you have any questions regarding this upgrade process, please consult the `examples` directory:
+
+- [Complete](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete)
+
+If you find a bug, please open an issue with supporting configuration to reproduce.
+
+## List of backwards incompatible changes
+
+- Terraform v1.10.0 is now minimum supported version
+- AWS provider v6.0.0 is now minimum supported version
+- The default value for `ami_ssm_parameter` was changed from `"/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"` to `"/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"`. AL2 is approaching end of life.
+
+## Additional changes
+
+### Added
+
+- Support for creating a security group within the module; this is now the default behavior and can be disabled by setting `create_security_group = false`.
+- Support for `region` parameter to specify the AWS region for the resources created if different from the provider region.
+- Support for tagging spot instances
+
+### Modified
+
+- Variable definitions now contain detailed `object` types in place of the previously used `any` type.
+- Inline `ebs_block_device` argument has been removed in favor of `ebs_volumes` which is a map of EBS volumes created through `aws_ebs_volume` and `aws_ebs_volume_attachment` resources. This provides the same API as before, but allows for more flexibility without generating diffs when adding or removing EBS volumes as well as unintended changes to the volumes.
+- Correct tag precedence ordering (least specific to most specific)
+
+### Removed
+
+- The `volume-attachment` example has been removed since the module has been updated to use the corrected form of EBS volume creation and attachment (tl;dr - example is no longer useful).
+
+### Variable and output changes
+
+1. Removed variables:
+
+ - `cpu_core_count` - removed from provider `v6.x`
+ - `cpu_threads_per_core` - removed from provider `v6.x`
+
+2. Renamed variables:
+
+ - `ebs_block_device` -> `ebs_volumes`
+
+3. Added variables:
+
+ - `region`
+ - `enable_primary_ipv6`
+ - `host_resource_group_arn`
+ - `instance_market_options`
+ - `placement_partition_number`
+ - `create_security_group`
+ - `security_group_name`
+ - `security_group_use_name_prefix`
+ - `security_group_description`
+ - `security_group_vpc_id`
+ - `security_group_tags`
+ - `security_group_egress_rules`
+ - `security_group_ingress_rules`
+
+4. Removed outputs:
+
+ - None
+
+5. Renamed outputs:
+
+ - None
+
+6. Added outputs:
+
+ - `ebs_volumes`
+
+## Upgrade State Migrations
+
+### Before 5.x Example
+
+```hcl
+module "ec2_upgrade" {
+ source = "terraform-aws-modules/ec2-instance/aws"
+ version = "5.8.0"
+
+ # Truncated for brevity, only relevant module API changes are shown ...
+
+ root_block_device = [
+ {
+ encrypted = true
+ volume_size = 50
+ volume_type = "gp3"
+ throughput = 200
+ tags = {
+ Name = "my-root-block"
+ }
+ },
+ ]
+
+ ebs_block_device = [
+ {
+ device_name = "/dev/sdf"
+ encrypted = true
+ volume_size = 5
+ volume_type = "gp3"
+ throughput = 200
+ tags = {
+ MountPoint = "/mnt/data"
+ }
+ }
+ ]
+
+ network_interface = [
+ {
+ device_index = 0
+ network_interface_id = aws_network_interface.this.id
+ delete_on_termination = false
+ }
+ ]
+
+ tags = local.tags
+}
+```
+
+### After 6.x Example
+
+```hcl
+module "ec2_upgrade" {
+ source = "terraform-aws-modules/ec2-instance/aws"
+ version = "6.0.0"
+
+ # Truncated for brevity, only relevant module API changes are shown ...
+
+ # There can only be one root block device, so the wrapping list is removed
+ root_block_device = {
+ encrypted = true
+ size = 50 # Was `volume_size`
+ type = "gp3" # Was `volume_type`
+ throughput = 200
+ tags = {
+ Name = "my-root-block"
+ }
+ }
+
+ # Now a map of EBS volumes is used instead of a list
+ ebs_volumes = {
+ # The device_name can be the key of the map, or set by `device_name` attribute
+ "/dev/sdf" = {
+ encrypted = true
+ size = 5 # Was `volume_size`
+ type = "gp3" # Was `volume_type`, `gp3` is now the default
+ throughput = 200
+ tags = {
+ MountPoint = "/mnt/data"
+ }
+ }
+ }
+
+ # Now a map of network interfaces is used instead of a list
+ network_interface = {
+ # The device_index can be the key of the map, or set by `device_index` attribute
+ 0 = {
+ network_interface_id = aws_network_interface.this.id
+ delete_on_termination = false
+ }
+ }
+
+ tags = local.tags
+}
+```
+
+To migrate from the `v5.x` version to `v6.x` version example shown above, the following state move commands can be performed to maintain the current resources without modification:
+
+> [!NOTE]
+> State move commands should only be required on instances that have additional EBS volumes attached to them.
+
+```bash
+terraform state rm 'module.ec2_complete.aws_instance.this[0]'
+terraform import 'module.ec2_complete.aws_instance.this[0]'
+
+# Do the following for each additional EBS volume attached to the instance
+terraform import 'module.ec2_complete.aws_ebs_volume.this["/dev/sdf"]'
+terraform import 'module.ec2_complete.aws_volume_attachment.this["/dev/sdf"]' ::
+```
+
+> [!TIP]
+> If you encounter a situation where Terraform wants to recreate the instance due to user data changes, you can set the `user_data_replace_on_change` variable to `false` to prevent this behavior.
+> This is related to https://github.com/hashicorp/terraform-provider-aws/issues/5011
diff --git a/examples/complete/README.md b/examples/complete/README.md
index 1658ff2a..f0b0d11d 100644
--- a/examples/complete/README.md
+++ b/examples/complete/README.md
@@ -19,21 +19,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.66 |
+| [terraform](#requirement\_terraform) | >= 1.10 |
+| [aws](#requirement\_aws) | >= 6.0 |
## Providers
| Name | Version |
|------|---------|
-| [aws](#provider\_aws) | >= 4.66 |
+| [aws](#provider\_aws) | >= 6.0 |
## 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\_ignore\_ami\_changes](#module\_ec2\_ignore\_ami\_changes) | ../../ | n/a |
| [ec2\_metadata\_options](#module\_ec2\_metadata\_options) | ../../ | n/a |
@@ -44,8 +43,8 @@ Note that this example may create resources which can cost money. Run `terraform
| [ec2\_t2\_unlimited](#module\_ec2\_t2\_unlimited) | ../../ | n/a |
| [ec2\_t3\_unlimited](#module\_ec2\_t3\_unlimited) | ../../ | n/a |
| [ec2\_targeted\_capacity\_reservation](#module\_ec2\_targeted\_capacity\_reservation) | ../../ | n/a |
-| [security\_group](#module\_security\_group) | terraform-aws-modules/security-group/aws | ~> 4.0 |
-| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |
+| [security\_group](#module\_security\_group) | terraform-aws-modules/security-group/aws | ~> 5.0 |
+| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 6.0 |
## Resources
@@ -57,7 +56,6 @@ 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 465e7902..d43bf633 100644
--- a/examples/complete/main.tf
+++ b/examples/complete/main.tf
@@ -52,38 +52,34 @@ module "ec2_complete" {
# enclave_options_enabled = true
user_data_base64 = base64encode(local.user_data)
- user_data_replace_on_change = true
+ user_data_replace_on_change = false
cpu_options = {
core_count = 2
threads_per_core = 1
}
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
+ root_block_device = {
+ encrypted = true
+ type = "gp3"
+ throughput = 200
+ size = 50
+ tags = {
+ Name = "my-root-block"
+ }
+ }
+
+ ebs_volumes = {
+ "/dev/sdf" = {
+ size = 5
+ throughput = 200
+ encrypted = true
+ kms_key_id = aws_kms_key.this.arn
tags = {
MountPoint = "/mnt/data"
}
}
- ]
+ }
tags = local.tags
}
@@ -93,13 +89,12 @@ module "ec2_network_interface" {
name = "${local.name}-network-interface"
- network_interface = [
- {
- device_index = 0
+ network_interface = {
+ 0 = {
network_interface_id = aws_network_interface.this.id
delete_on_termination = false
}
- ]
+ }
tags = local.tags
}
@@ -109,8 +104,7 @@ module "ec2_metadata_options" {
name = "${local.name}-metadata-options"
- subnet_id = element(module.vpc.private_subnets, 0)
- vpc_security_group_ids = [module.security_group.security_group_id]
+ subnet_id = element(module.vpc.private_subnets, 0)
metadata_options = {
http_endpoint = "enabled"
@@ -130,7 +124,6 @@ module "ec2_t2_unlimited" {
instance_type = "t2.micro"
cpu_credits = "unlimited"
subnet_id = element(module.vpc.private_subnets, 0)
- vpc_security_group_ids = [module.security_group.security_group_id]
associate_public_ip_address = true
maintenance_options = {
@@ -148,7 +141,6 @@ module "ec2_t3_unlimited" {
instance_type = "t3.micro"
cpu_credits = "unlimited"
subnet_id = element(module.vpc.private_subnets, 0)
- vpc_security_group_ids = [module.security_group.security_group_id]
associate_public_ip_address = true
tags = local.tags
@@ -167,15 +159,14 @@ module "ec2_disabled" {
module "ec2_ignore_ami_changes" {
source = "../../"
- name = local.name
+ name = "${local.name}-ignore-ami-changes"
ignore_ami_changes = true
- ami = data.aws_ami.amazon_linux.id
- instance_type = "t2.micro"
- 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]
+ ami = data.aws_ami.amazon_linux.id
+ instance_type = "t2.micro"
+ availability_zone = element(module.vpc.azs, 0)
+ subnet_id = element(module.vpc.private_subnets, 0)
tags = local.tags
}
@@ -190,29 +181,25 @@ locals {
instance_type = "t3.micro"
availability_zone = element(module.vpc.azs, 0)
subnet_id = element(module.vpc.private_subnets, 0)
- root_block_device = [
- {
- encrypted = true
- volume_type = "gp3"
- throughput = 200
- volume_size = 50
- tags = {
- Name = "my-root-block"
- }
+ root_block_device = {
+ encrypted = true
+ type = "gp3"
+ throughput = 200
+ size = 50
+ tags = {
+ Name = "my-root-block"
}
- ]
+ }
}
two = {
instance_type = "t3.small"
availability_zone = element(module.vpc.azs, 1)
subnet_id = element(module.vpc.private_subnets, 1)
- root_block_device = [
- {
- encrypted = true
- volume_type = "gp2"
- volume_size = 50
- }
- ]
+ root_block_device = {
+ encrypted = true
+ type = "gp2"
+ size = 50
+ }
}
three = {
instance_type = "t3.medium"
@@ -229,13 +216,12 @@ module "ec2_multiple" {
name = "${local.name}-multi-${each.key}"
- instance_type = each.value.instance_type
- availability_zone = each.value.availability_zone
- subnet_id = each.value.subnet_id
- vpc_security_group_ids = [module.security_group.security_group_id]
+ instance_type = each.value.instance_type
+ availability_zone = each.value.availability_zone
+ subnet_id = each.value.subnet_id
enable_volume_tags = false
- root_block_device = lookup(each.value, "root_block_device", [])
+ root_block_device = try(each.value.root_block_device, null)
tags = local.tags
}
@@ -256,10 +242,9 @@ module "ec2_spot_instance" {
associate_public_ip_address = true
# Spot request specific attributes
- spot_price = "0.1"
- spot_wait_for_fulfillment = true
- spot_type = "persistent"
- spot_instance_interruption_behavior = "terminate"
+ spot_price = "0.1"
+ spot_wait_for_fulfillment = true
+ spot_type = "persistent"
# End spot request specific attributes
user_data_base64 = base64encode(local.user_data)
@@ -270,28 +255,24 @@ module "ec2_spot_instance" {
}
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
+ root_block_device = {
+ encrypted = true
+ type = "gp3"
+ throughput = 200
+ size = 50
+ tags = {
+ Name = "my-root-block"
+ }
+ }
+
+ ebs_volumes = {
+ "/dev/sdf" = {
+ size = 5
+ throughput = 200
+ encrypted = true
# kms_key_id = aws_kms_key.this.arn # you must grant the AWSServiceRoleForEC2Spot service-linked role access to any custom KMS keys
}
- ]
+ }
tags = local.tags
}
@@ -305,10 +286,8 @@ module "ec2_open_capacity_reservation" {
name = "${local.name}-open-capacity-reservation"
- ami = data.aws_ami.amazon_linux.id
- instance_type = "t3.micro"
+ instance_type = "m4.large"
subnet_id = element(module.vpc.private_subnets, 0)
- vpc_security_group_ids = [module.security_group.security_group_id]
associate_public_ip_address = false
capacity_reservation_specification = {
@@ -325,10 +304,8 @@ module "ec2_targeted_capacity_reservation" {
name = "${local.name}-targeted-capacity-reservation"
- ami = data.aws_ami.amazon_linux.id
- instance_type = "t3.micro"
+ instance_type = "m4.large"
subnet_id = element(module.vpc.private_subnets, 0)
- vpc_security_group_ids = [module.security_group.security_group_id]
associate_public_ip_address = false
capacity_reservation_specification = {
@@ -341,7 +318,7 @@ module "ec2_targeted_capacity_reservation" {
}
resource "aws_ec2_capacity_reservation" "open" {
- instance_type = "t3.micro"
+ instance_type = "m4.large"
instance_platform = "Linux/UNIX"
availability_zone = "${local.region}a"
instance_count = 1
@@ -349,84 +326,20 @@ resource "aws_ec2_capacity_reservation" "open" {
}
resource "aws_ec2_capacity_reservation" "targeted" {
- instance_type = "t3.micro"
+ instance_type = "m4.large"
instance_platform = "Linux/UNIX"
availability_zone = "${local.region}a"
instance_count = 1
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"
- }
- }
- ]
-
- instance_tags = { Persistence = "09:00-18:00" }
-
- tags = local.tags
-}
-
################################################################################
# Supporting Resources
################################################################################
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
- version = "~> 5.0"
+ version = "~> 6.0"
name = local.name
cidr = local.vpc_cidr
@@ -441,26 +354,12 @@ module "vpc" {
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
-
- filter {
- name = "name"
- values = ["amzn-ami-hvm-*-x86_64-gp2"]
- }
-}
-
-data "aws_ami" "amazon_linux_23" {
- most_recent = true
- owners = ["amazon"]
-
- filter {
- name = "name"
- values = ["al2023-ami-2023*-x86_64"]
- }
+ name_regex = "^al2023-ami-2023.*-x86_64"
}
module "security_group" {
source = "terraform-aws-modules/security-group/aws"
- version = "~> 4.0"
+ version = "~> 5.0"
name = local.name
description = "Security group for example usage with EC2 instance"
@@ -468,7 +367,6 @@ module "security_group" {
ingress_cidr_blocks = ["0.0.0.0/0"]
ingress_rules = ["http-80-tcp", "all-icmp"]
- egress_rules = ["all-all"]
tags = local.tags
}
@@ -482,5 +380,6 @@ resource "aws_kms_key" "this" {
}
resource "aws_network_interface" "this" {
- subnet_id = element(module.vpc.private_subnets, 0)
+ subnet_id = element(module.vpc.private_subnets, 0)
+ security_groups = [module.security_group.security_group_id]
}
diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf
index fd4d1167..f648e20c 100644
--- a/examples/complete/versions.tf
+++ b/examples/complete/versions.tf
@@ -1,10 +1,10 @@
terraform {
- required_version = ">= 1.0"
+ required_version = ">= 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
- version = ">= 4.66"
+ version = ">= 6.0"
}
}
}
diff --git a/examples/session-manager/README.md b/examples/session-manager/README.md
index 07552482..b778d379 100644
--- a/examples/session-manager/README.md
+++ b/examples/session-manager/README.md
@@ -29,23 +29,22 @@ Note that this example may create resources which can cost money. Run `terraform
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 1.0 |
-| [aws](#requirement\_aws) | >= 4.66 |
+| [terraform](#requirement\_terraform) | >= 1.10 |
+| [aws](#requirement\_aws) | >= 6.0 |
## Providers
| Name | Version |
|------|---------|
-| [aws](#provider\_aws) | >= 4.66 |
+| [aws](#provider\_aws) | >= 6.0 |
## Modules
| Name | Source | Version |
|------|--------|---------|
| [ec2](#module\_ec2) | ../../ | n/a |
-| [security\_group\_instance](#module\_security\_group\_instance) | terraform-aws-modules/security-group/aws | ~> 5.0 |
-| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |
-| [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 5.0 |
+| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 6.0 |
+| [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 6.0 |
## Resources
diff --git a/examples/session-manager/main.tf b/examples/session-manager/main.tf
index b7896da3..e58cb4e2 100644
--- a/examples/session-manager/main.tf
+++ b/examples/session-manager/main.tf
@@ -27,8 +27,14 @@ module "ec2" {
name = local.name
- subnet_id = element(module.vpc.intra_subnets, 0)
- vpc_security_group_ids = [module.security_group_instance.security_group_id]
+ subnet_id = element(module.vpc.intra_subnets, 0)
+ security_group_egress_rules = {
+ vpc-endpoints = {
+ description = "Allow outbound traffic to VPC endpoints"
+ cidr_ipv4 = module.vpc.vpc_cidr_block
+ from_port = 443
+ }
+ }
create_iam_instance_profile = true
iam_role_description = "IAM role for EC2 instance"
@@ -45,7 +51,7 @@ module "ec2" {
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
- version = "~> 5.0"
+ version = "~> 6.0"
name = local.name
cidr = local.vpc_cidr
@@ -56,23 +62,9 @@ module "vpc" {
tags = local.tags
}
-module "security_group_instance" {
- source = "terraform-aws-modules/security-group/aws"
- version = "~> 5.0"
-
- name = "${local.name}-ec2"
- description = "Security Group for EC2 Instance Egress"
-
- vpc_id = module.vpc.vpc_id
-
- egress_rules = ["https-443-tcp"]
-
- tags = local.tags
-}
-
module "vpc_endpoints" {
source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
- version = "~> 5.0"
+ version = "~> 6.0"
vpc_id = module.vpc.vpc_id
diff --git a/examples/session-manager/versions.tf b/examples/session-manager/versions.tf
index fd4d1167..f648e20c 100644
--- a/examples/session-manager/versions.tf
+++ b/examples/session-manager/versions.tf
@@ -1,10 +1,10 @@
terraform {
- required_version = ">= 1.0"
+ required_version = ">= 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
- version = ">= 4.66"
+ version = ">= 6.0"
}
}
}
diff --git a/examples/volume-attachment/README.md b/examples/volume-attachment/README.md
deleted file mode 100644
index 181dd3f9..00000000
--- a/examples/volume-attachment/README.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# EC2 instance with EBS volume attachment
-
-Configuration in this directory creates EC2 instances, EBS volume and attach it together.
-
-This example outputs instance id and EBS volume id.
-
-## Usage
-
-To run this example you need to execute:
-
-```bash
-$ terraform init
-$ terraform plan
-$ terraform apply
-```
-
-Note that this example may create resources which can cost money. Run `terraform destroy` when you don't need these resources.
-
-
-## Requirements
-
-| Name | Version |
-|------|---------|
-| [terraform](#requirement\_terraform) | >= 1.0 |
-| [aws](#requirement\_aws) | >= 4.66 |
-
-## Providers
-
-| Name | Version |
-|------|---------|
-| [aws](#provider\_aws) | >= 4.66 |
-
-## Modules
-
-| Name | Source | Version |
-|------|--------|---------|
-| [ec2](#module\_ec2) | ../../ | n/a |
-| [security\_group](#module\_security\_group) | terraform-aws-modules/security-group/aws | ~> 4.0 |
-| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 4.0 |
-
-## Resources
-
-| Name | Type |
-|------|------|
-| [aws_ebs_volume.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume) | resource |
-| [aws_volume_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/volume_attachment) | resource |
-| [aws_ami.amazon_linux](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
-
-No inputs.
-
-## Outputs
-
-| Name | Description |
-|------|-------------|
-| [ec2\_arn](#output\_ec2\_arn) | The ARN of the instance |
-| [ec2\_availability\_zone](#output\_ec2\_availability\_zone) | The availability zone of the created spot instance |
-| [ec2\_capacity\_reservation\_specification](#output\_ec2\_capacity\_reservation\_specification) | Capacity reservation specification of the instance |
-| [ec2\_id](#output\_ec2\_id) | The ID of the instance |
-| [ec2\_instance\_state](#output\_ec2\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` |
-| [ec2\_primary\_network\_interface\_id](#output\_ec2\_primary\_network\_interface\_id) | The ID of the instance's primary network interface |
-| [ec2\_private\_dns](#output\_ec2\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC |
-| [ec2\_public\_dns](#output\_ec2\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC |
-| [ec2\_public\_ip](#output\_ec2\_public\_ip) | The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws\_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached |
-| [ec2\_tags\_all](#output\_ec2\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block |
-
diff --git a/examples/volume-attachment/main.tf b/examples/volume-attachment/main.tf
deleted file mode 100644
index 877f2140..00000000
--- a/examples/volume-attachment/main.tf
+++ /dev/null
@@ -1,94 +0,0 @@
-provider "aws" {
- region = local.region
-}
-
-data "aws_availability_zones" "available" {}
-
-locals {
- name = "ex-${basename(path.cwd)}"
- region = "eu-west-1"
-
- vpc_cidr = "10.0.0.0/16"
- azs = slice(data.aws_availability_zones.available.names, 0, 3)
-
- tags = {
- Name = local.name
- Example = local.name
- Repository = "https://github.com/terraform-aws-modules/terraform-aws-ec2-instance"
- }
-}
-
-################################################################################
-# EC2 Module
-################################################################################
-
-module "ec2" {
- source = "../../"
-
- name = local.name
-
- ami = data.aws_ami.amazon_linux.id
- instance_type = "c5.large"
- availability_zone = element(local.azs, 0)
- subnet_id = element(module.vpc.private_subnets, 0)
- vpc_security_group_ids = [module.security_group.security_group_id]
- associate_public_ip_address = true
-
- tags = local.tags
-}
-
-resource "aws_volume_attachment" "this" {
- device_name = "/dev/sdh"
- volume_id = aws_ebs_volume.this.id
- instance_id = module.ec2.id
-}
-
-resource "aws_ebs_volume" "this" {
- availability_zone = module.ec2.availability_zone
- size = 1
-
- tags = local.tags
-}
-
-################################################################################
-# Supporting Resources
-################################################################################
-
-module "vpc" {
- source = "terraform-aws-modules/vpc/aws"
- version = "~> 4.0"
-
- name = local.name
- cidr = local.vpc_cidr
-
- azs = local.azs
- private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
- public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]
-
- tags = local.tags
-}
-
-data "aws_ami" "amazon_linux" {
- most_recent = true
- owners = ["amazon"]
-
- filter {
- name = "name"
- values = ["amzn-ami-hvm-*-x86_64-gp2"]
- }
-}
-
-module "security_group" {
- source = "terraform-aws-modules/security-group/aws"
- version = "~> 4.0"
-
- name = local.name
- description = "Security group for example usage with EC2 instance"
- vpc_id = module.vpc.vpc_id
-
- ingress_cidr_blocks = ["0.0.0.0/0"]
- ingress_rules = ["http-80-tcp", "all-icmp"]
- egress_rules = ["all-all"]
-
- tags = local.tags
-}
diff --git a/examples/volume-attachment/outputs.tf b/examples/volume-attachment/outputs.tf
deleted file mode 100644
index a927767b..00000000
--- a/examples/volume-attachment/outputs.tf
+++ /dev/null
@@ -1,50 +0,0 @@
-# EC2
-output "ec2_id" {
- description = "The ID of the instance"
- value = module.ec2.id
-}
-
-output "ec2_arn" {
- description = "The ARN of the instance"
- value = module.ec2.arn
-}
-
-output "ec2_capacity_reservation_specification" {
- description = "Capacity reservation specification of the instance"
- value = module.ec2.capacity_reservation_specification
-}
-
-output "ec2_instance_state" {
- description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`"
- value = module.ec2.instance_state
-}
-
-output "ec2_primary_network_interface_id" {
- description = "The ID of the instance's primary network interface"
- value = module.ec2.primary_network_interface_id
-}
-
-output "ec2_private_dns" {
- description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC"
- value = module.ec2.private_dns
-}
-
-output "ec2_public_dns" {
- description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC"
- value = module.ec2.public_dns
-}
-
-output "ec2_public_ip" {
- description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached"
- value = module.ec2.public_ip
-}
-
-output "ec2_tags_all" {
- description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block"
- value = module.ec2.tags_all
-}
-
-output "ec2_availability_zone" {
- description = "The availability zone of the created spot instance"
- value = module.ec2.availability_zone
-}
diff --git a/examples/volume-attachment/variables.tf b/examples/volume-attachment/variables.tf
deleted file mode 100644
index e69de29b..00000000
diff --git a/examples/volume-attachment/versions.tf b/examples/volume-attachment/versions.tf
deleted file mode 100644
index fd4d1167..00000000
--- a/examples/volume-attachment/versions.tf
+++ /dev/null
@@ -1,10 +0,0 @@
-terraform {
- required_version = ">= 1.0"
-
- required_providers {
- aws = {
- source = "hashicorp/aws"
- version = ">= 4.66"
- }
- }
-}
diff --git a/main.tf b/main.tf
index 01a520d5..b116b406 100644
--- a/main.tf
+++ b/main.tf
@@ -6,11 +6,33 @@ locals {
is_t_instance_type = replace(var.instance_type, "/^t(2|3|3a|4g){1}\\..*$/", "1") == "1" ? true : false
ami = try(coalesce(var.ami, try(nonsensitive(data.aws_ssm_parameter.this[0].value), null)), null)
+
+ instance_tags = merge(
+ var.tags,
+ var.instance_tags,
+ { "Name" = var.name },
+ )
+
+ instance_id = try(
+ aws_instance.this[0].id,
+ aws_instance.ignore_ami[0].id,
+ aws_spot_instance_request.this[0].spot_instance_id,
+ null,
+ )
+
+ instance_availability_zone = try(
+ aws_instance.this[0].availability_zone,
+ aws_instance.ignore_ami[0].availability_zone,
+ aws_spot_instance_request.this[0].availability_zone,
+ null,
+ )
}
data "aws_ssm_parameter" "this" {
count = local.create && var.ami == null ? 1 : 0
+ region = var.region
+
name = var.ami_ssm_parameter
}
@@ -21,175 +43,187 @@ data "aws_ssm_parameter" "this" {
resource "aws_instance" "this" {
count = local.create && !var.ignore_ami_changes && !var.create_spot_instance ? 1 : 0
- ami = local.ami
- instance_type = var.instance_type
- cpu_core_count = var.cpu_core_count
- cpu_threads_per_core = var.cpu_threads_per_core
- hibernation = var.hibernation
-
- user_data = var.user_data
- user_data_base64 = var.user_data_base64
- user_data_replace_on_change = var.user_data_replace_on_change
-
- availability_zone = var.availability_zone
- subnet_id = var.subnet_id
- vpc_security_group_ids = var.vpc_security_group_ids
-
- key_name = var.key_name
- monitoring = var.monitoring
- get_password_data = var.get_password_data
- iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile
+ region = var.region
+ ami = local.ami
associate_public_ip_address = var.associate_public_ip_address
- private_ip = var.private_ip
- secondary_private_ips = var.secondary_private_ips
- ipv6_address_count = var.ipv6_address_count
- ipv6_addresses = var.ipv6_addresses
-
- 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)
- }
- }
+ availability_zone = var.availability_zone
dynamic "capacity_reservation_specification" {
- for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : []
+ for_each = var.capacity_reservation_specification != null ? [var.capacity_reservation_specification] : []
content {
- capacity_reservation_preference = try(capacity_reservation_specification.value.capacity_reservation_preference, null)
+ capacity_reservation_preference = capacity_reservation_specification.value.capacity_reservation_preference
dynamic "capacity_reservation_target" {
- for_each = try([capacity_reservation_specification.value.capacity_reservation_target], [])
+ for_each = capacity_reservation_specification.value.capacity_reservation_target != null ? [capacity_reservation_specification.value.capacity_reservation_target] : []
content {
- capacity_reservation_id = try(capacity_reservation_target.value.capacity_reservation_id, null)
- capacity_reservation_resource_group_arn = try(capacity_reservation_target.value.capacity_reservation_resource_group_arn, null)
+ capacity_reservation_id = capacity_reservation_target.value.capacity_reservation_id
+ capacity_reservation_resource_group_arn = capacity_reservation_target.value.capacity_reservation_resource_group_arn
}
}
}
}
- dynamic "root_block_device" {
- for_each = var.root_block_device
+ dynamic "cpu_options" {
+ for_each = var.cpu_options != null ? [var.cpu_options] : []
content {
- delete_on_termination = try(root_block_device.value.delete_on_termination, null)
- encrypted = try(root_block_device.value.encrypted, null)
- iops = try(root_block_device.value.iops, null)
- kms_key_id = lookup(root_block_device.value, "kms_key_id", null)
- volume_size = try(root_block_device.value.volume_size, null)
- volume_type = try(root_block_device.value.volume_type, null)
- throughput = try(root_block_device.value.throughput, null)
- tags = try(root_block_device.value.tags, null)
+ amd_sev_snp = cpu_options.value.amd_sev_snp
+ core_count = cpu_options.value.core_count
+ threads_per_core = cpu_options.value.threads_per_core
}
}
- dynamic "ebs_block_device" {
- for_each = var.ebs_block_device
+ credit_specification {
+ cpu_credits = local.is_t_instance_type ? var.cpu_credits : null
+ }
- content {
- delete_on_termination = try(ebs_block_device.value.delete_on_termination, null)
- device_name = ebs_block_device.value.device_name
- encrypted = try(ebs_block_device.value.encrypted, null)
- iops = try(ebs_block_device.value.iops, null)
- kms_key_id = lookup(ebs_block_device.value, "kms_key_id", null)
- snapshot_id = lookup(ebs_block_device.value, "snapshot_id", null)
- volume_size = try(ebs_block_device.value.volume_size, null)
- volume_type = try(ebs_block_device.value.volume_type, null)
- throughput = try(ebs_block_device.value.throughput, null)
- tags = try(ebs_block_device.value.tags, null)
- }
+ disable_api_stop = var.disable_api_stop
+ disable_api_termination = var.disable_api_termination
+
+ # `ebs_block_device` managed by separate resource
+
+ ebs_optimized = var.ebs_optimized
+
+ enclave_options {
+ enabled = var.enclave_options_enabled
}
+ enable_primary_ipv6 = var.enable_primary_ipv6
+
dynamic "ephemeral_block_device" {
- for_each = var.ephemeral_block_device
+ for_each = var.ephemeral_block_device != null ? var.ephemeral_block_device : {}
content {
device_name = ephemeral_block_device.value.device_name
- no_device = try(ephemeral_block_device.value.no_device, null)
- virtual_name = try(ephemeral_block_device.value.virtual_name, null)
+ no_device = ephemeral_block_device.value.no_device
+ virtual_name = ephemeral_block_device.value.virtual_name
}
}
- dynamic "metadata_options" {
- for_each = length(var.metadata_options) > 0 ? [var.metadata_options] : []
+ get_password_data = var.get_password_data
+ hibernation = var.hibernation
+ host_id = var.host_id
+ host_resource_group_arn = var.host_resource_group_arn
+ iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile
+ instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior
+
+ dynamic "instance_market_options" {
+ for_each = var.instance_market_options != null ? [var.instance_market_options] : []
content {
- http_endpoint = try(metadata_options.value.http_endpoint, "enabled")
- http_tokens = try(metadata_options.value.http_tokens, "required")
- http_put_response_hop_limit = try(metadata_options.value.http_put_response_hop_limit, 1)
- instance_metadata_tags = try(metadata_options.value.instance_metadata_tags, null)
+ market_type = instance_market_options.value.market_type
+
+ dynamic "spot_options" {
+ for_each = instance_market_options.value.spot_options != null ? [instance_market_options.value.spot_options] : []
+
+ content {
+ instance_interruption_behavior = spot_options.value.instance_interruption_behavior
+ max_price = spot_options.value.max_price
+ spot_instance_type = spot_options.value.spot_instance_type
+ valid_until = spot_options.value.valid_until
+ }
+ }
}
}
- dynamic "network_interface" {
- for_each = var.network_interface
+ instance_type = var.instance_type
+ ipv6_address_count = var.ipv6_address_count
+ ipv6_addresses = var.ipv6_addresses
+ key_name = var.key_name
+
+ dynamic "launch_template" {
+ for_each = var.launch_template != null ? [var.launch_template] : []
content {
- device_index = network_interface.value.device_index
- network_interface_id = lookup(network_interface.value, "network_interface_id", null)
- delete_on_termination = try(network_interface.value.delete_on_termination, false)
+ id = launch_template.value.id
+ name = launch_template.value.name
+ version = launch_template.value.version
}
}
- dynamic "private_dns_name_options" {
- for_each = length(var.private_dns_name_options) > 0 ? [var.private_dns_name_options] : []
+ dynamic "maintenance_options" {
+ for_each = var.maintenance_options != null ? [var.maintenance_options] : []
content {
- hostname_type = try(private_dns_name_options.value.hostname_type, null)
- enable_resource_name_dns_a_record = try(private_dns_name_options.value.enable_resource_name_dns_a_record, null)
- enable_resource_name_dns_aaaa_record = try(private_dns_name_options.value.enable_resource_name_dns_aaaa_record, null)
+ auto_recovery = maintenance_options.value.auto_recovery
}
}
- dynamic "launch_template" {
- for_each = length(var.launch_template) > 0 ? [var.launch_template] : []
+ dynamic "metadata_options" {
+ for_each = var.metadata_options != null ? [var.metadata_options] : []
content {
- id = lookup(var.launch_template, "id", null)
- name = lookup(var.launch_template, "name", null)
- version = lookup(var.launch_template, "version", null)
+ http_endpoint = metadata_options.value.http_endpoint
+ http_protocol_ipv6 = metadata_options.value.http_protocol_ipv6
+ http_put_response_hop_limit = metadata_options.value.http_put_response_hop_limit
+ http_tokens = metadata_options.value.http_tokens
+ instance_metadata_tags = metadata_options.value.instance_metadata_tags
}
}
- dynamic "maintenance_options" {
- for_each = length(var.maintenance_options) > 0 ? [var.maintenance_options] : []
+ monitoring = var.monitoring
+
+ dynamic "network_interface" {
+ for_each = var.network_interface != null ? var.network_interface : {}
content {
- auto_recovery = try(maintenance_options.value.auto_recovery, null)
+ delete_on_termination = network_interface.value.delete_on_termination
+ device_index = coalesce(network_interface.value.device_index, network_interface.key)
+ network_card_index = network_interface.value.network_card_index
+ network_interface_id = network_interface.value.network_interface_id
+
}
}
- enclave_options {
- enabled = var.enclave_options_enabled
+ placement_group = var.placement_group
+ placement_partition_number = var.placement_partition_number
+
+ dynamic "private_dns_name_options" {
+ for_each = var.private_dns_name_options != null ? [var.private_dns_name_options] : []
+
+ content {
+ enable_resource_name_dns_aaaa_record = private_dns_name_options.value.enable_resource_name_dns_aaaa_record
+ enable_resource_name_dns_a_record = private_dns_name_options.value.enable_resource_name_dns_a_record
+ hostname_type = private_dns_name_options.value.hostname_type
+ }
}
- source_dest_check = length(var.network_interface) > 0 ? null : var.source_dest_check
- disable_api_termination = var.disable_api_termination
- disable_api_stop = var.disable_api_stop
- instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior
- placement_group = var.placement_group
- tenancy = var.tenancy
- host_id = var.host_id
+ private_ip = var.private_ip
- credit_specification {
- cpu_credits = local.is_t_instance_type ? var.cpu_credits : null
+ dynamic "root_block_device" {
+ for_each = var.root_block_device != null ? [var.root_block_device] : []
+
+ content {
+ delete_on_termination = root_block_device.value.delete_on_termination
+ encrypted = root_block_device.value.encrypted
+ iops = root_block_device.value.iops
+ kms_key_id = root_block_device.value.kms_key_id
+ tags = root_block_device.value.tags
+ throughput = root_block_device.value.throughput
+ volume_size = root_block_device.value.size
+ volume_type = root_block_device.value.type
+ }
}
+ secondary_private_ips = var.secondary_private_ips
+ source_dest_check = var.network_interface != null ? null : var.source_dest_check
+ subnet_id = var.subnet_id
+ tags = local.instance_tags
+ tenancy = var.tenancy
+ user_data = var.user_data
+ user_data_base64 = var.user_data_base64
+ user_data_replace_on_change = var.user_data_replace_on_change
+ volume_tags = var.enable_volume_tags ? merge(var.tags, var.volume_tags, { "Name" = var.name }) : null
+ vpc_security_group_ids = var.network_interface == null ? local.vpc_security_group_ids : null
+
timeouts {
create = try(var.timeouts.create, null)
update = try(var.timeouts.update, null)
delete = try(var.timeouts.delete, null)
}
-
- tags = merge({ "Name" = var.name }, var.instance_tags, var.tags)
- volume_tags = var.enable_volume_tags ? merge({ "Name" = var.name }, var.volume_tags) : null
}
################################################################################
@@ -199,176 +233,188 @@ resource "aws_instance" "this" {
resource "aws_instance" "ignore_ami" {
count = local.create && var.ignore_ami_changes && !var.create_spot_instance ? 1 : 0
- ami = local.ami
- instance_type = var.instance_type
- cpu_core_count = var.cpu_core_count
- cpu_threads_per_core = var.cpu_threads_per_core
- hibernation = var.hibernation
-
- user_data = var.user_data
- user_data_base64 = var.user_data_base64
- user_data_replace_on_change = var.user_data_replace_on_change
-
- availability_zone = var.availability_zone
- subnet_id = var.subnet_id
- vpc_security_group_ids = var.vpc_security_group_ids
-
- key_name = var.key_name
- monitoring = var.monitoring
- get_password_data = var.get_password_data
- iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile
+ region = var.region
+ ami = local.ami
associate_public_ip_address = var.associate_public_ip_address
- private_ip = var.private_ip
- secondary_private_ips = var.secondary_private_ips
- ipv6_address_count = var.ipv6_address_count
- ipv6_addresses = var.ipv6_addresses
-
- 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)
- }
- }
+ availability_zone = var.availability_zone
dynamic "capacity_reservation_specification" {
- for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : []
+ for_each = var.capacity_reservation_specification != null ? [var.capacity_reservation_specification] : []
content {
- capacity_reservation_preference = try(capacity_reservation_specification.value.capacity_reservation_preference, null)
+ capacity_reservation_preference = capacity_reservation_specification.value.capacity_reservation_preference
dynamic "capacity_reservation_target" {
- for_each = try([capacity_reservation_specification.value.capacity_reservation_target], [])
+ for_each = capacity_reservation_specification.value.capacity_reservation_target != null ? [capacity_reservation_specification.value.capacity_reservation_target] : []
content {
- capacity_reservation_id = try(capacity_reservation_target.value.capacity_reservation_id, null)
- capacity_reservation_resource_group_arn = try(capacity_reservation_target.value.capacity_reservation_resource_group_arn, null)
+ capacity_reservation_id = capacity_reservation_target.value.capacity_reservation_id
+ capacity_reservation_resource_group_arn = capacity_reservation_target.value.capacity_reservation_resource_group_arn
}
}
}
}
- dynamic "root_block_device" {
- for_each = var.root_block_device
+ dynamic "cpu_options" {
+ for_each = var.cpu_options != null ? [var.cpu_options] : []
content {
- delete_on_termination = try(root_block_device.value.delete_on_termination, null)
- encrypted = try(root_block_device.value.encrypted, null)
- iops = try(root_block_device.value.iops, null)
- kms_key_id = lookup(root_block_device.value, "kms_key_id", null)
- volume_size = try(root_block_device.value.volume_size, null)
- volume_type = try(root_block_device.value.volume_type, null)
- throughput = try(root_block_device.value.throughput, null)
- tags = try(root_block_device.value.tags, null)
+ amd_sev_snp = cpu_options.value.amd_sev_snp
+ core_count = cpu_options.value.core_count
+ threads_per_core = cpu_options.value.threads_per_core
}
}
- dynamic "ebs_block_device" {
- for_each = var.ebs_block_device
+ credit_specification {
+ cpu_credits = local.is_t_instance_type ? var.cpu_credits : null
+ }
- content {
- delete_on_termination = try(ebs_block_device.value.delete_on_termination, null)
- device_name = ebs_block_device.value.device_name
- encrypted = try(ebs_block_device.value.encrypted, null)
- iops = try(ebs_block_device.value.iops, null)
- kms_key_id = lookup(ebs_block_device.value, "kms_key_id", null)
- snapshot_id = lookup(ebs_block_device.value, "snapshot_id", null)
- volume_size = try(ebs_block_device.value.volume_size, null)
- volume_type = try(ebs_block_device.value.volume_type, null)
- throughput = try(ebs_block_device.value.throughput, null)
- tags = try(ebs_block_device.value.tags, null)
- }
+ disable_api_stop = var.disable_api_stop
+ disable_api_termination = var.disable_api_termination
+
+ # `ebs_block_device` managed by separate resource
+
+ ebs_optimized = var.ebs_optimized
+
+ enclave_options {
+ enabled = var.enclave_options_enabled
}
+ enable_primary_ipv6 = var.enable_primary_ipv6
+
dynamic "ephemeral_block_device" {
- for_each = var.ephemeral_block_device
+ for_each = var.ephemeral_block_device != null ? var.ephemeral_block_device : {}
content {
device_name = ephemeral_block_device.value.device_name
- no_device = try(ephemeral_block_device.value.no_device, null)
- virtual_name = try(ephemeral_block_device.value.virtual_name, null)
+ no_device = ephemeral_block_device.value.no_device
+ virtual_name = ephemeral_block_device.value.virtual_name
}
}
- dynamic "metadata_options" {
- for_each = length(var.metadata_options) > 0 ? [var.metadata_options] : []
+ get_password_data = var.get_password_data
+ hibernation = var.hibernation
+ host_id = var.host_id
+ host_resource_group_arn = var.host_resource_group_arn
+ iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile
+ instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior
+
+ dynamic "instance_market_options" {
+ for_each = var.instance_market_options != null ? [var.instance_market_options] : []
content {
- http_endpoint = try(metadata_options.value.http_endpoint, "enabled")
- http_tokens = try(metadata_options.value.http_tokens, "required")
- http_put_response_hop_limit = try(metadata_options.value.http_put_response_hop_limit, 1)
- instance_metadata_tags = try(metadata_options.value.instance_metadata_tags, null)
+ market_type = instance_market_options.value.market_type
+
+ dynamic "spot_options" {
+ for_each = instance_market_options.value.spot_options != null ? [instance_market_options.value.spot_options] : []
+
+ content {
+ instance_interruption_behavior = spot_options.value.instance_interruption_behavior
+ max_price = spot_options.value.max_price
+ spot_instance_type = spot_options.value.spot_instance_type
+ valid_until = spot_options.value.valid_until
+ }
+ }
}
}
- dynamic "network_interface" {
- for_each = var.network_interface
+ instance_type = var.instance_type
+ ipv6_address_count = var.ipv6_address_count
+ ipv6_addresses = var.ipv6_addresses
+ key_name = var.key_name
+
+ dynamic "launch_template" {
+ for_each = var.launch_template != null ? [var.launch_template] : []
content {
- device_index = network_interface.value.device_index
- network_interface_id = lookup(network_interface.value, "network_interface_id", null)
- delete_on_termination = try(network_interface.value.delete_on_termination, false)
+ id = launch_template.value.id
+ name = launch_template.value.name
+ version = launch_template.value.version
}
}
- dynamic "private_dns_name_options" {
- for_each = length(var.private_dns_name_options) > 0 ? [var.private_dns_name_options] : []
+ dynamic "maintenance_options" {
+ for_each = var.maintenance_options != null ? [var.maintenance_options] : []
content {
- hostname_type = try(private_dns_name_options.value.hostname_type, null)
- enable_resource_name_dns_a_record = try(private_dns_name_options.value.enable_resource_name_dns_a_record, null)
- enable_resource_name_dns_aaaa_record = try(private_dns_name_options.value.enable_resource_name_dns_aaaa_record, null)
+ auto_recovery = maintenance_options.value.auto_recovery
}
}
- dynamic "launch_template" {
- for_each = length(var.launch_template) > 0 ? [var.launch_template] : []
+ dynamic "metadata_options" {
+ for_each = var.metadata_options != null ? [var.metadata_options] : []
content {
- id = lookup(var.launch_template, "id", null)
- name = lookup(var.launch_template, "name", null)
- version = lookup(var.launch_template, "version", null)
+ http_endpoint = metadata_options.value.http_endpoint
+ http_protocol_ipv6 = metadata_options.value.http_protocol_ipv6
+ http_put_response_hop_limit = metadata_options.value.http_put_response_hop_limit
+ http_tokens = metadata_options.value.http_tokens
+ instance_metadata_tags = metadata_options.value.instance_metadata_tags
}
}
- dynamic "maintenance_options" {
- for_each = length(var.maintenance_options) > 0 ? [var.maintenance_options] : []
+ monitoring = var.monitoring
+
+ dynamic "network_interface" {
+ for_each = var.network_interface != null ? var.network_interface : {}
content {
- auto_recovery = try(maintenance_options.value.auto_recovery, null)
+ delete_on_termination = network_interface.value.delete_on_termination
+ device_index = coalesce(network_interface.value.device_index, network_interface.key)
+ network_card_index = network_interface.value.network_card_index
+ network_interface_id = network_interface.value.network_interface_id
+
}
}
- enclave_options {
- enabled = var.enclave_options_enabled
+ placement_group = var.placement_group
+ placement_partition_number = var.placement_partition_number
+
+ dynamic "private_dns_name_options" {
+ for_each = var.private_dns_name_options != null ? [var.private_dns_name_options] : []
+
+ content {
+ enable_resource_name_dns_aaaa_record = private_dns_name_options.value.enable_resource_name_dns_aaaa_record
+ enable_resource_name_dns_a_record = private_dns_name_options.value.enable_resource_name_dns_a_record
+ hostname_type = private_dns_name_options.value.hostname_type
+ }
}
- source_dest_check = length(var.network_interface) > 0 ? null : var.source_dest_check
- disable_api_termination = var.disable_api_termination
- disable_api_stop = var.disable_api_stop
- instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior
- placement_group = var.placement_group
- tenancy = var.tenancy
- host_id = var.host_id
+ private_ip = var.private_ip
- credit_specification {
- cpu_credits = local.is_t_instance_type ? var.cpu_credits : null
+ dynamic "root_block_device" {
+ for_each = var.root_block_device != null ? [var.root_block_device] : []
+
+ content {
+ delete_on_termination = root_block_device.value.delete_on_termination
+ encrypted = root_block_device.value.encrypted
+ iops = root_block_device.value.iops
+ kms_key_id = root_block_device.value.kms_key_id
+ tags = root_block_device.value.tags
+ throughput = root_block_device.value.throughput
+ volume_size = root_block_device.value.size
+ volume_type = root_block_device.value.type
+ }
}
+ secondary_private_ips = var.secondary_private_ips
+ source_dest_check = var.network_interface != null ? null : var.source_dest_check
+ subnet_id = var.subnet_id
+ tags = local.instance_tags
+ tenancy = var.tenancy
+ user_data = var.user_data
+ user_data_base64 = var.user_data_base64
+ user_data_replace_on_change = var.user_data_replace_on_change
+ volume_tags = var.enable_volume_tags ? merge(var.tags, var.volume_tags, { "Name" = var.name }) : null
+ vpc_security_group_ids = var.network_interface == null ? local.vpc_security_group_ids : null
+
timeouts {
create = try(var.timeouts.create, null)
update = try(var.timeouts.update, null)
delete = try(var.timeouts.delete, null)
}
- tags = merge({ "Name" = var.name }, var.instance_tags, var.tags)
- volume_tags = var.enable_volume_tags ? merge({ "Name" = var.name }, var.volume_tags) : null
-
lifecycle {
ignore_changes = [
ami
@@ -383,165 +429,234 @@ resource "aws_instance" "ignore_ami" {
resource "aws_spot_instance_request" "this" {
count = local.create && var.create_spot_instance ? 1 : 0
- ami = local.ami
- instance_type = var.instance_type
- cpu_core_count = var.cpu_core_count
- cpu_threads_per_core = var.cpu_threads_per_core
- hibernation = var.hibernation
-
- user_data = var.user_data
- user_data_base64 = var.user_data_base64
- user_data_replace_on_change = var.user_data_replace_on_change
-
- availability_zone = var.availability_zone
- subnet_id = var.subnet_id
- vpc_security_group_ids = var.vpc_security_group_ids
-
- key_name = var.key_name
- monitoring = var.monitoring
- get_password_data = var.get_password_data
- iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile
-
- associate_public_ip_address = var.associate_public_ip_address
- private_ip = var.private_ip
- secondary_private_ips = var.secondary_private_ips
- ipv6_address_count = var.ipv6_address_count
- ipv6_addresses = var.ipv6_addresses
-
- ebs_optimized = var.ebs_optimized
+ region = var.region
# Spot request specific attributes
+ instance_interruption_behavior = var.spot_instance_interruption_behavior
+ launch_group = var.spot_launch_group
spot_price = var.spot_price
- wait_for_fulfillment = var.spot_wait_for_fulfillment
spot_type = var.spot_type
- launch_group = var.spot_launch_group
- block_duration_minutes = var.spot_block_duration_minutes
- instance_interruption_behavior = var.spot_instance_interruption_behavior
- valid_until = var.spot_valid_until
+ wait_for_fulfillment = var.spot_wait_for_fulfillment
valid_from = var.spot_valid_from
+ valid_until = var.spot_valid_until
# 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)
- }
- }
+ ami = local.ami
+ associate_public_ip_address = var.associate_public_ip_address
+ availability_zone = var.availability_zone
dynamic "capacity_reservation_specification" {
- for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : []
+ for_each = var.capacity_reservation_specification != null ? [var.capacity_reservation_specification] : []
content {
- capacity_reservation_preference = try(capacity_reservation_specification.value.capacity_reservation_preference, null)
+ capacity_reservation_preference = capacity_reservation_specification.value.capacity_reservation_preference
dynamic "capacity_reservation_target" {
- for_each = try([capacity_reservation_specification.value.capacity_reservation_target], [])
+ for_each = capacity_reservation_specification.value.capacity_reservation_target != null ? [capacity_reservation_specification.value.capacity_reservation_target] : []
+
content {
- capacity_reservation_id = try(capacity_reservation_target.value.capacity_reservation_id, null)
- capacity_reservation_resource_group_arn = try(capacity_reservation_target.value.capacity_reservation_resource_group_arn, null)
+ capacity_reservation_id = capacity_reservation_target.value.capacity_reservation_id
+ capacity_reservation_resource_group_arn = capacity_reservation_target.value.capacity_reservation_resource_group_arn
}
}
}
}
- dynamic "root_block_device" {
- for_each = var.root_block_device
+ dynamic "cpu_options" {
+ for_each = var.cpu_options != null ? [var.cpu_options] : []
content {
- delete_on_termination = try(root_block_device.value.delete_on_termination, null)
- encrypted = try(root_block_device.value.encrypted, null)
- iops = try(root_block_device.value.iops, null)
- kms_key_id = lookup(root_block_device.value, "kms_key_id", null)
- volume_size = try(root_block_device.value.volume_size, null)
- volume_type = try(root_block_device.value.volume_type, null)
- throughput = try(root_block_device.value.throughput, null)
- tags = try(root_block_device.value.tags, null)
+ amd_sev_snp = cpu_options.value.amd_sev_snp
+ core_count = cpu_options.value.core_count
+ threads_per_core = cpu_options.value.threads_per_core
}
}
- dynamic "ebs_block_device" {
- for_each = var.ebs_block_device
+ credit_specification {
+ cpu_credits = local.is_t_instance_type ? var.cpu_credits : null
+ }
- content {
- delete_on_termination = try(ebs_block_device.value.delete_on_termination, null)
- device_name = ebs_block_device.value.device_name
- encrypted = try(ebs_block_device.value.encrypted, null)
- iops = try(ebs_block_device.value.iops, null)
- kms_key_id = lookup(ebs_block_device.value, "kms_key_id", null)
- snapshot_id = lookup(ebs_block_device.value, "snapshot_id", null)
- volume_size = try(ebs_block_device.value.volume_size, null)
- volume_type = try(ebs_block_device.value.volume_type, null)
- throughput = try(ebs_block_device.value.throughput, null)
- tags = try(ebs_block_device.value.tags, null)
- }
+ disable_api_stop = var.disable_api_stop
+ disable_api_termination = var.disable_api_termination
+
+ # `ebs_block_device` managed by separate resource
+
+ ebs_optimized = var.ebs_optimized
+
+ enclave_options {
+ enabled = var.enclave_options_enabled
}
+ enable_primary_ipv6 = var.enable_primary_ipv6
+
dynamic "ephemeral_block_device" {
- for_each = var.ephemeral_block_device
+ for_each = var.ephemeral_block_device != null ? var.ephemeral_block_device : {}
content {
device_name = ephemeral_block_device.value.device_name
- no_device = try(ephemeral_block_device.value.no_device, null)
- virtual_name = try(ephemeral_block_device.value.virtual_name, null)
+ no_device = ephemeral_block_device.value.no_device
+ virtual_name = ephemeral_block_device.value.virtual_name
+ }
+ }
+
+ get_password_data = var.get_password_data
+ hibernation = var.hibernation
+ host_id = var.host_id
+ host_resource_group_arn = var.host_resource_group_arn
+ iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile
+ instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior
+
+ instance_type = var.instance_type
+ ipv6_address_count = var.ipv6_address_count
+ ipv6_addresses = var.ipv6_addresses
+ key_name = var.key_name
+
+ dynamic "launch_template" {
+ for_each = var.launch_template != null ? [var.launch_template] : []
+
+ content {
+ id = launch_template.value.id
+ name = launch_template.value.name
+ version = launch_template.value.version
+ }
+ }
+
+ dynamic "maintenance_options" {
+ for_each = var.maintenance_options != null ? [var.maintenance_options] : []
+
+ content {
+ auto_recovery = maintenance_options.value.auto_recovery
}
}
dynamic "metadata_options" {
- for_each = length(var.metadata_options) > 0 ? [var.metadata_options] : []
+ for_each = var.metadata_options != null ? [var.metadata_options] : []
content {
- http_endpoint = try(metadata_options.value.http_endpoint, "enabled")
- http_tokens = try(metadata_options.value.http_tokens, "required")
- http_put_response_hop_limit = try(metadata_options.value.http_put_response_hop_limit, 1)
- instance_metadata_tags = try(metadata_options.value.instance_metadata_tags, null)
+ http_endpoint = metadata_options.value.http_endpoint
+ http_protocol_ipv6 = metadata_options.value.http_protocol_ipv6
+ http_put_response_hop_limit = metadata_options.value.http_put_response_hop_limit
+ http_tokens = metadata_options.value.http_tokens
+ instance_metadata_tags = metadata_options.value.instance_metadata_tags
}
}
+ monitoring = var.monitoring
+
dynamic "network_interface" {
- for_each = var.network_interface
+ for_each = var.network_interface != null ? var.network_interface : {}
content {
- device_index = network_interface.value.device_index
- network_interface_id = lookup(network_interface.value, "network_interface_id", null)
- delete_on_termination = try(network_interface.value.delete_on_termination, false)
+ delete_on_termination = network_interface.value.delete_on_termination
+ device_index = try(network_interface.value.device_index, network_interface.key)
+ network_card_index = network_interface.value.network_card_index
+ network_interface_id = network_interface.value.network_interface_id
+
}
}
- dynamic "launch_template" {
- for_each = length(var.launch_template) > 0 ? [var.launch_template] : []
+ placement_group = var.placement_group
+ placement_partition_number = var.placement_partition_number
+
+ dynamic "private_dns_name_options" {
+ for_each = var.private_dns_name_options != null ? [var.private_dns_name_options] : []
content {
- id = lookup(var.launch_template, "id", null)
- name = lookup(var.launch_template, "name", null)
- version = lookup(var.launch_template, "version", null)
+ enable_resource_name_dns_aaaa_record = private_dns_name_options.value.enable_resource_name_dns_aaaa_record
+ enable_resource_name_dns_a_record = private_dns_name_options.value.enable_resource_name_dns_a_record
+ hostname_type = private_dns_name_options.value.hostname_type
}
}
- enclave_options {
- enabled = var.enclave_options_enabled
- }
+ private_ip = var.private_ip
- source_dest_check = length(var.network_interface) > 0 ? null : var.source_dest_check
- disable_api_termination = var.disable_api_termination
- instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior
- placement_group = var.placement_group
- tenancy = var.tenancy
- host_id = var.host_id
+ dynamic "root_block_device" {
+ for_each = var.root_block_device != null ? [var.root_block_device] : []
- credit_specification {
- cpu_credits = local.is_t_instance_type ? var.cpu_credits : null
+ content {
+ delete_on_termination = root_block_device.value.delete_on_termination
+ encrypted = root_block_device.value.encrypted
+ iops = root_block_device.value.iops
+ kms_key_id = root_block_device.value.kms_key_id
+ tags = root_block_device.value.tags
+ throughput = root_block_device.value.throughput
+ volume_size = root_block_device.value.size
+ volume_type = root_block_device.value.type
+ }
}
+ secondary_private_ips = var.secondary_private_ips
+ source_dest_check = var.network_interface != null ? null : var.source_dest_check
+ subnet_id = var.subnet_id
+ tags = local.instance_tags
+ tenancy = var.tenancy
+ user_data = var.user_data
+ user_data_base64 = var.user_data_base64
+ user_data_replace_on_change = var.user_data_replace_on_change
+ volume_tags = var.enable_volume_tags ? merge(var.tags, var.volume_tags, { "Name" = var.name }) : null
+ vpc_security_group_ids = var.network_interface == null ? local.vpc_security_group_ids : null
+
timeouts {
create = try(var.timeouts.create, null)
delete = try(var.timeouts.delete, null)
}
- tags = merge({ "Name" = var.name }, var.instance_tags, var.tags)
- volume_tags = var.enable_volume_tags ? merge({ "Name" = var.name }, var.volume_tags) : null
+ lifecycle {
+ ignore_changes = [
+ ebs_block_device,
+ ]
+ }
+}
+
+resource "aws_ec2_tag" "spot_instance" {
+ for_each = { for k, v in local.instance_tags : k => v if local.create && var.create_spot_instance }
+
+ resource_id = aws_spot_instance_request.this[0].spot_instance_id
+ key = each.key
+ value = each.value
+}
+
+################################################################################
+# EBS Volume(s)
+################################################################################
+
+resource "aws_ebs_volume" "this" {
+ for_each = var.create && var.ebs_volumes != null ? var.ebs_volumes : {}
+
+ region = var.region
+
+ availability_zone = local.instance_availability_zone
+ encrypted = each.value.encrypted
+ final_snapshot = each.value.final_snapshot
+ iops = each.value.iops
+ kms_key_id = each.value.kms_key_id
+ multi_attach_enabled = each.value.multi_attach_enabled
+ outpost_arn = each.value.outpost_arn
+ size = each.value.size
+ snapshot_id = each.value.snapshot_id
+
+ tags = merge(
+ var.tags,
+ var.volume_tags,
+ { "Name" = "${var.name}-${each.key}" },
+ each.value.tags,
+ )
+
+ throughput = each.value.throughput
+ type = each.value.type
+}
+
+resource "aws_volume_attachment" "this" {
+ for_each = var.create && var.ebs_volumes != null ? var.ebs_volumes : {}
+
+ region = var.region
+
+ device_name = coalesce(each.value.device_name, each.key)
+ instance_id = local.instance_id
+ volume_id = aws_ebs_volume.this[each.key].id
+ force_detach = each.value.force_detach
+ skip_destroy = each.value.skip_destroy
+ stop_instance_before_detaching = each.value.stop_instance_before_detaching
}
################################################################################
@@ -604,6 +719,94 @@ resource "aws_iam_instance_profile" "this" {
}
}
+################################################################################
+# Security Group
+################################################################################
+
+locals {
+ create_security_group = var.create && var.create_security_group && var.network_interface == null
+ security_group_name = try(coalesce(var.security_group_name, var.name), "")
+
+ vpc_security_group_ids = local.create_security_group ? concat(var.vpc_security_group_ids, [aws_security_group.this[0].id]) : var.vpc_security_group_ids
+}
+
+data "aws_subnet" "this" {
+ count = local.create_security_group ? 1 : 0
+
+ region = var.region
+
+ id = var.subnet_id
+}
+
+resource "aws_security_group" "this" {
+ count = local.create_security_group ? 1 : 0
+
+ region = var.region
+
+ name = var.security_group_use_name_prefix ? null : local.security_group_name
+ name_prefix = var.security_group_use_name_prefix ? "${local.security_group_name}-" : null
+ description = var.security_group_description
+ vpc_id = coalesce(var.security_group_vpc_id, data.aws_subnet.this[0].vpc_id)
+
+ tags = merge(
+ var.tags,
+ { "Name" = local.security_group_name },
+ var.security_group_tags
+ )
+
+ lifecycle {
+ create_before_destroy = true
+ }
+}
+
+resource "aws_vpc_security_group_egress_rule" "this" {
+ for_each = local.create_security_group && var.security_group_egress_rules != null ? var.security_group_egress_rules : {}
+
+ region = var.region
+
+ cidr_ipv4 = each.value.cidr_ipv4
+ cidr_ipv6 = each.value.cidr_ipv6
+ description = each.value.description
+ from_port = try(coalesce(each.value.from_port, each.value.to_port), null)
+ ip_protocol = each.value.ip_protocol
+ prefix_list_id = each.value.prefix_list_id
+ referenced_security_group_id = each.value.referenced_security_group_id
+ security_group_id = aws_security_group.this[0].id
+
+ tags = merge(
+ var.tags,
+ var.security_group_tags,
+ { "Name" = "${var.name}-${each.key}" },
+ each.value.tags,
+ )
+
+ to_port = try(coalesce(each.value.to_port, each.value.from_port), null)
+}
+
+resource "aws_vpc_security_group_ingress_rule" "this" {
+ for_each = local.create_security_group && var.security_group_ingress_rules != null ? var.security_group_ingress_rules : {}
+
+ region = var.region
+
+ cidr_ipv4 = each.value.cidr_ipv4
+ cidr_ipv6 = each.value.cidr_ipv6
+ description = each.value.description
+ from_port = try(coalesce(each.value.from_port, each.value.to_port), null)
+ ip_protocol = each.value.ip_protocol
+ prefix_list_id = each.value.prefix_list_id
+ referenced_security_group_id = each.value.referenced_security_group_id
+ security_group_id = aws_security_group.this[0].id
+
+ tags = merge(
+ var.tags,
+ var.security_group_tags,
+ { "Name" = "${var.name}-${each.key}" },
+ each.value.tags,
+ )
+
+ to_port = try(coalesce(each.value.to_port, each.value.from_port), null)
+}
+
################################################################################
# Elastic IP
################################################################################
@@ -611,12 +814,10 @@ resource "aws_iam_instance_profile" "this" {
resource "aws_eip" "this" {
count = local.create && var.create_eip && !var.create_spot_instance ? 1 : 0
- instance = try(
- aws_instance.this[0].id,
- aws_instance.ignore_ami[0].id,
- )
+ region = var.region
- domain = var.eip_domain
+ domain = var.eip_domain
+ instance = local.instance_id
tags = merge(var.tags, var.eip_tags)
}
diff --git a/outputs.tf b/outputs.tf
index 3f57b650..3b6a9818 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -1,11 +1,6 @@
output "id" {
description = "The ID of the instance"
- value = try(
- aws_instance.this[0].id,
- aws_instance.ignore_ami[0].id,
- aws_spot_instance_request.this[0].id,
- null,
- )
+ value = local.instance_id
}
output "arn" {
@@ -156,12 +151,16 @@ output "ami" {
output "availability_zone" {
description = "The availability zone of the created instance"
- value = try(
- aws_instance.this[0].availability_zone,
- aws_instance.ignore_ami[0].availability_zone,
- aws_spot_instance_request.this[0].availability_zone,
- null,
- )
+ value = local.instance_availability_zone
+}
+
+################################################################################
+# EBS Volume(s)
+################################################################################
+
+output "ebs_volumes" {
+ description = "Map of EBS volumes created and their attributes"
+ value = aws_ebs_volume.this
}
################################################################################
@@ -201,6 +200,7 @@ output "iam_instance_profile_unique" {
################################################################################
# Block Devices
################################################################################
+
output "root_block_device" {
description = "Root block device information"
value = try(
diff --git a/variables.tf b/variables.tf
index e59a9dc8..f354c2ce 100644
--- a/variables.tf
+++ b/variables.tf
@@ -10,18 +10,28 @@ variable "name" {
default = ""
}
-variable "ami_ssm_parameter" {
- description = "SSM parameter name for the AMI ID. For Amazon Linux AMI SSM parameters see [reference](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters-ami.html)"
+variable "region" {
+ description = "Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration"
type = string
- default = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
+ default = null
}
+################################################################################
+# Instance
+################################################################################
+
variable "ami" {
description = "ID of AMI to use for the instance"
type = string
default = null
}
+variable "ami_ssm_parameter" {
+ description = "SSM parameter name for the AMI ID. For Amazon Linux AMI SSM parameters see [reference](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters-ami.html)"
+ type = string
+ default = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"
+}
+
variable "ignore_ami_changes" {
description = "Whether changes to the AMI ID changes should be ignored by Terraform. Note - changing this value will result in the replacement of the instance"
type = bool
@@ -34,12 +44,6 @@ variable "associate_public_ip_address" {
default = null
}
-variable "maintenance_options" {
- description = "The maintenance options for the instance"
- type = any
- default = {}
-}
-
variable "availability_zone" {
description = "AZ to start the instance in"
type = string
@@ -48,8 +52,24 @@ variable "availability_zone" {
variable "capacity_reservation_specification" {
description = "Describes an instance's Capacity Reservation targeting option"
- type = any
- default = {}
+ type = object({
+ capacity_reservation_preference = optional(string)
+ capacity_reservation_target = optional(object({
+ capacity_reservation_id = optional(string)
+ capacity_reservation_resource_group_arn = optional(string)
+ }))
+ })
+ default = null
+}
+
+variable "cpu_options" {
+ description = "Defines CPU options to apply to the instance at launch time."
+ type = object({
+ amd_sev_snp = optional(string)
+ core_count = optional(number)
+ threads_per_core = optional(number)
+ })
+ default = null
}
variable "cpu_credits" {
@@ -64,10 +84,10 @@ variable "disable_api_termination" {
default = null
}
-variable "ebs_block_device" {
- description = "Additional EBS block devices to attach to the instance"
- type = list(any)
- default = []
+variable "disable_api_stop" {
+ description = "If true, enables EC2 Instance Stop Protection"
+ type = bool
+ default = null
}
variable "ebs_optimized" {
@@ -82,10 +102,20 @@ variable "enclave_options_enabled" {
default = null
}
+variable "enable_primary_ipv6" {
+ description = "Whether to assign a primary IPv6 Global Unicast Address (GUA) to the instance when launched in a dual-stack or IPv6-only subnet"
+ type = bool
+ default = null
+}
+
variable "ephemeral_block_device" {
description = "Customize Ephemeral (also known as Instance Store) volumes on the instance"
- type = list(map(string))
- default = []
+ type = map(object({
+ device_name = string
+ no_device = optional(bool)
+ virtual_name = optional(string)
+ }))
+ default = null
}
variable "get_password_data" {
@@ -106,6 +136,12 @@ variable "host_id" {
default = null
}
+variable "host_resource_group_arn" {
+ description = "ARN of the host resource group in which to launch the instances. If you specify an ARN, omit the `tenancy` parameter or set it to `host`"
+ type = string
+ default = null
+}
+
variable "iam_instance_profile" {
description = "IAM Instance Profile to launch the instance with. Specified as the name of the Instance Profile"
type = string
@@ -118,18 +154,26 @@ variable "instance_initiated_shutdown_behavior" {
default = null
}
+variable "instance_market_options" {
+ description = "The market (purchasing) option for the instance. If set, overrides the `create_spot_instance` variable"
+ type = object({
+ market_type = optional(string)
+ spot_options = optional(object({
+ instance_interruption_behavior = optional(string)
+ max_price = optional(string)
+ spot_instance_type = optional(string)
+ valid_until = optional(string)
+ }))
+ })
+ default = null
+}
+
variable "instance_type" {
description = "The type of instance to start"
type = string
default = "t3.micro"
}
-variable "instance_tags" {
- description = "Additional tags for the instance"
- type = map(string)
- default = {}
-}
-
variable "ipv6_address_count" {
description = "A number of IPv6 addresses to associate with the primary network interface. Amazon EC2 chooses the IPv6 addresses from the range of your subnet"
type = number
@@ -150,17 +194,35 @@ variable "key_name" {
variable "launch_template" {
description = "Specifies a Launch Template to configure the instance. Parameters configured on this resource will override the corresponding parameters in the Launch Template"
- type = map(string)
- default = {}
+ type = object({
+ id = optional(string)
+ name = optional(string)
+ version = optional(string)
+ })
+ default = null
+}
+
+variable "maintenance_options" {
+ description = "The maintenance options for the instance"
+ type = object({
+ auto_recovery = optional(string)
+ })
+ default = null
}
variable "metadata_options" {
description = "Customize the metadata options of the instance"
- type = map(string)
+ type = object({
+ http_endpoint = optional(string, "enabled")
+ http_protocol_ipv6 = optional(string)
+ http_put_response_hop_limit = optional(number, 1)
+ http_tokens = optional(string, "required")
+ instance_metadata_tags = optional(string)
+ })
default = {
- "http_endpoint" = "enabled"
- "http_put_response_hop_limit" = 1
- "http_tokens" = "required"
+ http_endpoint = "enabled"
+ http_put_response_hop_limit = 1
+ http_tokens = "required"
}
}
@@ -172,14 +234,13 @@ variable "monitoring" {
variable "network_interface" {
description = "Customize network interfaces to be attached at instance boot time"
- type = list(map(string))
- default = []
-}
-
-variable "private_dns_name_options" {
- description = "Customize the private DNS name options of the instance"
- type = map(string)
- default = {}
+ type = map(object({
+ delete_on_termination = optional(bool)
+ device_index = optional(number) # Will fall back to use map key as device index
+ network_card_index = optional(number)
+ network_interface_id = string
+ }))
+ default = null
}
variable "placement_group" {
@@ -188,6 +249,22 @@ variable "placement_group" {
default = null
}
+variable "placement_partition_number" {
+ description = "Number of the partition the instance is in. Valid only if the `aws_placement_group` resource's `strategy` argument is set to `partition`"
+ type = number
+ default = null
+}
+
+variable "private_dns_name_options" {
+ description = "Customize the private DNS name options of the instance"
+ type = object({
+ enable_resource_name_dns_a_record = optional(bool)
+ enable_resource_name_dns_aaaa_record = optional(bool)
+ hostname_type = optional(string)
+ })
+ default = null
+}
+
variable "private_ip" {
description = "Private IP address to associate with the instance in a VPC"
type = string
@@ -196,8 +273,17 @@ variable "private_ip" {
variable "root_block_device" {
description = "Customize details about the root block device of the instance. See Block Devices below for details"
- type = list(any)
- default = []
+ type = object({
+ delete_on_termination = optional(bool)
+ encrypted = optional(bool)
+ iops = optional(number)
+ kms_key_id = optional(string)
+ tags = optional(map(string), {})
+ throughput = optional(number)
+ size = optional(number)
+ type = optional(string)
+ })
+ default = null
}
variable "secondary_private_ips" {
@@ -224,6 +310,12 @@ variable "tags" {
default = {}
}
+variable "instance_tags" {
+ description = "Additional tags for the instance"
+ type = map(string)
+ default = {}
+}
+
variable "tenancy" {
description = "The tenancy of the instance (if the instance is running in a VPC). Available values: default, dedicated, host"
type = string
@@ -263,7 +355,7 @@ variable "enable_volume_tags" {
variable "vpc_security_group_ids" {
description = "A list of security group IDs to associate with"
type = list(string)
- default = null
+ default = []
}
variable "timeouts" {
@@ -272,63 +364,48 @@ 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
- default = null
-}
-
-variable "cpu_threads_per_core" {
- description = "Sets the number of CPU threads per core for an instance (has no effect unless cpu_core_count is also set)"
- type = number
- default = null
-}
+################################################################################
+# Spot Instance Request
+################################################################################
-# Spot instance request
variable "create_spot_instance" {
description = "Depicts if the instance is a spot instance"
type = bool
default = false
}
-variable "spot_price" {
- description = "The maximum price to request on the spot market. Defaults to on-demand price"
+variable "spot_instance_interruption_behavior" {
+ description = "Indicates Spot instance behavior when it is interrupted. Valid values are `terminate`, `stop`, or `hibernate`"
type = string
default = null
}
-variable "spot_wait_for_fulfillment" {
- description = "If set, Terraform will wait for the Spot Request to be fulfilled, and will throw an error if the timeout of 10m is reached"
- type = bool
+variable "spot_launch_group" {
+ description = "A launch group is a group of spot instances that launch together and terminate together. If left empty instances are launched and terminated individually"
+ type = string
default = null
}
-variable "spot_type" {
- description = "If set to one-time, after the instance is terminated, the spot request will be closed. Default `persistent`"
+variable "spot_price" {
+ description = "The maximum price to request on the spot market. Defaults to on-demand price"
type = string
default = null
}
-variable "spot_launch_group" {
- description = "A launch group is a group of spot instances that launch together and terminate together. If left empty instances are launched and terminated individually"
+variable "spot_type" {
+ description = "If set to one-time, after the instance is terminated, the spot request will be closed. Default `persistent`"
type = string
default = null
}
-variable "spot_block_duration_minutes" {
- description = "The required duration for the Spot instances, in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, or 360)"
- type = number
+variable "spot_wait_for_fulfillment" {
+ description = "If set, Terraform will wait for the Spot Request to be fulfilled, and will throw an error if the timeout of 10m is reached"
+ type = bool
default = null
}
-variable "spot_instance_interruption_behavior" {
- description = "Indicates Spot instance behavior when it is interrupted. Valid values are `terminate`, `stop`, or `hibernate`"
+variable "spot_valid_from" {
+ description = "The start date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ)"
type = string
default = null
}
@@ -339,22 +416,31 @@ variable "spot_valid_until" {
default = null
}
-variable "spot_valid_from" {
- description = "The start date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ)"
- type = string
- default = null
-}
-
-variable "disable_api_stop" {
- description = "If true, enables EC2 Instance Stop Protection"
- type = bool
- default = null
+################################################################################
+# EBS Volume(s)
+################################################################################
-}
-variable "putin_khuylo" {
- description = "Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo!"
- type = bool
- default = true
+variable "ebs_volumes" {
+ description = "Additional EBS volumes to attach to the instance"
+ type = map(object({
+ encrypted = optional(bool)
+ final_snapshot = optional(bool)
+ iops = optional(number)
+ kms_key_id = optional(string)
+ multi_attach_enabled = optional(bool)
+ outpost_arn = optional(string)
+ size = optional(number)
+ snapshot_id = optional(string)
+ tags = optional(map(string), {})
+ throughput = optional(number)
+ type = optional(string, "gp3")
+ # Attachment
+ device_name = optional(string) # Will fall back to use map key as device name
+ force_detach = optional(bool)
+ skip_destroy = optional(bool)
+ stop_instance_before_detaching = optional(bool)
+ }))
+ default = null
}
################################################################################
@@ -409,6 +495,89 @@ variable "iam_role_tags" {
default = {}
}
+################################################################################
+# Security Group
+################################################################################
+
+variable "create_security_group" {
+ description = "Determines whether a security group will be created"
+ type = bool
+ default = true
+}
+
+variable "security_group_name" {
+ description = "Name to use on security group created"
+ type = string
+ default = null
+}
+
+variable "security_group_use_name_prefix" {
+ description = "Determines whether the security group name (`security_group_name` or `name`) is used as a prefix"
+ type = bool
+ default = true
+}
+
+variable "security_group_description" {
+ description = "Description of the security group"
+ type = string
+ default = null
+}
+
+variable "security_group_vpc_id" {
+ description = "VPC ID to create the security group in. If not set, the security group will be created in the default VPC"
+ type = string
+ default = null
+}
+
+variable "security_group_tags" {
+ description = "A map of additional tags to add to the security group created"
+ type = map(string)
+ default = {}
+}
+
+variable "security_group_egress_rules" {
+ description = "Egress rules to add to the security group"
+ type = map(object({
+ cidr_ipv4 = optional(string)
+ cidr_ipv6 = optional(string)
+ description = optional(string)
+ from_port = optional(number)
+ ip_protocol = optional(string, "tcp")
+ prefix_list_id = optional(string)
+ referenced_security_group_id = optional(string)
+ tags = optional(map(string), {})
+ to_port = optional(number)
+ }))
+ default = {
+ ipv4_default = {
+ cidr_ipv4 = "0.0.0.0/0"
+ description = "Allow all IPv4 traffic"
+ ip_protocol = "-1"
+ }
+ ipv6_default = {
+ cidr_ipv6 = "::/0"
+ description = "Allow all IPv6 traffic"
+ ip_protocol = "-1"
+ }
+ }
+}
+
+variable "security_group_ingress_rules" {
+ description = "Egress rules to add to the security group"
+ type = map(object({
+ cidr_ipv4 = optional(string)
+ cidr_ipv6 = optional(string)
+ description = optional(string)
+ from_port = optional(number)
+ ip_protocol = optional(string, "tcp")
+ prefix_list_id = optional(string)
+ referenced_security_group_id = optional(string)
+ tags = optional(map(string), {})
+ to_port = optional(number)
+ }))
+ default = null
+}
+
################################################################################
# Elastic IP
################################################################################
@@ -430,3 +599,9 @@ variable "eip_tags" {
type = map(string)
default = {}
}
+
+variable "putin_khuylo" {
+ description = "Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo!"
+ type = bool
+ default = true
+}
diff --git a/versions.tf b/versions.tf
index fd4d1167..f648e20c 100644
--- a/versions.tf
+++ b/versions.tf
@@ -1,10 +1,10 @@
terraform {
- required_version = ">= 1.0"
+ required_version = ">= 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
- version = ">= 4.66"
+ version = ">= 6.0"
}
}
}
diff --git a/wrappers/main.tf b/wrappers/main.tf
index 048da569..fe9fc307 100644
--- a/wrappers/main.tf
+++ b/wrappers/main.tf
@@ -4,30 +4,31 @@ module "wrapper" {
for_each = var.items
ami = try(each.value.ami, var.defaults.ami, null)
- ami_ssm_parameter = try(each.value.ami_ssm_parameter, var.defaults.ami_ssm_parameter, "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2")
+ ami_ssm_parameter = try(each.value.ami_ssm_parameter, var.defaults.ami_ssm_parameter, "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64")
associate_public_ip_address = try(each.value.associate_public_ip_address, var.defaults.associate_public_ip_address, null)
availability_zone = try(each.value.availability_zone, var.defaults.availability_zone, null)
- capacity_reservation_specification = try(each.value.capacity_reservation_specification, var.defaults.capacity_reservation_specification, {})
- cpu_core_count = try(each.value.cpu_core_count, var.defaults.cpu_core_count, null)
+ capacity_reservation_specification = try(each.value.capacity_reservation_specification, var.defaults.capacity_reservation_specification, null)
cpu_credits = try(each.value.cpu_credits, var.defaults.cpu_credits, null)
- cpu_options = try(each.value.cpu_options, var.defaults.cpu_options, {})
- cpu_threads_per_core = try(each.value.cpu_threads_per_core, var.defaults.cpu_threads_per_core, null)
+ cpu_options = try(each.value.cpu_options, var.defaults.cpu_options, null)
create = try(each.value.create, var.defaults.create, true)
create_eip = try(each.value.create_eip, var.defaults.create_eip, false)
create_iam_instance_profile = try(each.value.create_iam_instance_profile, var.defaults.create_iam_instance_profile, false)
+ create_security_group = try(each.value.create_security_group, var.defaults.create_security_group, true)
create_spot_instance = try(each.value.create_spot_instance, var.defaults.create_spot_instance, false)
disable_api_stop = try(each.value.disable_api_stop, var.defaults.disable_api_stop, null)
disable_api_termination = try(each.value.disable_api_termination, var.defaults.disable_api_termination, null)
- ebs_block_device = try(each.value.ebs_block_device, var.defaults.ebs_block_device, [])
ebs_optimized = try(each.value.ebs_optimized, var.defaults.ebs_optimized, null)
+ ebs_volumes = try(each.value.ebs_volumes, var.defaults.ebs_volumes, null)
eip_domain = try(each.value.eip_domain, var.defaults.eip_domain, "vpc")
eip_tags = try(each.value.eip_tags, var.defaults.eip_tags, {})
+ enable_primary_ipv6 = try(each.value.enable_primary_ipv6, var.defaults.enable_primary_ipv6, null)
enable_volume_tags = try(each.value.enable_volume_tags, var.defaults.enable_volume_tags, true)
enclave_options_enabled = try(each.value.enclave_options_enabled, var.defaults.enclave_options_enabled, null)
- ephemeral_block_device = try(each.value.ephemeral_block_device, var.defaults.ephemeral_block_device, [])
+ ephemeral_block_device = try(each.value.ephemeral_block_device, var.defaults.ephemeral_block_device, null)
get_password_data = try(each.value.get_password_data, var.defaults.get_password_data, null)
hibernation = try(each.value.hibernation, var.defaults.hibernation, null)
host_id = try(each.value.host_id, var.defaults.host_id, null)
+ host_resource_group_arn = try(each.value.host_resource_group_arn, var.defaults.host_resource_group_arn, null)
iam_instance_profile = try(each.value.iam_instance_profile, var.defaults.iam_instance_profile, null)
iam_role_description = try(each.value.iam_role_description, var.defaults.iam_role_description, null)
iam_role_name = try(each.value.iam_role_name, var.defaults.iam_role_name, null)
@@ -38,29 +39,49 @@ module "wrapper" {
iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true)
ignore_ami_changes = try(each.value.ignore_ami_changes, var.defaults.ignore_ami_changes, false)
instance_initiated_shutdown_behavior = try(each.value.instance_initiated_shutdown_behavior, var.defaults.instance_initiated_shutdown_behavior, null)
+ instance_market_options = try(each.value.instance_market_options, var.defaults.instance_market_options, null)
instance_tags = try(each.value.instance_tags, var.defaults.instance_tags, {})
instance_type = try(each.value.instance_type, var.defaults.instance_type, "t3.micro")
ipv6_address_count = try(each.value.ipv6_address_count, var.defaults.ipv6_address_count, null)
ipv6_addresses = try(each.value.ipv6_addresses, var.defaults.ipv6_addresses, null)
key_name = try(each.value.key_name, var.defaults.key_name, null)
- launch_template = try(each.value.launch_template, var.defaults.launch_template, {})
- maintenance_options = try(each.value.maintenance_options, var.defaults.maintenance_options, {})
+ launch_template = try(each.value.launch_template, var.defaults.launch_template, null)
+ maintenance_options = try(each.value.maintenance_options, var.defaults.maintenance_options, null)
metadata_options = try(each.value.metadata_options, var.defaults.metadata_options, {
- "http_endpoint" = "enabled"
- "http_put_response_hop_limit" = 1
- "http_tokens" = "required"
+ http_endpoint = "enabled"
+ http_put_response_hop_limit = 1
+ http_tokens = "required"
})
- monitoring = try(each.value.monitoring, var.defaults.monitoring, null)
- name = try(each.value.name, var.defaults.name, "")
- network_interface = try(each.value.network_interface, var.defaults.network_interface, [])
- placement_group = try(each.value.placement_group, var.defaults.placement_group, null)
- private_dns_name_options = try(each.value.private_dns_name_options, var.defaults.private_dns_name_options, {})
- private_ip = try(each.value.private_ip, var.defaults.private_ip, null)
- putin_khuylo = try(each.value.putin_khuylo, var.defaults.putin_khuylo, true)
- root_block_device = try(each.value.root_block_device, var.defaults.root_block_device, [])
- secondary_private_ips = try(each.value.secondary_private_ips, var.defaults.secondary_private_ips, null)
+ monitoring = try(each.value.monitoring, var.defaults.monitoring, null)
+ name = try(each.value.name, var.defaults.name, "")
+ network_interface = try(each.value.network_interface, var.defaults.network_interface, null)
+ placement_group = try(each.value.placement_group, var.defaults.placement_group, null)
+ placement_partition_number = try(each.value.placement_partition_number, var.defaults.placement_partition_number, null)
+ private_dns_name_options = try(each.value.private_dns_name_options, var.defaults.private_dns_name_options, null)
+ private_ip = try(each.value.private_ip, var.defaults.private_ip, null)
+ putin_khuylo = try(each.value.putin_khuylo, var.defaults.putin_khuylo, true)
+ region = try(each.value.region, var.defaults.region, null)
+ root_block_device = try(each.value.root_block_device, var.defaults.root_block_device, null)
+ secondary_private_ips = try(each.value.secondary_private_ips, var.defaults.secondary_private_ips, null)
+ security_group_description = try(each.value.security_group_description, var.defaults.security_group_description, null)
+ security_group_egress_rules = try(each.value.security_group_egress_rules, var.defaults.security_group_egress_rules, {
+ ipv4_default = {
+ cidr_ipv4 = "0.0.0.0/0"
+ description = "Allow all IPv4 traffic"
+ ip_protocol = "-1"
+ }
+ ipv6_default = {
+ cidr_ipv6 = "::/0"
+ description = "Allow all IPv6 traffic"
+ ip_protocol = "-1"
+ }
+ })
+ security_group_ingress_rules = try(each.value.security_group_ingress_rules, var.defaults.security_group_ingress_rules, null)
+ security_group_name = try(each.value.security_group_name, var.defaults.security_group_name, null)
+ security_group_tags = try(each.value.security_group_tags, var.defaults.security_group_tags, {})
+ security_group_use_name_prefix = try(each.value.security_group_use_name_prefix, var.defaults.security_group_use_name_prefix, true)
+ security_group_vpc_id = try(each.value.security_group_vpc_id, var.defaults.security_group_vpc_id, null)
source_dest_check = try(each.value.source_dest_check, var.defaults.source_dest_check, null)
- spot_block_duration_minutes = try(each.value.spot_block_duration_minutes, var.defaults.spot_block_duration_minutes, null)
spot_instance_interruption_behavior = try(each.value.spot_instance_interruption_behavior, var.defaults.spot_instance_interruption_behavior, null)
spot_launch_group = try(each.value.spot_launch_group, var.defaults.spot_launch_group, null)
spot_price = try(each.value.spot_price, var.defaults.spot_price, null)
@@ -76,5 +97,5 @@ module "wrapper" {
user_data_base64 = try(each.value.user_data_base64, var.defaults.user_data_base64, null)
user_data_replace_on_change = try(each.value.user_data_replace_on_change, var.defaults.user_data_replace_on_change, null)
volume_tags = try(each.value.volume_tags, var.defaults.volume_tags, {})
- vpc_security_group_ids = try(each.value.vpc_security_group_ids, var.defaults.vpc_security_group_ids, null)
+ vpc_security_group_ids = try(each.value.vpc_security_group_ids, var.defaults.vpc_security_group_ids, [])
}
diff --git a/wrappers/versions.tf b/wrappers/versions.tf
index fd4d1167..f648e20c 100644
--- a/wrappers/versions.tf
+++ b/wrappers/versions.tf
@@ -1,10 +1,10 @@
terraform {
- required_version = ">= 1.0"
+ required_version = ">= 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
- version = ">= 4.66"
+ version = ">= 6.0"
}
}
}