# Some instance variables
locals {
  ami_selection = "minion" # master, minion, ...
  instance_name = var.instance_name != "" ? var.instance_name : "${ var.prefix }-splunk-sh"
  alb_name = var.alb_name != "" ? var.alb_name : "${ var.prefix }-splunk"
  is_moose = length(regexall("moose", var.prefix)) > 0 ? true : false
  is_monitoring_console = var.alb_name == "splunk-mc" ? true : false
  is_fm_searchhead = var.alb_name == "fm-shared-search" ? true : false
}

# Rather than pass in the aws security group, we just look it up. This will
# probably be useful other places, as well.
data "aws_security_group" "typical-host" {
  name   = "typical-host"
  vpc_id = var.vpc_id
}

# Use the default EBS key
data "aws_kms_key" "ebs-key" {
  key_id = "alias/ebs_root_encrypt_decrypt"
}

resource "aws_network_interface" "instance" {
  subnet_id = var.subnets[0]
  security_groups = [ data.aws_security_group.typical-host.id, aws_security_group.searchhead_security_group.id ]
  description = local.instance_name
  tags = merge(var.standard_tags, var.tags, { Name = local.instance_name })
}

resource "aws_instance" "instance" {
  #availability_zone = var.azs[count.index % 2]
  tenancy = "default"
  ebs_optimized = true
  disable_api_termination = var.instance_termination_protection
  instance_initiated_shutdown_behavior = "stop"
  instance_type = var.instance_type
  key_name = "msoc-build"
  monitoring = false
  iam_instance_profile = "msoc-default-instance-profile"

  ami = local.ami_map[local.ami_selection]
  # We need to ignore ebs_block_device changes, because if the AMI changes, so does the snapshot_id.
  # If they add a feature to block more specific changes (eg `ebs_block_devices[*].snapshot_id`), then
  # that could be removed.
  lifecycle { ignore_changes = [ ami, key_name, user_data, ebs_block_device ] }

  # These device definitions are optional, but added for clarity.
  root_block_device {
    volume_type = "gp2"
    volume_size = var.splunk_volume_sizes["searchhead"]["/"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
  }

  ebs_block_device {
    # /opt/splunk
    # Note: Not in AMI
    device_name = "/dev/xvdf"
    volume_size = var.splunk_volume_sizes["searchhead"]["/opt/splunk"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
  }

  ebs_block_device {
    # swap
    device_name = "/dev/xvdm"
    volume_size = var.splunk_volume_sizes["searchhead"]["swap"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
    # Snapshot IDs need to be grabbed from the ami, or it will replace every time. It's ugly.
    # This may prompt replacement when the AMI is updated.
    # See:
    #   https://github.com/hashicorp/terraform/issues/19958
    #   https://github.com/terraform-providers/terraform-provider-aws/issues/13118
    snapshot_id = local.block_device_mappings[local.ami_selection]["/dev/xvdm"].ebs.snapshot_id
  }
  ebs_block_device {
    # /home
    device_name = "/dev/xvdn"
    volume_size = var.splunk_volume_sizes["searchhead"]["/home"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
    snapshot_id = local.block_device_mappings[local.ami_selection]["/dev/xvdn"].ebs.snapshot_id

  }
  ebs_block_device {
    # /var
    device_name = "/dev/xvdo"
    volume_size = var.splunk_volume_sizes["searchhead"]["/var"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
    snapshot_id = local.block_device_mappings[local.ami_selection]["/dev/xvdo"].ebs.snapshot_id
  }
  ebs_block_device {
    # /var/tmp
    device_name = "/dev/xvdp"
    volume_size = var.splunk_volume_sizes["searchhead"]["/var/tmp"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
    snapshot_id = local.block_device_mappings[local.ami_selection]["/dev/xvdp"].ebs.snapshot_id
  }
  ebs_block_device {
    # /var/log
    device_name = "/dev/xvdq"
    volume_size = var.splunk_volume_sizes["searchhead"]["/var/log"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
    snapshot_id = local.block_device_mappings[local.ami_selection]["/dev/xvdq"].ebs.snapshot_id
  }
  ebs_block_device {
    # /var/log/audit
    device_name = "/dev/xvdr"
    volume_size = var.splunk_volume_sizes["searchhead"]["/var/log/audit"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
    snapshot_id = local.block_device_mappings[local.ami_selection]["/dev/xvdr"].ebs.snapshot_id
  }
  ebs_block_device {
    # /tmp
    device_name = "/dev/xvds"
    volume_size = var.splunk_volume_sizes["searchhead"]["/tmp"]
    delete_on_termination = true
    encrypted = true
    kms_key_id = data.aws_kms_key.ebs-key.arn
    snapshot_id = local.block_device_mappings[local.ami_selection]["/dev/xvds"].ebs.snapshot_id
  }

  network_interface {
    device_index = 0
    network_interface_id = aws_network_interface.instance.id
  }

  user_data = data.template_cloudinit_config.cloud-init.rendered
  tags = merge( var.standard_tags, var.tags, { Name = local.instance_name })
  volume_tags = merge( var.standard_tags, var.tags, { Name = local.instance_name })
}

module "private_dns_record" {
  source = "../../../submodules/dns/private_A_record"

  name = local.instance_name
  ip_addresses = [ aws_instance.instance.private_ip ]
  dns_info = var.dns_info
  reverse_enabled = var.reverse_enabled

  providers = {
    aws.c2 = aws.c2
  }
}

data "template_file" "cloud-init" {
  # Should these be in a common directory? I suspect they'd be reusable
  template = file("${path.module}/cloud-init/cloud-init.tpl")

  vars = {
    hostname = local.instance_name
    fqdn = "${local.instance_name}.${var.dns_info["private"]["zone"]}"
    splunk_prefix = var.prefix
    environment = var.environment
    salt_master  = var.salt_master
    proxy = var.proxy
    aws_partition = var.aws_partition
    aws_partition_alias = var.aws_partition_alias
    aws_region = var.aws_region
  }
}

# Render a multi-part cloud-init config making use of the part
# above, and other source files
data "template_cloudinit_config" "cloud-init" {
  gzip          = true
  base64_encode = true

  # Main cloud-config configuration file.
  part {
    filename     = "init.cfg"
    content_type = "text/cloud-config"
    content      = data.template_file.cloud-init.rendered
  }

  # mount /dev/xvdf at /opt/splunk
  part {
    content_type = "text/cloud-boothook"
    content      = file("${path.module}/cloud-init/opt_splunk.boothook")
  }
}

## Searchhead
#
# Summary:
#   Ingress:
#     tcp/8000      - Splunk Web                 - vpc-access, legacy openvpn, legacy bastion, Phantom
#     tcp/8000      - Splunk Web                 - Entire VPC + var.splunk_legacy_cidr
#     tcp/8089      - Splunk API                 - vpc-access, legacy openvpn, legacy bastion, Phantom
#     tcp/8089      - Splunk API + IDX Discovery - Entire VPC + var.splunk_legacy_cidr 
#     tcp/9997-9998 - Splunk Data                - Entire VPC + var.splunk_legacy_cidr
#
#   Ingress:
#     tcp/8000      - Splunk Web                 - vpc-system-services (for salt inventory (moose only))
#     tcp/8089      - Splunk Web                 - vpc-system-services (for salt inventory and portal lambda)
#
#   Egress:
#     tcp/8089      - Splunk API + IDX Discovery - Entire VPC + var.splunk_legacy_cidr
resource "aws_security_group" "searchhead_security_group" {
  name = "${ var.prefix }_searchhead_security_group"
  description = "Security Group for Splunk Searchhead Instance(s)"
  vpc_id = var.vpc_id
  tags = merge(var.standard_tags, var.tags)
}

# Ingress
resource "aws_security_group_rule" "splunk-web-in" {
  description       = "Web access"
  type              = "ingress"
  from_port         = 8000
  to_port           = 8000
  protocol          = "tcp"
  cidr_blocks       = toset(concat(var.cidr_map["vpc-access"], 
                                   var.cidr_map["vpc-private-services"], 
                                   var.splunk_legacy_cidr, 
                                   [ var.vpc_cidr ], 
                                   local.is_moose ? var.cidr_map["vpc-system-services"] : [], # for salt inventory
                      ))
  security_group_id = aws_security_group.searchhead_security_group.id
}

resource "aws_security_group_rule" "splunk-api-in" {
  description       = "Splunk API"
  type              = "ingress"
  from_port         = 8089
  to_port           = 8089
  protocol          = "tcp"
  cidr_blocks       = toset(concat(var.cidr_map["vpc-access"], 
                                   var.cidr_map["vpc-private-services"], 
                                   var.cidr_map["vpc-splunk"], # MC
                                   var.splunk_legacy_cidr, 
                                   [ var.vpc_cidr ], 
                                   var.cidr_map["vpc-system-services"], # for salt inventory and Portal lambda
                      ))
  security_group_id = aws_security_group.searchhead_security_group.id
}

# Egress
resource "aws_security_group_rule" "ssh-out" {
  count = length(var.splunk_legacy_cidr) > 0 ? 1 : 0
  description       = "SSH to legacy splunk"
  type              = "egress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = var.splunk_legacy_cidr
  security_group_id = aws_security_group.searchhead_security_group.id
}

resource "aws_security_group_rule" "splunk-api-out" {
  description       = "Splunk API Outbound to talk to indexers"
  type              = "egress"
  from_port         = 8089
  to_port           = 8089
  protocol          = "tcp"
  cidr_blocks       = toset(concat([ var.vpc_cidr ], var.splunk_legacy_cidr))
  security_group_id = aws_security_group.searchhead_security_group.id
}

resource "aws_security_group_rule" "splunk-api-out-to-all" {
  count             = local.is_monitoring_console || local.is_fm_searchhead  ? 1 : 0
  description       = "Splunk API Outbound to talk to Other Segments"
  type              = "egress"
  from_port         = 8089
  to_port           = 8089
  protocol          = "tcp"
  cidr_blocks       = [ "10.0.0.0/8" ]
  security_group_id = aws_security_group.searchhead_security_group.id
}

resource "aws_security_group_rule" "splunk-data-out" {
  description       = "Splunk Data Outbound to talk to own indexers"
  type              = "egress"
  from_port         = 9997
  to_port           = 9998
  protocol          = "tcp"
  cidr_blocks       = toset(concat([ var.vpc_cidr ], var.splunk_legacy_cidr))
  security_group_id = aws_security_group.searchhead_security_group.id
}
