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
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = module.default_tags.tags
  }
}

provider "aws" {
  region  = var.aws_region
  alias   = "networking"
  profile = "networking"

  default_tags {
    tags = module.default_tags.tags
  }
}

terraform {
  backend "s3" {
    bucket  = "shared-orcd-terraform-state"
    key     = "prod/jenkins/scheduler/controller/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

data "aws_caller_identity" "current" {}

module "vpc_info" {
  source = "git@github.com:theorchard/terraform-vpc-info.git//?ref=3.1.0"

  environment = var.environment
}

data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [module.vpc_info.vpc_id]
  }

  tags = {
    Name = var.subnet_name_pattern
  }
}

data "aws_ec2_managed_prefix_list" "prefix_lists" {
  for_each = var.prefix_lists_to_allow_ingress_to_lb
  name     = each.value
}

data "aws_route53_zone" "route53_zone" {
  name = "${var.environment}.theorchard.io."
}

data "aws_route53_zone" "route53_zone_networking" {
  provider = aws.networking
  name     = "theorchard.io."
}

data "aws_s3_bucket" "logging_bucket_waf" {
  bucket = "aws-waf-logs-${var.environment}-orcd"
}

data "aws_s3_bucket" "logging_bucket_lb" {
  bucket = "${var.environment}-orcd-lb-logs"
}

data "aws_acm_certificate" "theorchard_io_certificate" {
  domain   = "*.theorchard.io"
  statuses = ["ISSUED"]
}

module "jenkins_controller_storage" {
  source = "git@github.com:theorchard/terraform-efs.git//?ref=4.1.0"

  providers = {
    aws.dns = aws.networking
  }

  environment              = var.environment
  service_name             = var.service_name
  application_family       = var.application_family
  vpc_id                   = module.vpc_info.vpc_id
  subnet_ids               = data.aws_subnets.private.ids
  owner_gid                = "1000"
  owner_uid                = "1000"
  access_point_permissions = "750"
  efs_throughput_mode      = "elastic"

  efs_ingress_additional_cidr_blocks = [
    "192.168.32.0/24",
  ]
}

resource "aws_security_group_rule" "allow_jenkins_to_access_efs" {
  from_port                = 2049
  to_port                  = 2049
  protocol                 = "tcp"
  security_group_id        = module.jenkins_controller_storage.efs_security_group_id_output
  source_security_group_id = module.jenkins_controller.fargate_security_group_id
  type                     = "ingress"
}

module "jenkins_controller" {
  source = "git@github.com:theorchard/terraform-fargate.git//?ref=5.8.0"

  providers = {
    aws.dns = aws
  }

  environment                              = var.environment
  service_name                             = var.service_name
  application_family                       = var.application_family
  aws_region                               = var.aws_region
  ows_machine_to_machine_enabled           = false
  splitio_enabled                          = false
  desired_task_count                       = 1
  task_cpu                                 = 4096
  task_memory                              = 8192
  load_balancer_access_logs_s3_bucket_name = data.aws_s3_bucket.logging_bucket_lb.id
  load_balancer_subnets                    = data.aws_subnets.private.ids
  fargate_service_subnets                  = data.aws_subnets.private.ids
  availability_zone_rebalancing            = "DISABLED"
  health_check_path                        = "/login"
  vpc_id                                   = module.vpc_info.vpc_id
  route53_zone_id                          = data.aws_route53_zone.route53_zone.zone_id
  autoscaling_cpu_policy_enabled           = false
  minimum_capacity                         = 1
  maximum_capacity                         = 1
  container_port                           = "8080"
  health_check_grace_period_seconds        = 300
  container_start_period_seconds           = 300
  custom_waf_arn                           = module.custom_waf.waf_blocking_arn_output

  # The deployment settings are deliberately configured in such a way that the
  # ECS scheduler will be unable to terminate the running task when the service is updated.
  # This ensures we can safely shut down Jenkins without affecting running builds.
  deployment_maximum_percent         = 100
  deployment_minimum_healthy_percent = 50

