diff --git a/.gitignore b/.gitignore index 141171d..4381353 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,24 @@ -# ignored files +# Terraform state files - Contains sensitive infrastructure state information *.tfstate *.tfstate.backup + +# Local Terraform directory - Contains downloaded providers and modules .terraform + +# IDE settings directory for IntelliJ .idea + +# IntelliJ project files *.iml + +# Go dependency file go.sum + +# Terraform lock file - Contains provider version constraints *.terraform.lock.hcl + +# Terraform crash log file - Generated during crashes crash.log + +# Variable definitions files - May contain sensitive values +*.tfvars \ No newline at end of file diff --git a/examples/basic/example.tf b/examples/basic/example.tf index 0cf5274..5ce4dad 100644 --- a/examples/basic/example.tf +++ b/examples/basic/example.tf @@ -16,8 +16,19 @@ module "ec2" { #instance instance_count = 1 - ami = "ami-08d658f84a6d84a80" - instance_type = "c4.xlarge" + instance_configuration = { + ami = "ami-08d658f84a6d84a80" + instance_type = "c4.xlarge" + + #Root Volume + root_block_device = [ + { + volume_type = "gp2" + volume_size = 15 + delete_on_termination = true + } + ] + } #Networking subnet_ids = ["subnet-xxxxxxxx"] @@ -28,14 +39,7 @@ module "ec2" { #IAM iam_instance_profile = "iam-profile-xxxxxxxxx" - #Root Volume - root_block_device = [ - { - volume_type = "gp2" - volume_size = 15 - delete_on_termination = true - } - ] + #Tags instance_tags = { "snapshot" = true } diff --git a/examples/complete/example.tf b/examples/complete/example.tf index d56f15c..89b0d4b 100644 --- a/examples/complete/example.tf +++ b/examples/complete/example.tf @@ -91,8 +91,21 @@ module "ec2" { ssh_allowed_ports = [22] #Instance instance_count = 1 - ami = "ami-0f8e81a3da6e2510a" - instance_type = "t2.nano" + instance_configuration = { + ami = "ami-0f8e81a3da6e2510a" + instance_type = "t2.nano" + + #Root Volume + root_block_device = [ + { + volume_type = "gp2" + volume_size = 15 + delete_on_termination = true + } + ] + #Mount EBS With User Data + user_data = file("user-data.sh") + } #Keypair public_key = "" @@ -103,14 +116,7 @@ module "ec2" { #IAM iam_instance_profile = module.iam-role.name - #Root Volume - root_block_device = [ - { - volume_type = "gp2" - volume_size = 15 - delete_on_termination = true - } - ] + #EBS Volume ebs_volume_enabled = true @@ -120,6 +126,5 @@ module "ec2" { #Tags instance_tags = { "snapshot" = true } - #Mount EBS With User Data - user_data = file("user-data.sh") + } \ No newline at end of file diff --git a/examples/spot_instance/example.tf b/examples/spot_instance/example.tf index f9e5e80..771963c 100644 --- a/examples/spot_instance/example.tf +++ b/examples/spot_instance/example.tf @@ -17,13 +17,23 @@ module "spot-ec2" { public_key = "" # Spot-instance - spot_price = "0.3" - spot_wait_for_fulfillment = true - spot_type = "persistent" - spot_instance_interruption_behavior = "terminate" - spot_instance_enabled = true - spot_instance_count = 1 - instance_type = "c4.xlarge" + spot_configuration = { + spot_price = "0.3" + wait_for_fulfillment = true + spot_type = "persistent" + instance_interruption_behavior = "terminate" + spot_instance_enabled = true + spot_instance_count = 1 + instance_type = "c4.xlarge" + + root_block_device = [ + { + volume_type = "gp2" + volume_size = 15 + delete_on_termination = true + } + ] + } #Networking subnet_ids = ["subnet-xxxxxxxx"] @@ -32,13 +42,6 @@ module "spot-ec2" { iam_instance_profile = "iam-profile-xxxxxxxxx" #Root Volume - root_block_device = [ - { - volume_type = "gp2" - volume_size = 15 - delete_on_termination = true - } - ] #EBS Volume ebs_volume_enabled = true diff --git a/main.tf b/main.tf index f061249..e25aa0b 100644 --- a/main.tf +++ b/main.tf @@ -148,33 +148,34 @@ data "aws_iam_policy_document" "kms" { #tfsec:ignore:aws-ec2-enforce-http-token-imds resource "aws_instance" "default" { count = var.enable && var.default_instance_enabled ? var.instance_count : 0 - ami = var.ami == "" ? data.aws_ami.ubuntu.id : var.ami - ebs_optimized = var.ebs_optimized - instance_type = var.instance_type + ami = var.instance_configuration.ami == "" ? data.aws_ami.ubuntu.id : var.instance_configuration.ami + ebs_optimized = var.instance_configuration.ebs_optimized + instance_type = var.instance_configuration.instance_type key_name = var.key_name == "" ? join("", aws_key_pair.default[*].key_name) : var.key_name - monitoring = var.monitoring + monitoring = var.instance_configuration.monitoring vpc_security_group_ids = length(var.sg_ids) < 1 ? aws_security_group.default[*].id : var.sg_ids subnet_id = element(distinct(compact(concat(var.subnet_ids))), count.index) - associate_public_ip_address = var.associate_public_ip_address - 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 - 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 - user_data_replace_on_change = var.user_data_replace_on_change - availability_zone = var.availability_zone - get_password_data = var.get_password_data - private_ip = var.private_ip - secondary_private_ips = var.secondary_private_ips + associate_public_ip_address = var.instance_configuration.associate_public_ip_address + disable_api_termination = var.instance_configuration.disable_api_termination + instance_initiated_shutdown_behavior = var.instance_configuration.instance_initiated_shutdown_behavior + placement_group = var.instance_configuration.placement_group + tenancy = var.instance_configuration.tenancy + host_id = var.instance_configuration.host_id + cpu_core_count = var.instance_configuration.cpu_core_count + cpu_threads_per_core = var.instance_configuration.cpu_threads_per_core + user_data = var.instance_configuration.user_data + user_data_base64 = var.instance_configuration.user_data_base64 + user_data_replace_on_change = var.instance_configuration.user_data_replace_on_change + availability_zone = var.instance_configuration.availability_zone + get_password_data = var.instance_configuration.get_password_data + private_ip = var.instance_configuration.private_ip + secondary_private_ips = var.instance_configuration.secondary_private_ips iam_instance_profile = join("", aws_iam_instance_profile.default[*].name) - source_dest_check = var.source_dest_check - ipv6_address_count = var.ipv6_address_count - ipv6_addresses = var.ipv6_addresses - hibernation = var.hibernation + source_dest_check = var.instance_configuration.source_dest_check + ipv6_address_count = var.instance_configuration.ipv6_address_count + ipv6_addresses = var.instance_configuration.ipv6_addresses + hibernation = var.instance_configuration.hibernation + dynamic "cpu_options" { for_each = length(var.cpu_options) > 0 ? [var.cpu_options] : [] content { @@ -199,7 +200,7 @@ resource "aws_instance" "default" { } dynamic "root_block_device" { - for_each = var.root_block_device + for_each = var.instance_configuration.root_block_device content { delete_on_termination = lookup(root_block_device.value, "delete_on_termination", null) encrypted = true @@ -238,7 +239,7 @@ resource "aws_instance" "default" { } dynamic "ephemeral_block_device" { - for_each = var.ephemeral_block_device + for_each = var.instance_configuration.ephemeral_block_device content { device_name = ephemeral_block_device.value.device_name no_device = lookup(ephemeral_block_device.value, "no_device", null) @@ -372,42 +373,44 @@ resource "aws_route53_record" "default" { ## Below Provides an EC2 Spot Instance Request resource. This allows instances to be requested on the spot market.. ##---------------------------------------------------------------------------------- resource "aws_spot_instance_request" "default" { - count = var.enable && var.spot_instance_enabled ? var.spot_instance_count : 0 - 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 - ami = var.ami == "" ? data.aws_ami.ubuntu.id : var.ami - ebs_optimized = var.ebs_optimized - instance_type = var.instance_type + count = var.enable && var.spot_instance_enabled ? var.spot_instance_count : 0 + spot_price = var.spot_configuration.spot_price + wait_for_fulfillment = var.spot_configuration.wait_for_fulfillment + spot_type = var.spot_configuration.spot_type + launch_group = var.spot_configuration.launch_group + block_duration_minutes = var.spot_configuration.block_duration_minutes + instance_interruption_behavior = var.spot_configuration.instance_interruption_behavior + valid_until = var.spot_configuration.valid_until + valid_from = var.spot_configuration.valid_from + + # Instance configuration + ami = var.instance_configuration.ami == "" ? data.aws_ami.ubuntu.id : var.instance_configuration.ami + ebs_optimized = var.instance_configuration.ebs_optimized + instance_type = var.instance_configuration.instance_type key_name = var.key_name == "" ? join("", aws_key_pair.default[*].key_name) : var.key_name - monitoring = var.monitoring + monitoring = var.instance_configuration.monitoring vpc_security_group_ids = length(var.sg_ids) < 1 ? aws_security_group.default[*].id : var.sg_ids subnet_id = element(distinct(compact(concat(var.subnet_ids))), count.index) - associate_public_ip_address = var.associate_public_ip_address - 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 - 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 - user_data_replace_on_change = var.user_data_replace_on_change - availability_zone = var.availability_zone - get_password_data = var.get_password_data - private_ip = var.private_ip - secondary_private_ips = var.secondary_private_ips + associate_public_ip_address = var.instance_configuration.associate_public_ip_address + disable_api_termination = var.instance_configuration.disable_api_termination + instance_initiated_shutdown_behavior = var.instance_configuration.instance_initiated_shutdown_behavior + placement_group = var.instance_configuration.placement_group + tenancy = var.instance_configuration.tenancy + host_id = var.instance_configuration.host_id + cpu_core_count = var.instance_configuration.cpu_core_count + cpu_threads_per_core = var.instance_configuration.cpu_threads_per_core + user_data = var.instance_configuration.user_data + user_data_base64 = var.instance_configuration.user_data_base64 + user_data_replace_on_change = var.instance_configuration.user_data_replace_on_change + availability_zone = var.instance_configuration.availability_zone + get_password_data = var.instance_configuration.get_password_data + private_ip = var.instance_configuration.private_ip + secondary_private_ips = var.instance_configuration.secondary_private_ips iam_instance_profile = join("", aws_iam_instance_profile.default[*].name) - source_dest_check = var.source_dest_check - ipv6_address_count = var.ipv6_address_count - ipv6_addresses = var.ipv6_addresses - hibernation = var.hibernation + source_dest_check = var.instance_configuration.source_dest_check + ipv6_address_count = var.instance_configuration.ipv6_address_count + ipv6_addresses = var.instance_configuration.ipv6_addresses + hibernation = var.instance_configuration.hibernation dynamic "cpu_options" { for_each = length(var.cpu_options) > 0 ? [var.cpu_options] : [] @@ -433,7 +436,7 @@ resource "aws_spot_instance_request" "default" { } dynamic "root_block_device" { - for_each = var.root_block_device + for_each = var.instance_configuration.root_block_device content { delete_on_termination = lookup(root_block_device.value, "delete_on_termination", null) encrypted = true @@ -472,7 +475,7 @@ resource "aws_spot_instance_request" "default" { } dynamic "ephemeral_block_device" { - for_each = var.ephemeral_block_device + for_each = var.instance_configuration.ephemeral_block_device content { device_name = ephemeral_block_device.value.device_name no_device = lookup(ephemeral_block_device.value, "no_device", null) diff --git a/variables.tf b/variables.tf index 2728408..e723c74 100644 --- a/variables.tf +++ b/variables.tf @@ -56,82 +56,38 @@ variable "enable" { description = "Flag to control module creation." } -variable "ami" { - type = string - default = "" - description = "The AMI to use for the instance." -} - -variable "ebs_optimized" { - type = bool - default = false - description = "If true, the launched EC2 instance will be EBS-optimized." -} - -variable "instance_type" { - type = string - description = "The type of instance to start. Updates to this field will trigger a stop/start of the EC2 instance." -} - -variable "monitoring" { - type = bool - default = false - description = "If true, the launched EC2 instance will have detailed monitoring enabled. (Available since v0.6.0)." -} - -variable "associate_public_ip_address" { - type = bool - default = true - description = "Associate a public IP address with the instance." - sensitive = true -} - -variable "ephemeral_block_device" { - type = list(any) - default = [] - description = "Customize Ephemeral (also known as Instance Store) volumes on the instance." -} - -variable "disable_api_termination" { - type = bool - default = false - description = "If true, enables EC2 Instance Termination Protection." -} - -variable "instance_initiated_shutdown_behavior" { - type = string - default = "stop" - description = "(Optional) 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 instances. See Shutdown Behavior for more information." -} - -variable "placement_group" { - type = string - default = "" - description = "The Placement Group to start the instance in." -} - -variable "tenancy" { - type = string - default = "default" - description = "The tenancy of the instance (if the instance is running in a VPC). An instance with a tenancy of dedicated runs on single-tenant hardware. The host tenancy is not supported for the import-instance command." -} - -variable "root_block_device" { - type = list(any) - default = [] - description = "Customize details about the root block device of the instance. See Block Devices below for details." -} - -variable "user_data" { - type = string - default = "" - description = "(Optional) A string of the desired User Data for the ec2." -} - -variable "user_data_base64" { - description = "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" - type = string - default = null +variable "instance_configuration" { + description = "Configuration options for the EC2 instance" + type = object({ + ami = optional(string, "") + ebs_optimized = optional(bool, false) + instance_type = string + monitoring = optional(bool, false) + associate_public_ip_address = optional(bool, true) + disable_api_termination = optional(bool, false) + instance_initiated_shutdown_behavior = optional(string, "stop") + placement_group = optional(string, "") + tenancy = optional(string, "default") + host_id = optional(string, null) + cpu_core_count = optional(number, null) + cpu_threads_per_core = optional(number, null) + user_data = optional(string, "") + user_data_base64 = optional(string, null) + user_data_replace_on_change = optional(bool, null) + availability_zone = optional(string, null) + get_password_data = optional(bool, null) + private_ip = optional(string, null) + secondary_private_ips = optional(list(string), null) + source_dest_check = optional(bool, true) + ipv6_address_count = optional(number, null) + ipv6_addresses = optional(list(string), null) + hibernation = optional(bool, false) + root_block_device = optional(list(any), []) + ephemeral_block_device = optional(list(any), []) + }) + default = { + instance_type = "t2.micro" # Providing a default instance type + } } variable "assign_eip_address" { @@ -509,52 +465,19 @@ variable "spot_instance_count" { description = "Number of instances to launch." } -variable "spot_price" { - type = string - default = null - description = "The maximum price to request on the spot market. Defaults to on-demand price" -} - -variable "spot_wait_for_fulfillment" { - type = bool - default = false - 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" -} - -variable "spot_type" { - type = string - default = null - description = "If set to one-time, after the instance is terminated, the spot request will be closed. Default `persistent`" -} - -variable "spot_launch_group" { - type = string - default = null - 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_block_duration_minutes" { - type = number - default = null - 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)" -} - -variable "spot_instance_interruption_behavior" { - type = string - default = null - description = "Indicates Spot instance behavior when it is interrupted. Valid values are `terminate`, `stop`, or `hibernate`" -} - -variable "spot_valid_until" { - type = string - default = null - description = "The end date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ)" -} - -variable "spot_valid_from" { - type = string - default = null - description = "The start date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ)" +variable "spot_configuration" { + description = "Configuration options for the EC2 spot instance" + type = object({ + spot_price = optional(string, null) + wait_for_fulfillment = optional(bool, false) + spot_type = optional(string, null) + launch_group = optional(string, null) + block_duration_minutes = optional(number, null) + instance_interruption_behavior = optional(string, null) + valid_until = optional(string, null) + valid_from = optional(string, null) + }) + default = {} } variable "cpu_threads_per_core" {