# Specify the provider and access details
provider "aws" {
  region = var.aws_region
}

# Existing vpc
data "aws_vpc" "this" {
  id = var.vpc_id
}

resource "aws_subnet" "private_subnet" {
  vpc_id            = var.vpc_id
  count             = 2
  cidr_block        = cidrsubnet(var.vpc_private_subnet_cidr, 2, count.index)
  availability_zone = element(split(",", var.aws_azs[var.aws_region]), count.index)

  tags = {
    Name        = "${var.environment}-${var.aws_stack_name}-subnet"
    terraformed = true
  }
}

resource "aws_route_table_association" "route_table_association" {
  count          = length(aws_subnet.private_subnet.*.id)
  subnet_id      = element(aws_subnet.private_subnet.*.id, count.index)
  route_table_id = var.vpc_route_table
}

# Info about AMI
data "aws_ami" "centos" {
  # as per https://wiki.centos.org/Cloud/AWS "Finding AMI ids"
  most_recent = true
  owners      = ["679593333241"]
  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
  filter {
    name   = "product-code"
    values = ["aw0evgkw8e5c1q413zgy5pjce"]
  }
}

data "aws_s3_bucket" "s3_bucket" {
  bucket = var.s3_bucket
}

data "aws_caller_identity" "current" {
}

data "aws_iam_policy_document" "s3_access_policy_doc" {
  statement {
    effect = "Allow"

    actions = [
      "s3:GetObject",
      "s3:ListBucket",
    ]

    resources = [
      "arn:aws:s3:::${data.aws_s3_bucket.s3_bucket.id}/ciscat",
      "arn:aws:s3:::${data.aws_s3_bucket.s3_bucket.id}/ciscat/*",
    ]
  }
}

resource "aws_iam_role" "s3_access_role" {
  name               = "S3-${var.environment}-${var.aws_stack_name}-RO"
  assume_role_policy = data.aws_iam_policy_document.instance-assume-role-policy.json
}

# IAM policy document for ec2 instance's role within ASG
data "aws_iam_policy_document" "instance-assume-role-policy" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

resource "aws_iam_role_policy" "s3_access_policy" {
  name   = "${var.environment}_${var.aws_stack_name}_s3_RO"
  role   = aws_iam_role.s3_access_role.id
  policy = data.aws_iam_policy_document.s3_access_policy_doc.json
}

# Security group to access the instances over SSH and HTTP
resource "aws_security_group" "asg-sg" {
  name        = "${var.environment}-${var.aws_stack_name}-sg"
  description = "Access the instances over SSH and HTTP"
  vpc_id      = var.vpc_id

  # SSH access from the VPC
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = [data.aws_vpc.this.cidr_block]
  }

  # HTTP access from ELB security group
  ingress {
    from_port       = var.service_port
    to_port         = var.service_port
    protocol        = "tcp"
    security_groups = [aws_security_group.elb-sg.id]
  }

  # outbound internet access
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    terraformed = true
  }
}

# A security group for the LB so it's accessible via the web
resource "aws_security_group" "elb-sg" {
  name        = "${var.environment}-${var.aws_stack_name}-lb"
  description = "Load Balancer security group"
  vpc_id      = var.vpc_id

  # HTTPS access
  ingress {
    from_port = 443
    to_port   = 443
    protocol  = "tcp"
    cidr_blocks = concat(
      lookup(var.https_listener_allow_cidr_blocks, var.environment, var.https_listener_allow_cidr_blocks["dev"]),
      [data.aws_vpc.this.cidr_block],
    )
  }

  # HTTP outbound rule within VPC
  egress {
    from_port   = var.service_port
    to_port     = var.service_port
    protocol    = "tcp"
    cidr_blocks = [data.aws_vpc.this.cidr_block]
  }

  tags = {
    terraformed = true
  }
}

# The ALB for ciscat-dashboard instances
resource "aws_alb_target_group" "default" {
  name     = "${var.environment}-${var.aws_stack_name}"
  port     = var.service_port
  protocol = "HTTP"
  vpc_id   = var.vpc_id

  health_check {
    path     = var.health_check_path
    protocol = "HTTP"
    matcher  = "301"
  }

  tags = {
    Environment = var.environment
    terraformed = true
  }
}

resource "aws_alb" "alb" {
  name            = "${var.environment}-${var.aws_stack_name}"
  internal        = true
  idle_timeout    = "300"
  subnets         = aws_subnet.private_subnet.*.id
  security_groups = [aws_security_group.elb-sg.id]

  tags = {
    Environment = var.environment
  }
}

resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_alb.alb.id
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS-1-2-2017-01"
  certificate_arn   = var.ssl_certificate_arn

  default_action {
    target_group_arn = aws_alb_target_group.default.id
    type             = "forward"
  }
}

# Route 53 record
resource "aws_route53_record" "route53-record" {
  name    = var.dns_name
  zone_id = var.aws_route53_params["zone_id"]
  type    = var.aws_route53_params["type"]
  ttl     = var.aws_route53_params["ttl"]
  records = [aws_alb.alb.dns_name]
}

# Launch configuration
resource "aws_launch_configuration" "launch-config" {
  name_prefix                 = "${var.environment}-${var.aws_stack_name}"
  image_id                    = data.aws_ami.centos.id
  instance_type               = var.aws_instance_type
  associate_public_ip_address = false
  iam_instance_profile        = aws_iam_instance_profile.iam-instance-profile.name

  root_block_device {
    volume_type           = var.aws_volume_type
    volume_size           = var.aws_volume_size
    delete_on_termination = true
  }

  security_groups = [aws_security_group.asg-sg.id]
  key_name        = var.aws_key_name
  user_data       = var.user_data

  lifecycle {
    create_before_destroy = true
  }
}

# Auto scaling group
resource "aws_autoscaling_group" "asg" {
  name                      = "${var.environment}-${var.aws_stack_name}"
  max_size                  = var.asg_max_size
  min_size                  = var.asg_min_size
  desired_capacity          = var.asg_desired_capacity
  health_check_type         = "EC2"
  health_check_grace_period = 900
  launch_configuration      = aws_launch_configuration.launch-config.name

  vpc_zone_identifier = aws_subnet.private_subnet.*.id
  target_group_arns   = [aws_alb_target_group.default.arn]

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

  lifecycle {
    create_before_destroy = true
  }
}

# IAM instance profile
resource "aws_iam_instance_profile" "iam-instance-profile" {
  name = "${var.environment}-${var.aws_stack_name}"
  role = aws_iam_role.s3_access_role.name
}

# Stack name variable to use in other terraform modules
output "aws_stack_name_output" {
  value = "${var.environment}-${var.aws_stack_name}"
}

# ASG arn variable to use in other terraform modules
output "aws_asg_name_output" {
  value = aws_autoscaling_group.asg.name
}

# SG variable for RDS module
output "aws_security_group_id" {
  value = aws_security_group.asg-sg.id
}

# IAM role id
output "iam_role_id" {
  value = aws_iam_role.s3_access_role.id
}

# VPC Private subnet ids
output "vpc_private_subnet_ids" {
  value = aws_subnet.private_subnet.*.id
}

