provider "aws" {
  region = "us-east-1"

  default_tags {
    tags = module.default_tags.tags
  }
}

terraform {
  backend "s3" {
    bucket  = "dev-orcd-terraform-state"
    key     = "dev/terraform-chef-bootstrap/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

module "default_tags" {
  source             = "git@github.com:theorchard/terraform-default-tags.git//?ref=2.0.0"
  environment        = var.environment
  application_family = var.application_family
  service_name       = var.service_name
  team_name          = var.team_name
}

data "aws_vpc" "main" {
  tags = {
    Name = "dev"
  }
}

data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.main.id]
  }

  tags = {
    Name = "private0*"
  }
}

data "aws_ami" "ami" {
  for_each = var.platforms_to_test

  most_recent = true

  owners = [each.value.ami.owner]

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  dynamic "filter" {
    for_each = each.value.ami.name == null ? [] : [1]

    content {
      name   = "name"
      values = [each.value.ami.name]
    }
  }

  dynamic "filter" {
    for_each = each.value.ami.product-code == null ? [] : [1]

    content {
      name   = "product-code"
      values = [each.value.ami.product-code]
    }
  }
}

resource "aws_security_group" "instance_security_group" {
  name        = "${var.environment}-${var.service_name}-instance-security-group"
  description = "Instance security group for ${var.environment}-${var.service_name}"
  vpc_id      = data.aws_vpc.main.id

  tags = {
    environment    = var.environment
    service_name   = var.service_name
    terraformed    = true
    eiso-exception = "aws.08.30"
  }
}

data "aws_ec2_managed_prefix_list" "vpn_sme_internal_primary" {
  name = "vpn-sme-internal-primary"
}

resource "aws_security_group_rule" "allow_ssh" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "TCP"
  prefix_list_ids   = [data.aws_ec2_managed_prefix_list.vpn_sme_internal_primary.id]
  security_group_id = aws_security_group.instance_security_group.id
}

resource "aws_security_group_rule" "allow_instance_egress" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.instance_security_group.id
}

data "aws_iam_policy_document" "assume_instance_role" {
  statement {
    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "Service"
      identifiers = [
        "ec2.amazonaws.com",
      ]
    }
  }
}

resource "aws_iam_role" "instance_iam_role" {
  name               = "${var.environment}-${var.service_name}-asg-role"
  assume_role_policy = data.aws_iam_policy_document.assume_instance_role.json
}

resource "aws_iam_instance_profile" "iam_instance_profile" {
  name = "${var.environment}-${var.service_name}-asg-instance-profile"
  role = aws_iam_role.instance_iam_role.name
}

resource "aws_launch_template" "launch_template" {
  for_each = var.platforms_to_test

  description             = "${var.environment}-${var.service_name}-${each.key}"
  disable_api_stop        = false
  disable_api_termination = false
  ebs_optimized           = true
  image_id                = data.aws_ami.ami[each.key].id
  instance_type           = each.value.instance_type
  key_name                = var.ssh_keypair_name
  name                    = "${var.environment}-${var.service_name}-${each.key}"
  user_data               = base64encode(module.chef_bootstrap.user_data_output)
  vpc_security_group_ids  = [aws_security_group.instance_security_group.id]

  block_device_mappings {
    device_name = data.aws_ami.ami[each.key].root_device_name
    ebs {
      volume_size = 10
    }
  }

  iam_instance_profile {
    name = aws_iam_instance_profile.iam_instance_profile.name
  }

  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required"  # Enforce IMDSv2
    http_put_response_hop_limit = 1
    instance_metadata_tags      = "disabled"
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "autoscaling_group" {
  for_each = var.platforms_to_test

  name                      = "${var.environment}-${var.service_name}-${each.key}-autoscaling-group"
  min_size                  = 1
  max_size                  = 1
  desired_capacity          = 1
  default_cooldown          = 300
  health_check_type         = "EC2"
  health_check_grace_period = 1800
  wait_for_capacity_timeout = "10m"
  vpc_zone_identifier       = data.aws_subnets.private.ids
  enabled_metrics           = []

  launch_template {
    id      = aws_launch_template.launch_template[each.key].id
    version = "$Latest"
  }

  tag {
    key                 = "Name"
    value               = "${var.environment}-${var.service_name}-${each.key}"
    propagate_at_launch = true
  }
  tag {
    key                 = "environment"
    value               = var.environment
    propagate_at_launch = true
  }
  tag {
    key                 = "service_name"
    value               = var.service_name
    propagate_at_launch = true
  }

  lifecycle {
    create_before_destroy = true
  }
}

module "chef_bootstrap" {
  source = "../"

  chef_role         = "qa_base_linux"
  aws_iam_role_id   = aws_iam_role.instance_iam_role.name
  aws_instance_name = "${var.environment}-${var.service_name}"

  node_attributes = {
    datadog = {
      tags = {
        environment  = "dev"
        service_name = "terraform-chef-bootstrap-test"
      }
    }
  }
}

#============================================#
#    Block Device Configuration Tests        #
#============================================#

# AMI lookup for block device tests
data "aws_ami" "block_device_test_ami" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  most_recent = true
  owners      = [each.value.ami.owner]

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  filter {
    name   = "name"
    values = [each.value.ami.name]
  }
}