  docker_volumes = [
    {
      name            = "${var.environment}-${var.service_name}"
      file_system_id  = module.jenkins_controller_storage.efs_file_system_id_output
      access_point_id = module.jenkins_controller_storage.efs_access_point_id_output
    },
    {
      name = "${var.environment}-${var.service_name}-plugins"
      type = "BIND_MOUNT"
    }
  ]

  docker_volume_mount_points = [
    {
      source_volume  = "${var.environment}-${var.service_name}"
      container_path = "/var/jenkins_home"
    },
    # Create a bind mount volume for the plugins directory. This ensures that out of band changes
    # to plugins are not persisted, guaranteeing that the Docker image is the source of truth.
    {
      source_volume  = "${var.environment}-${var.service_name}-plugins"
      container_path = "/var/jenkins_home/plugins"
    }
  ]

  iam_managed_policy_attachments = [
    module.jenkins_controller_storage.efs_iam_policy_arn_output,
  ]

  environment_variables = [
    {
      Environment = var.environment
    },
    {
      JENKINS_JAVA_OPTS = "-Xmx6g -Dorg.jenkinsci.plugins.docker.commons.credentials.ImageNameValidator.SKIP=true"
    },
    {
      TZ = "America/New_York"
    }
  ]
}
resource "aws_security_group_rule" "allow_inbound_access_to_lb" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  prefix_list_ids   = [for list in data.aws_ec2_managed_prefix_list.prefix_lists : list.id]
  security_group_id = module.jenkins_controller.fargate_load_balancer_security_group_id
}

resource "aws_lb_listener_certificate" "additional_certificate" {
  listener_arn    = module.jenkins_controller.fargate_load_balancer_https_listener_arn
  certificate_arn = data.aws_acm_certificate.theorchard_io_certificate.arn
}

module "custom_waf" {
  source            = "git@github.com:theorchard/terraform-aws-waf.git//?ref=2.0.2"
  environment       = var.environment
  service_name      = var.service_name
  aws_region        = var.aws_region
  count_waf_enabled = false
  block_waf_enabled = true
  excluded_rules = [
    "CrossSiteScripting_BODY",
    "EC2MetaDataSSRF_BODY",
    "GenericLFI_BODY",
    "GenericRFI_BODY",
    "SizeRestrictions_BODY",
  ]
}

resource "aws_wafv2_web_acl_logging_configuration" "waf_block_web_acl_logging_configuration" {
  log_destination_configs = [data.aws_s3_bucket.logging_bucket_waf.arn]
  resource_arn            = module.custom_waf.waf_blocking_arn_output

  redacted_fields {
    single_header {
      name = "authorization"
    }
  }

  redacted_fields {
    single_header {
      name = "session"
    }
  }

  redacted_fields {
    single_header {
      name = "cookie"
    }
  }
}

module "fargate_service_dashboard" {
  source = "git@github.com:theorchard/terraform-datadog.git//modules/service?ref=6.13.7"

  environment        = var.environment
  environment_type   = "fargate"
  service_name       = var.service_name
  application_family = var.application_family
  teams              = [var.team]

  healthy_tasks_critical_number          = 1
  healthy_tasks_warning_number           = null
  healthy_tasks_warning_recovery_number  = null
  healthy_tasks_critical_recovery_number = null


  notification_endpoints            = var.notification_endpoints
  escalation_notification_endpoints = var.notification_endpoints
}

module "jenkins_monitoring" {
  source = "git@github.com:theorchard/terraform-datadog.git//modules/jenkins?ref=6.16.0"

  environment        = var.environment
  service_name       = var.service_name
  application_family = var.application_family
  teams              = [var.team]

  notification_endpoints            = var.notification_endpoints
  escalation_notification_endpoints = var.notification_endpoints
}

resource "aws_route53_record" "theorchard_io_cname_record" {
  provider = aws.networking

  name    = "scheduler.theorchard.io"
  type    = "CNAME"
  ttl     = 300
  zone_id = data.aws_route53_zone.route53_zone_networking.zone_id
  records = [module.jenkins_controller.non_prod_fargate_service_route53_record_fqdn_output]
}
