# Task 129


VPC with a public and private subnet. Define an EC2 Fleet of the newest AWS Linux 2 with a combination of 5 On-Demand and 4 Spot Instances.  Utilize Launch Templates for configuration consistency.

## Intent

Create VPC, public subnet in the VPC, private subnet in the VPC, aws_ec2_fleet with 5 spot and 4 on demand, and aws_autoscaling

## Reference Terraform solution

terraform {
  required_version = ">= 1.15.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

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

# Create a Virtual Private Cloud (VPC)
resource "aws_vpc" "my_vpc" {
  cidr_block = "10.0.0.0/16"
}

data "aws_availability_zones" "available" {
  state = "available"
}

# Create Public Subnet
resource "aws_subnet" "public_subnet" {
  vpc_id                  = aws_vpc.my_vpc.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = data.aws_availability_zones.available.names[0]
  map_public_ip_on_launch = true
}

# Create Private Subnet
resource "aws_subnet" "private_subnet" {
  vpc_id            = aws_vpc.my_vpc.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = data.aws_availability_zones.available.names[1]
}


data "aws_ami" "latest_amazon_linux_2" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["*ubuntu-noble-24.04-amd64-server-*"]
  }
}

# Create Launch Template for EC2 instances
resource "aws_launch_template" "ec2_launch_template" {
  name = "my-launch-template"

  instance_type = "t2.micro"
  image_id = data.aws_ami.latest_amazon_linux_2.id
}

# Create EC2 Fleet
resource "aws_ec2_fleet" "ec2_fleet" {
  launch_template_config {
    launch_template_specification {
      launch_template_id = aws_launch_template.ec2_launch_template.id
      version            = aws_launch_template.ec2_launch_template.latest_version
    }
  }

  target_capacity_specification {
    default_target_capacity_type = "on-demand"
    total_target_capacity        = 9
    on_demand_target_capacity    = 5
    spot_target_capacity         = 4
  }

  excess_capacity_termination_policy = "termination"
  replace_unhealthy_instances = true
  terminate_instances = true

  # Additional configurations can be added as needed
}

# Don't know why we use asg and ec2 fleet together
# # Create EC2 Auto Scaling Group
# resource "aws_autoscaling_group" "asg" {
#   desired_capacity    = 1
#   max_size            = 10
#   min_size            = 1
#   vpc_zone_identifier = [aws_subnet.public_subnet.id, aws_subnet.private_subnet.id]
  
#   launch_template {
#     id      = aws_launch_template.ec2_launch_template.id
#     version = aws_launch_template.ec2_launch_template.latest_version
#   }

#   health_check_type         = "EC2"
#   health_check_grace_period = 300

#   # Additional configurations can be added as needed
# }


## OPA Rego validation policy

package terraform.policy

import rego.v1

default allow = false

allow if {
    public_subnet_exists(input.resource_changes)
    private_subnet_exists(input.resource_changes)
    ec2_fleet_valid(input.resource_changes)
    launch_template_valid(input.resource_changes)
    scaling_group_valid(input.resource_changes)
}

public_subnet_exists(resources) if {
    some resource in resources
    resource.type == "aws_subnet"
    resource.change.after.map_public_ip_on_launch == true
}

private_subnet_exists(resources) if {
    some resource in resources
    resource.type == "aws_subnet"
    resource.change.after.map_public_ip_on_launch == false
}

ec2_fleet_valid(resources) if {
    some resource in resources
    resource.type == "aws_ec2_fleet"
    resource.change.after.launch_template_config[0].launch_template_specification[0].version == "$Latest"
    resource.change.after.target_capacity_specification[0].on_demand_target_capacity == 5
    resource.change.after.target_capacity_specification[0].spot_target_capacity == 4
}

launch_template_valid(resources) if {
    some resource in resources
    resource.type == "aws_launch_template"
    resource.change.after.image_id == "ami-0591e1c6a24d08458"
}

scaling_group_valid(resources) if {
    some resource in resources
    resource.type == "aws_autoscaling_group"
    resource.change.after.launch_template[0].version == "$Latest"
}

main if {
    allow
}