# Module: EBS data volume only (ext4)
module "chef_bootstrap_ebs_only" {
  count  = var.block_device_tests_enabled ? 1 : 0
  source = "../"

  chef_role         = "qa_base_linux"
  aws_iam_role_id   = aws_iam_role.instance_iam_role.name
  aws_instance_name = "${var.environment}-${var.service_name}-ebs-only"

  ebs_data_mount_point         = "/data"
  block_device_filesystem_type = "ext4"

  node_attributes = {
    datadog = {
      tags = {
        environment  = "dev"
        service_name = "terraform-chef-bootstrap-test-ebs-only"
      }
    }
  }
}

# Module: Instance store only (ext4)
module "chef_bootstrap_instance_store" {
  count  = var.block_device_tests_enabled ? 1 : 0
  source = "../"

  chef_role         = "qa_base_linux"
  aws_iam_role_id   = aws_iam_role.instance_iam_role.name
  aws_instance_name = "${var.environment}-${var.service_name}-instance-store"

  instance_store_mount_point   = "/scratch"
  block_device_filesystem_type = "ext4"

  node_attributes = {
    datadog = {
      tags = {
        environment  = "dev"
        service_name = "terraform-chef-bootstrap-test-instance-store"
      }
    }
  }
}

# Module: Both EBS and instance store (ext4)
module "chef_bootstrap_both_volumes" {
  count  = var.block_device_tests_enabled ? 1 : 0
  source = "../"

  chef_role         = "qa_base_linux"
  aws_iam_role_id   = aws_iam_role.instance_iam_role.name
  aws_instance_name = "${var.environment}-${var.service_name}-both-volumes"

  ebs_data_mount_point         = "/data"
  instance_store_mount_point   = "/scratch"
  block_device_filesystem_type = "ext4"

  node_attributes = {
    datadog = {
      tags = {
        environment  = "dev"
        service_name = "terraform-chef-bootstrap-test-both-volumes"
      }
    }
  }
}

# Module: XFS filesystem test
module "chef_bootstrap_xfs" {
  count  = var.block_device_tests_enabled ? 1 : 0
  source = "../"

  chef_role         = "qa_base_linux"
  aws_iam_role_id   = aws_iam_role.instance_iam_role.name
  aws_instance_name = "${var.environment}-${var.service_name}-xfs"

  ebs_data_mount_point         = "/data"
  block_device_filesystem_type = "xfs"

  node_attributes = {
    datadog = {
      tags = {
        environment  = "dev"
        service_name = "terraform-chef-bootstrap-test-xfs"
      }
    }
  }
}

# Launch template: EBS data volume only
resource "aws_launch_template" "ebs_only" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  description             = "${var.environment}-${var.service_name}-ebs-only-${each.key}"
  disable_api_stop        = false
  disable_api_termination = false
  ebs_optimized           = true
  image_id                = data.aws_ami.block_device_test_ami[each.key].id
  instance_type           = each.value.instance_type_ebs_only
  key_name                = var.ssh_keypair_name
  name                    = "${var.environment}-${var.service_name}-ebs-only-${each.key}"
  user_data               = base64encode(module.chef_bootstrap_ebs_only[0].user_data_output)
  vpc_security_group_ids  = [aws_security_group.instance_security_group.id]

  # Root volume
  block_device_mappings {
    device_name = data.aws_ami.block_device_test_ami[each.key].root_device_name
    ebs {
      volume_size = 10
    }
  }

  # Additional EBS data volume
  block_device_mappings {
    device_name = "/dev/sdf"
    ebs {
      volume_size           = 20
      volume_type           = "gp3"
      delete_on_termination = true
      encrypted             = true
    }
  }

  iam_instance_profile {
    name = aws_iam_instance_profile.iam_instance_profile.name
  }

  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
    instance_metadata_tags      = "disabled"
  }

  lifecycle {
    create_before_destroy = true
  }
}

