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

# Getting AMI id
data "aws_ami" "centos" {
  most_recent = true
  owners = [
    "679593333241",
  ]
  filter {
    name = "virtualization-type"
    values = [
      "hvm",]
  }
  filter {
    name = "product-code"
    values = [
      "cvugziknvmxgqna9noibqnnsy",
    ]
  }

  filter {
    name   = "architecture"
    values = [
      "x86_64",
    ]
  }
}

# Getting SG for SSH access from VPN
data "aws_security_group" "aws_sg" {
  filter {
    name = "group-name"
    values = [
      var.vpc_ssh_group,
    ]
  }
}

# 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"]
    }
  }
}

# Policy document for IAM policy
data "aws_iam_policy_document" "iam_policy_document_ecr" {
  statement {
    actions = [
      "ecr:GetAuthorizationToken",
    ]
    resources = [
      "*",
    ]
  }
}

data "aws_iam_policy_document" "ecr_policy_document" {
  statement {
    sid = var.aws_stack_name
    actions = [
      "ecr:GetDownloadUrlForLayer",
      "ecr:BatchGetImage",
      "ecr:BatchCheckLayerAvailability",
    ]
    principals {
      identifiers = [
        aws_iam_role.iam-role.arn,
      ]
      type = "AWS"
    }
  }
}

# User data for jenkins slave
data "template_file" "jenkins_slave_user_data" {
  template = file("${path.module}/jenkins_slave_user_data.sh.tpl")

  vars = {
    aws_region         = "us-east-1"
    jenkins_master_url = var.jenkins_master_url
    aws_stack_name     = var.aws_stack_name
    labels             = format("%s %s", join(" ", var.slave_labels), var.aws_stack_name)
  }
}

data "template_file" "additional_mount" {
  template = file("${path.module}/mounts.sh.tpl")

  vars = {
    mount_device = var.additional_mount["device"]
    mount_path   = var.additional_mount["path"]
  }
}

# IAM role
resource "aws_iam_role" "iam-role" {
  name               = var.aws_stack_name
  assume_role_policy = data.aws_iam_policy_document.instance-assume-role-policy.json
}

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

resource "aws_iam_policy" "iam_policy_ecr" {
  name   = "ECR-${var.aws_stack_name}-getAuthToken"
  policy = data.aws_iam_policy_document.iam_policy_document_ecr.json
}

resource "aws_iam_policy_attachment" "iam_policy_ecr_attachment" {
  name = "${var.aws_stack_name}-ecr-get-auth-token"
  roles = [
    aws_iam_role.iam-role.id,
  ]
  policy_arn = aws_iam_policy.iam_policy_ecr.arn
}

resource "aws_ecr_repository_policy" "ecr_policy" {
  count      = length(var.ecr_ro_repositories)
  repository = element(var.ecr_ro_repositories, count.index)

  policy = data.aws_iam_policy_document.ecr_policy_document.json
}

# Launch configuration
resource "aws_launch_configuration" "launch-config" {
  name_prefix                 = "${var.aws_stack_name}-lc-"
  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           = "standard"
    volume_size           = var.aws_volume_size
    delete_on_termination = true
  }

  ebs_block_device {
    device_name           = var.additional_mount["device"]
    volume_size           = var.additional_mount["size"]
    delete_on_termination = true
  }

  security_groups = [
    var.aws_cluster_sg,
    data.aws_security_group.aws_sg.id,
  ]
  key_name  = var.aws_key_name
  user_data = "${data.template_file.additional_mount.rendered}\n${var.user_data}\n${data.template_file.jenkins_slave_user_data.rendered}"

  lifecycle {
    create_before_destroy = true
  }
}

# Auto scaling group
resource "aws_autoscaling_group" "asg" {
  name                      = var.aws_stack_name
  max_size                  = var.aws_asg_max_size
  min_size                  = var.aws_asg_min_size
  desired_capacity          = var.aws_asg_desired_capacity
  health_check_type         = "EC2"
  health_check_grace_period = 900
  launch_configuration      = aws_launch_configuration.launch-config.name

  vpc_zone_identifier = var.vpc_private_subnet_ids

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

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_policy" "asg_policy_out" {
  name                   = "${var.aws_stack_name}-out"
  scaling_adjustment     = 1
  adjustment_type        = "ChangeInCapacity"
  cooldown               = 300
  autoscaling_group_name = aws_autoscaling_group.asg.name
}

resource "aws_cloudwatch_metric_alarm" "scale_out" {
  alarm_name          = "${var.aws_stack_name}-scale-out"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "4"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/EC2"
  period              = "60"
  statistic           = "Average"
  threshold           = "80"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.asg.name
  }

  alarm_description = "This metric monitors ec2 cpu utilization"
  alarm_actions     = [aws_autoscaling_policy.asg_policy_out.arn]
}

resource "aws_autoscaling_policy" "asg_policy_in" {
  name                   = "${var.aws_stack_name}-in"
  scaling_adjustment     = -1
  adjustment_type        = "ChangeInCapacity"
  cooldown               = 300
  autoscaling_group_name = aws_autoscaling_group.asg.name
}

resource "aws_cloudwatch_metric_alarm" "scale_in" {
  alarm_name          = "${var.aws_stack_name}-scale-in"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "2"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/EC2"
  period              = "120"
  statistic           = "Average"
  threshold           = "50"

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.asg.name
  }

  alarm_description = "This metric monitors ec2 cpu utilization"
  ok_actions        = [aws_autoscaling_policy.asg_policy_in.arn]
}

output "aws_asg_name_output" {
  value = aws_autoscaling_group.asg.name
}

# IAM role variable to use in other terraform modules
output "aws_iam_role_id_output" {
  value = aws_iam_role.iam-role.id
}

