diff --git a/README.md b/README.md index 9c3e8f66..d8d737c5 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,33 @@ module "ec2_instance" { } ``` +### Spot EC2 Instance + +```hcl +module "ec2_instance" { + source = "terraform-aws-modules/ec2-instance/aws" + version = "~> 3.0" + + name = "spot-instance" + + create_spot_instance = true + spot_price = "0.60" + spot_type = "persistent" + + ami = "ami-ebd02392" + instance_type = "t2.micro" + key_name = "user1" + monitoring = true + vpc_security_group_ids = ["sg-12345678"] + subnet_id = "subnet-eddcdzz4" + + tags = { + Terraform = "true" + Environment = "dev" + } +} +``` + ## Examples - [Complete EC2 instance](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete) @@ -105,10 +132,27 @@ data "aws_ami" "encrypted-ami" { } ``` +## Conditional creation + +The following combinations are supported to conditionally create resources: + +- Disable resource creation (no resources created): + +```hcl + create = false +``` + +- Create spot instance: + +```hcl + create_spot_instance = true +``` + ## 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` ## Requirements @@ -133,6 +177,7 @@ No modules. | Name | Type | |------|------| | [aws_instance.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | +| [aws_spot_instance_request.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/spot_instance_request) | resource | ## Inputs @@ -146,6 +191,7 @@ No modules. | [cpu\_credits](#input\_cpu\_credits) | The credit option for CPU usage (unlimited or standard) | `string` | `null` | no | | [cpu\_threads\_per\_core](#input\_cpu\_threads\_per\_core) | Sets the number of CPU threads per core for an instance (has no effect unless cpu\_core\_count is also set). | `number` | `null` | no | | [create](#input\_create) | Whether to create an instance | `bool` | `true` | no | +| [create\_spot\_instance](#input\_create\_spot\_instance) | Depicts if the instance is a spot instance | `bool` | `false` | 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(map(string))` | `[]` | no | | [ebs\_optimized](#input\_ebs\_optimized) | If true, the launched EC2 instance will be EBS-optimized | `bool` | `null` | no | @@ -171,6 +217,14 @@ No modules. | [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 | | [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 | | [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` | `true` | 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 | +| [spot\_type](#input\_spot\_type) | If set to one-time, after the instance is terminated, the spot request will be closed. Default `persistent` | `string` | `null` | no | +| [spot\_valid\_from](#input\_spot\_valid\_from) | The start date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ) | `string` | `null` | no | +| [spot\_valid\_until](#input\_spot\_valid\_until) | The end date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ) | `string` | `null` | no | +| [spot\_wait\_for\_fulfillment](#input\_spot\_wait\_for\_fulfillment) | If set, Terraform will wait for the Spot Request to be fulfilled, and will throw an error if the timeout of 10m is reached | `bool` | `null` | no | | [subnet\_id](#input\_subnet\_id) | The VPC Subnet ID to launch in | `string` | `null` | no | | [tags](#input\_tags) | A mapping of tags to assign to the resource | `map(string)` | `{}` | no | | [tenancy](#input\_tenancy) | The tenancy of the instance (if the instance is running in a VPC). Available values: default, dedicated, host. | `string` | `null` | no | @@ -194,6 +248,9 @@ No modules. | [private\_dns](#output\_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 | | [public\_dns](#output\_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 | | [public\_ip](#output\_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 | +| [spot\_bid\_status](#output\_spot\_bid\_status) | The current bid status of the Spot Instance Request | +| [spot\_instance\_id](#output\_spot\_instance\_id) | The Instance ID (if any) that is currently fulfilling the Spot Instance request | +| [spot\_request\_state](#output\_spot\_request\_state) | The current request state of the Spot Instance Request | | [tags\_all](#output\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | diff --git a/examples/complete/README.md b/examples/complete/README.md index 005d209c..5431cb6e 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -37,6 +37,7 @@ Note that this example may create resources which can cost money. Run `terraform | [ec2\_metadata\_options](#module\_ec2\_metadata\_options) | ../../ | | | [ec2\_multiple](#module\_ec2\_multiple) | ../../ | | | [ec2\_network\_interface](#module\_ec2\_network\_interface) | ../../ | | +| [ec2\_spot\_instance](#module\_ec2\_spot\_instance) | ../../ | | | [ec2\_t2\_unlimited](#module\_ec2\_t2\_unlimited) | ../../ | | | [ec2\_t3\_unlimited](#module\_ec2\_t3\_unlimited) | ../../ | | | [security\_group](#module\_security\_group) | terraform-aws-modules/security-group/aws | ~> 4.0 | @@ -69,6 +70,15 @@ No inputs. | [ec2\_complete\_public\_ip](#output\_ec2\_complete\_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\_complete\_tags\_all](#output\_ec2\_complete\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | | [ec2\_multiple](#output\_ec2\_multiple) | The full output of the `ec2_module` module | +| [ec2\_spot\_instance\_arn](#output\_ec2\_spot\_instance\_arn) | The ARN of the instance | +| [ec2\_spot\_instance\_capacity\_reservation\_specification](#output\_ec2\_spot\_instance\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | +| [ec2\_spot\_instance\_id](#output\_ec2\_spot\_instance\_id) | The ID of the instance | +| [ec2\_spot\_instance\_instance\_state](#output\_ec2\_spot\_instance\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` | +| [ec2\_spot\_instance\_primary\_network\_interface\_id](#output\_ec2\_spot\_instance\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | +| [ec2\_spot\_instance\_private\_dns](#output\_ec2\_spot\_instance\_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\_spot\_instance\_public\_dns](#output\_ec2\_spot\_instance\_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\_spot\_instance\_public\_ip](#output\_ec2\_spot\_instance\_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\_spot\_instance\_tags\_all](#output\_ec2\_spot\_instance\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | | [ec2\_t2\_unlimited\_arn](#output\_ec2\_t2\_unlimited\_arn) | The ARN of the instance | | [ec2\_t2\_unlimited\_capacity\_reservation\_specification](#output\_ec2\_t2\_unlimited\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | | [ec2\_t2\_unlimited\_id](#output\_ec2\_t2\_unlimited\_id) | The ID of the instance | @@ -87,4 +97,7 @@ No inputs. | [ec2\_t3\_unlimited\_public\_dns](#output\_ec2\_t3\_unlimited\_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\_t3\_unlimited\_public\_ip](#output\_ec2\_t3\_unlimited\_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\_t3\_unlimited\_tags\_all](#output\_ec2\_t3\_unlimited\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | +| [spot\_bid\_status](#output\_spot\_bid\_status) | The current bid status of the Spot Instance Request | +| [spot\_instance\_id](#output\_spot\_instance\_id) | The Instance ID (if any) that is currently fulfilling the Spot Instance request | +| [spot\_request\_state](#output\_spot\_request\_state) | The current request state of the Spot Instance Request | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 25664c35..2575b406 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -264,3 +264,64 @@ module "ec2_multiple" { tags = local.tags } + +################################################################################ +# EC2 Module - spot instance request +################################################################################ + +module "ec2_spot_instance" { + source = "../../" + + name = "${local.name}-spot-instance" + create_spot_instance = true + + ami = data.aws_ami.amazon_linux.id + instance_type = "c4.4xlarge" + 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 + + # Spot request specific attributes + spot_price = "0.60" + spot_wait_for_fulfillment = true + spot_type = "persistent" + spot_instance_interruption_behavior = "terminate" + # End spot request specific attributes + + user_data_base64 = base64encode(local.user_data) + + cpu_core_count = 2 # default 4 + cpu_threads_per_core = 1 # default 2 + + capacity_reservation_specification = { + capacity_reservation_preference = "open" + } + + 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 # you must grant the AWSServiceRoleForEC2Spot service-linked role access to any custom KMS keys + } + ] + + tags = local.tags +} diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index b6911d9c..e87dfe82 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -141,3 +141,64 @@ output "ec2_multiple" { description = "The full output of the `ec2_module` module" value = module.ec2_multiple } + +# EC2 Spot Instance +output "ec2_spot_instance_id" { + description = "The ID of the instance" + value = module.ec2_spot_instance.id +} + +output "ec2_spot_instance_arn" { + description = "The ARN of the instance" + value = module.ec2_spot_instance.arn +} + +output "ec2_spot_instance_capacity_reservation_specification" { + description = "Capacity reservation specification of the instance" + value = module.ec2_spot_instance.capacity_reservation_specification +} + +output "ec2_spot_instance_instance_state" { + description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" + value = module.ec2_spot_instance.instance_state +} + +output "ec2_spot_instance_primary_network_interface_id" { + description = "The ID of the instance's primary network interface" + value = module.ec2_spot_instance.primary_network_interface_id +} + +output "ec2_spot_instance_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_spot_instance.private_dns +} + +output "ec2_spot_instance_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_spot_instance.public_dns +} + +output "ec2_spot_instance_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_spot_instance.public_ip +} + +output "ec2_spot_instance_tags_all" { + description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" + value = module.ec2_spot_instance.tags_all +} + +output "spot_bid_status" { + description = "The current bid status of the Spot Instance Request" + value = module.ec2_spot_instance.spot_bid_status +} + +output "spot_request_state" { + description = "The current request state of the Spot Instance Request" + value = module.ec2_spot_instance.spot_request_state +} + +output "spot_instance_id" { + description = "The Instance ID (if any) that is currently fulfilling the Spot Instance request" + value = module.ec2_spot_instance.spot_instance_id +} diff --git a/main.tf b/main.tf index 17165aa4..7983db79 100644 --- a/main.tf +++ b/main.tf @@ -3,7 +3,7 @@ locals { } resource "aws_instance" "this" { - count = var.create ? 1 : 0 + count = var.create && !var.create_spot_instance ? 1 : 0 ami = var.ami instance_type = var.instance_type @@ -133,3 +133,145 @@ resource "aws_instance" "this" { tags = merge({ "Name" = var.name }, var.tags) volume_tags = var.enable_volume_tags ? merge({ "Name" = var.name }, var.volume_tags) : null } + +resource "aws_spot_instance_request" "this" { + count = var.create && var.create_spot_instance ? 1 : 0 + + ami = var.ami + instance_type = var.instance_type + cpu_core_count = var.cpu_core_count + cpu_threads_per_core = var.cpu_threads_per_core + user_data = var.user_data + user_data_base64 = var.user_data_base64 + hibernation = var.hibernation + + 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.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 + + # Spot request specific attributes + 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 + valid_from = var.spot_valid_from + # End spot request specific attributes + + dynamic "capacity_reservation_specification" { + for_each = var.capacity_reservation_specification != null ? [var.capacity_reservation_specification] : [] + content { + capacity_reservation_preference = lookup(capacity_reservation_specification.value, "capacity_reservation_preference", null) + + dynamic "capacity_reservation_target" { + for_each = lookup(capacity_reservation_specification.value, "capacity_reservation_target", []) + content { + capacity_reservation_id = lookup(capacity_reservation_target.value, "capacity_reservation_id", null) + } + } + } + } + + dynamic "root_block_device" { + for_each = var.root_block_device + content { + delete_on_termination = lookup(root_block_device.value, "delete_on_termination", null) + encrypted = lookup(root_block_device.value, "encrypted", null) + iops = lookup(root_block_device.value, "iops", null) + kms_key_id = lookup(root_block_device.value, "kms_key_id", null) + volume_size = lookup(root_block_device.value, "volume_size", null) + volume_type = lookup(root_block_device.value, "volume_type", null) + throughput = lookup(root_block_device.value, "throughput", null) + tags = lookup(root_block_device.value, "tags", null) + } + } + + dynamic "ebs_block_device" { + for_each = var.ebs_block_device + content { + delete_on_termination = lookup(ebs_block_device.value, "delete_on_termination", null) + device_name = ebs_block_device.value.device_name + encrypted = lookup(ebs_block_device.value, "encrypted", null) + iops = lookup(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 = lookup(ebs_block_device.value, "volume_size", null) + volume_type = lookup(ebs_block_device.value, "volume_type", null) + throughput = lookup(ebs_block_device.value, "throughput", null) + } + } + + dynamic "ephemeral_block_device" { + for_each = var.ephemeral_block_device + content { + device_name = ephemeral_block_device.value.device_name + no_device = lookup(ephemeral_block_device.value, "no_device", null) + virtual_name = lookup(ephemeral_block_device.value, "virtual_name", null) + } + } + + dynamic "metadata_options" { + for_each = var.metadata_options != null ? [var.metadata_options] : [] + content { + http_endpoint = lookup(metadata_options.value, "http_endpoint", "enabled") + http_tokens = lookup(metadata_options.value, "http_tokens", "optional") + http_put_response_hop_limit = lookup(metadata_options.value, "http_put_response_hop_limit", "1") + } + } + + dynamic "network_interface" { + for_each = 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 = lookup(network_interface.value, "delete_on_termination", false) + } + } + + dynamic "launch_template" { + for_each = var.launch_template != null ? [var.launch_template] : [] + content { + id = lookup(var.launch_template, "id", null) + name = lookup(var.launch_template, "name", null) + version = lookup(var.launch_template, "version", null) + } + } + + enclave_options { + enabled = var.enclave_options_enabled + } + + 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 + + credit_specification { + cpu_credits = local.is_t_instance_type ? var.cpu_credits : null + } + + timeouts { + create = lookup(var.timeouts, "create", null) + delete = lookup(var.timeouts, "delete", null) + } + + tags = merge({ "Name" = var.name }, var.tags) + volume_tags = var.enable_volume_tags ? merge({ "Name" = var.name }, var.volume_tags) : null +} diff --git a/outputs.tf b/outputs.tf index bb7e34ba..76c798c5 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,54 +1,69 @@ output "id" { description = "The ID of the instance" - value = element(concat(aws_instance.this.*.id, [""]), 0) + value = element(concat(aws_instance.this.*.id, aws_spot_instance_request.this.*.id, [""]), 0) } output "arn" { description = "The ARN of the instance" - value = element(concat(aws_instance.this.*.arn, [""]), 0) + value = element(concat(aws_instance.this.*.arn, aws_spot_instance_request.this.*.arn, [""]), 0) } output "capacity_reservation_specification" { description = "Capacity reservation specification of the instance" - value = element(concat(aws_instance.this.*.capacity_reservation_specification, [""]), 0) + value = element(concat(aws_instance.this.*.capacity_reservation_specification, aws_spot_instance_request.this.*.capacity_reservation_specification, [""]), 0) } output "instance_state" { description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" - value = element(concat(aws_instance.this.*.instance_state, [""]), 0) + value = element(concat(aws_instance.this.*.instance_state, aws_spot_instance_request.this.*.instance_state, [""]), 0) } output "outpost_arn" { description = "The ARN of the Outpost the instance is assigned to" - value = element(concat(aws_instance.this.*.outpost_arn, [""]), 0) + value = element(concat(aws_instance.this.*.outpost_arn, aws_spot_instance_request.this.*.outpost_arn, [""]), 0) } output "password_data" { description = "Base-64 encoded encrypted password data for the instance. Useful for getting the administrator password for instances running Microsoft Windows. This attribute is only exported if `get_password_data` is true" - value = element(concat(aws_instance.this.*.password_data, [""]), 0) + value = element(concat(aws_instance.this.*.password_data, aws_spot_instance_request.this.*.password_data, [""]), 0) } output "primary_network_interface_id" { description = "The ID of the instance's primary network interface" - value = element(concat(aws_instance.this.*.primary_network_interface_id, [""]), 0) + value = element(concat(aws_instance.this.*.primary_network_interface_id, aws_spot_instance_request.this.*.primary_network_interface_id, [""]), 0) } output "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 = element(concat(aws_instance.this.*.private_dns, [""]), 0) + value = element(concat(aws_instance.this.*.private_dns, aws_spot_instance_request.this.*.private_dns, [""]), 0) } output "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 = element(concat(aws_instance.this.*.public_dns, [""]), 0) + value = element(concat(aws_instance.this.*.public_dns, aws_spot_instance_request.this.*.public_dns, [""]), 0) } output "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 = element(concat(aws_instance.this.*.public_ip, [""]), 0) + value = element(concat(aws_instance.this.*.public_ip, aws_spot_instance_request.this.*.public_ip, [""]), 0) } output "tags_all" { description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" - value = element(concat(aws_instance.this.*.tags_all, [""]), 0) + value = element(concat(aws_instance.this.*.tags_all, aws_spot_instance_request.this.*.tags_all, [""]), 0) +} + +output "spot_bid_status" { + description = "The current bid status of the Spot Instance Request" + value = element(concat(aws_spot_instance_request.this.*.spot_bid_status, [""]), 0) +} + +output "spot_request_state" { + description = "The current request state of the Spot Instance Request" + value = element(concat(aws_spot_instance_request.this.*.spot_request_state, [""]), 0) +} + +output "spot_instance_id" { + description = "The Instance ID (if any) that is currently fulfilling the Spot Instance request" + value = element(concat(aws_spot_instance_request.this.*.spot_instance_id, [""]), 0) } diff --git a/variables.tf b/variables.tf index e83e6592..65a38baa 100644 --- a/variables.tf +++ b/variables.tf @@ -243,3 +243,58 @@ variable "cpu_threads_per_core" { type = number default = null } + +# 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" + 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 + default = null +} + +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_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_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 + default = null +} + +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_valid_until" { + description = "The end date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ)" + type = string + 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 +}