# Launch template: Instance store only (requires instance store capable instance type)
resource "aws_launch_template" "instance_store_only" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  description             = "${var.environment}-${var.service_name}-instance-store-${each.key}"
  disable_api_stop        = false
  disable_api_termination = false
  ebs_optimized           = true
  image_id                = data.aws_ami.block_device_test_ami[each.key].id
  instance_type           = each.value.instance_type_instance_store
  key_name                = var.ssh_keypair_name
  name                    = "${var.environment}-${var.service_name}-instance-store-${each.key}"
  user_data               = base64encode(module.chef_bootstrap_instance_store[0].user_data_output)
  vpc_security_group_ids  = [aws_security_group.instance_security_group.id]

  block_device_mappings {
    device_name = data.aws_ami.block_device_test_ami[each.key].root_device_name
    ebs {
      volume_size = 10
    }
  }

  iam_instance_profile {
    name = aws_iam_instance_profile.iam_instance_profile.name
  }

  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
    instance_metadata_tags      = "disabled"
  }

  lifecycle {
    create_before_destroy = true
  }
}

# Launch template: Both EBS and instance store
resource "aws_launch_template" "both_volumes" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  description             = "${var.environment}-${var.service_name}-both-volumes-${each.key}"
  disable_api_stop        = false
  disable_api_termination = false
  ebs_optimized           = true
  image_id                = data.aws_ami.block_device_test_ami[each.key].id
  instance_type           = each.value.instance_type_instance_store
  key_name                = var.ssh_keypair_name
  name                    = "${var.environment}-${var.service_name}-both-volumes-${each.key}"
  user_data               = base64encode(module.chef_bootstrap_both_volumes[0].user_data_output)
  vpc_security_group_ids  = [aws_security_group.instance_security_group.id]

  # Root volume
  block_device_mappings {
    device_name = data.aws_ami.block_device_test_ami[each.key].root_device_name
    ebs {
      volume_size = 10
    }
  }

  # Additional EBS data volume
  block_device_mappings {
    device_name = "/dev/sdf"
    ebs {
      volume_size           = 20
      volume_type           = "gp3"
      delete_on_termination = true
      encrypted             = true
    }
  }

  iam_instance_profile {
    name = aws_iam_instance_profile.iam_instance_profile.name
  }

  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
    instance_metadata_tags      = "disabled"
  }

  lifecycle {
    create_before_destroy = true
  }
}

# Launch template: XFS filesystem
resource "aws_launch_template" "xfs_test" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  description             = "${var.environment}-${var.service_name}-xfs-${each.key}"
  disable_api_stop        = false
  disable_api_termination = false
  ebs_optimized           = true
  image_id                = data.aws_ami.block_device_test_ami[each.key].id
  instance_type           = each.value.instance_type_ebs_only
  key_name                = var.ssh_keypair_name
  name                    = "${var.environment}-${var.service_name}-xfs-${each.key}"
  user_data               = base64encode(module.chef_bootstrap_xfs[0].user_data_output)
  vpc_security_group_ids  = [aws_security_group.instance_security_group.id]

  # Root volume
  block_device_mappings {
    device_name = data.aws_ami.block_device_test_ami[each.key].root_device_name
    ebs {
      volume_size = 10
    }
  }

  # Additional EBS data volume
  block_device_mappings {
    device_name = "/dev/sdf"
    ebs {
      volume_size           = 20
      volume_type           = "gp3"
      delete_on_termination = true
      encrypted             = true
    }
  }

  iam_instance_profile {
    name = aws_iam_instance_profile.iam_instance_profile.name
  }

  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
    instance_metadata_tags      = "disabled"
  }

  lifecycle {
    create_before_destroy = true
  }
}

# ASG: EBS only test
resource "aws_autoscaling_group" "ebs_only" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  name                      = "${var.environment}-${var.service_name}-ebs-only-${each.key}-asg"
  min_size                  = 1
  max_size                  = 1
  desired_capacity          = 1
  default_cooldown          = 300
  health_check_type         = "EC2"
  health_check_grace_period = 1800
  wait_for_capacity_timeout = "10m"
  vpc_zone_identifier       = data.aws_subnets.private.ids
  enabled_metrics           = []

  launch_template {
    id      = aws_launch_template.ebs_only[each.key].id
    version = "$Latest"
  }

  tag {
    key                 = "Name"
    value               = "${var.environment}-${var.service_name}-ebs-only-${each.key}"
    propagate_at_launch = true
  }
  tag {
    key                 = "environment"
    value               = var.environment
    propagate_at_launch = true
  }
  tag {
    key                 = "service_name"
    value               = var.service_name
    propagate_at_launch = true
  }
  tag {
    key                 = "test_type"
    value               = "ebs-only"
    propagate_at_launch = true
  }

  lifecycle {
    create_before_destroy = true
  }
}

# ASG: Instance store only test
resource "aws_autoscaling_group" "instance_store_only" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  name                      = "${var.environment}-${var.service_name}-instance-store-${each.key}-asg"
  min_size                  = 1
  max_size                  = 1
  desired_capacity          = 1
  default_cooldown          = 300
  health_check_type         = "EC2"
  health_check_grace_period = 1800
  wait_for_capacity_timeout = "10m"
  vpc_zone_identifier       = data.aws_subnets.private.ids
  enabled_metrics           = []

  launch_template {
    id      = aws_launch_template.instance_store_only[each.key].id
    version = "$Latest"
  }

  tag {
    key                 = "Name"
    value               = "${var.environment}-${var.service_name}-instance-store-${each.key}"
    propagate_at_launch = true
  }
  tag {
    key                 = "environment"
    value               = var.environment
    propagate_at_launch = true
  }
  tag {
    key                 = "service_name"
    value               = var.service_name
    propagate_at_launch = true
  }
  tag {
    key                 = "test_type"
    value               = "instance-store"
    propagate_at_launch = true
  }

  lifecycle {
    create_before_destroy = true
  }
}

# ASG: Both volumes test
resource "aws_autoscaling_group" "both_volumes" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  name                      = "${var.environment}-${var.service_name}-both-volumes-${each.key}-asg"
  min_size                  = 1
  max_size                  = 1
  desired_capacity          = 1
  default_cooldown          = 300
  health_check_type         = "EC2"
  health_check_grace_period = 1800
  wait_for_capacity_timeout = "10m"
  vpc_zone_identifier       = data.aws_subnets.private.ids
  enabled_metrics           = []

  launch_template {
    id      = aws_launch_template.both_volumes[each.key].id
    version = "$Latest"
  }

  tag {
    key                 = "Name"
    value               = "${var.environment}-${var.service_name}-both-volumes-${each.key}"
    propagate_at_launch = true
  }
  tag {
    key                 = "environment"
    value               = var.environment
    propagate_at_launch = true
  }
  tag {
    key                 = "service_name"
    value               = var.service_name
    propagate_at_launch = true
  }
  tag {
    key                 = "test_type"
    value               = "both-volumes"
    propagate_at_launch = true
  }

  lifecycle {
    create_before_destroy = true
  }
}

# ASG: XFS test
resource "aws_autoscaling_group" "xfs_test" {
  for_each = var.block_device_tests_enabled ? var.block_device_test_platforms : {}

  name                      = "${var.environment}-${var.service_name}-xfs-${each.key}-asg"
  min_size                  = 1
  max_size                  = 1
  desired_capacity          = 1
  default_cooldown          = 300
  health_check_type         = "EC2"
  health_check_grace_period = 1800
  wait_for_capacity_timeout = "10m"
  vpc_zone_identifier       = data.aws_subnets.private.ids
  enabled_metrics           = []

  launch_template {
    id      = aws_launch_template.xfs_test[each.key].id
    version = "$Latest"
  }

  tag {
    key                 = "Name"
    value               = "${var.environment}-${var.service_name}-xfs-${each.key}"
    propagate_at_launch = true
  }
  tag {
    key                 = "environment"
    value               = var.environment
    propagate_at_launch = true
  }
  tag {
    key                 = "service_name"
    value               = var.service_name
    propagate_at_launch = true
  }
  tag {
    key                 = "test_type"
    value               = "xfs"
    propagate_at_launch = true
  }

  lifecycle {
    create_before_destroy = true
  }
}
