Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Commit

Permalink
Add old internal modules (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
Puneeth-n authored Nov 30, 2021
1 parent 9aca24f commit 2ba6127
Show file tree
Hide file tree
Showing 6 changed files with 591 additions and 0 deletions.
41 changes: 41 additions & 0 deletions ecr-image/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
variable "registry_id" {
description = "AWS ECR registry ID"
default = "940226765273"
type = string
}

variable "repository_name" {
description = "AWS ECR repository name"
type = string
}

variable "image_tag" {
description = "AWS ECR image tag"
type = string
}

data "aws_ecr_repository" "service" {
name = var.repository_name
}

data "aws_ecr_image" "service_image" {
registry_id = var.registry_id
repository_name = var.repository_name
image_tag = var.image_tag
}

output "repository_url" {
value = data.aws_ecr_repository.service.repository_url
description = "ECR url"
}

output "image_digest" {
value = data.aws_ecr_image.service_image.image_digest
description = "Docker image digest"
}

output "image" {
value = "${data.aws_ecr_repository.service.repository_url}@${data.aws_ecr_image.service_image.image_digest}"
description = "Docker image"
}

4 changes: 4 additions & 0 deletions ecr-image/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

terraform {
required_version = ">= 0.12"
}
249 changes: 249 additions & 0 deletions ecs-service/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
locals {
default_min_healthy_percent = var.capacity.desired > 1 ? 50 : 0
default_max_healthy_percent = 100
min_healthy_percent = var.min_healthy_percent != null ? var.min_healthy_percent : local.default_min_healthy_percent
max_healthy_percent = var.max_healthy_percent != null ? var.max_healthy_percent : local.default_max_healthy_percent

enable_count = var.enable ? 1 : 0
enable_scaling_count = var.enable == true && var.scheduling_strategy == "REPLICA" && var.capacity.enable_scaling == true ? 1 : 0

service_count = var.scheduling_strategy == "REPLICA" && var.enable == true ? 1 : 0
daemon_count = var.scheduling_strategy == "DAEMON" && var.enable == true ? 1 : 0
stability_check_command = "AWS_METADATA_SERVICE_TIMEOUT=10 AWS_METADATA_SERVICE_NUM_ATTEMPTS=18 python3 ${path.module}/scripts/wait_for_service_stable.py --region ${var.region} --service ${var.name} --cluster ${var.cluster_id} --role_to_assume ${var.ecs_stability_check_config.role} --service_stability_check_timeout ${var.ecs_stability_check_config.timeout} --interval_between_stability_checks ${var.ecs_stability_check_config.interval}"

default_tags = {
Name = "${var.name}-${var.environment}"
Environment = var.environment
}
}

resource "aws_alb_target_group" "service" {
count = local.service_count
name = "${var.name}-${var.environment}"
port = var.port_mappings[0]["containerPort"]
protocol = "HTTP"
vpc_id = var.vpc_id
deregistration_delay = var.deregistration_delay
load_balancing_algorithm_type = var.load_balancing_algorithm_type

health_check {
interval = lookup(var.health_check, "interval", 30)
path = lookup(var.health_check, "path", "/")
healthy_threshold = lookup(var.health_check, "healthy_threshold", 2)
unhealthy_threshold = lookup(var.health_check, "unhealthy_threshold", 8)
timeout = lookup(var.health_check, "timeout", 5)
matcher = lookup(var.health_check, "matcher", 200)
port = "traffic-port"
}

stickiness {
type = "lb_cookie"
enabled = true
cookie_duration = 60
}

tags = merge(
local.default_tags,
{
"Loadbalancer" = var.load_balancer
},
)
}

resource "aws_ecs_task_definition" "service" {
count = local.enable_count
family = "${var.name}-${var.environment}"
container_definitions = var.container_definition
task_role_arn = var.task_role_arn
execution_role_arn = var.execution_role_arn
network_mode = var.network_mode
dynamic "volume" {
for_each = var.volumes
content {
host_path = volume.value.host_path
name = volume.value.name
}
}

tags = local.default_tags
}

resource "aws_appautoscaling_target" "ecs_target" {
count = local.enable_scaling_count
max_capacity = var.capacity.max
min_capacity = var.capacity.min
resource_id = "service/${local.cluster_name}/${var.name}"
role_arn = var.ecs_autoscaling_service_linked_role
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"

depends_on = [aws_ecs_service.service]
}

resource "aws_appautoscaling_policy" "ecs_policy" {
count = local.enable_scaling_count
name = "${local.cluster_name}-${var.name}"
policy_type = "TargetTrackingScaling"
resource_id = "service/${local.cluster_name}/${var.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"

target_tracking_scaling_policy_configuration {
target_value = var.capacity.target_value
scale_out_cooldown = 120
scale_in_cooldown = 300

predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageMemoryUtilization"
}
}

depends_on = [aws_appautoscaling_target.ecs_target]
}

resource "aws_ecs_service" "service" {
count = local.service_count
name = var.name
cluster = var.cluster_id
task_definition = aws_ecs_task_definition.service[0].arn
launch_type = "EC2"
desired_count = var.capacity.desired
iam_role = aws_iam_role.ecs_lb_role[0].arn
deployment_maximum_percent = local.max_healthy_percent
deployment_minimum_healthy_percent = local.min_healthy_percent
force_new_deployment = var.force_new_deployment
dynamic "ordered_placement_strategy" {
for_each = var.placement_strategy
content {
field = ordered_placement_strategy.value.field
type = ordered_placement_strategy.value.type
}
}
scheduling_strategy = var.scheduling_strategy
dynamic "placement_constraints" {
for_each = var.placement_constraints
content {
expression = placement_constraints.value.expression
type = placement_constraints.value.type
}
}

load_balancer {
target_group_arn = aws_alb_target_group.service[0].arn
container_name = var.name
container_port = var.port_mappings[0]["containerPort"]
}

depends_on = [
aws_iam_role.ecs_lb_role,
aws_ecs_task_definition.service,
]

lifecycle {
prevent_destroy = true
ignore_changes = [desired_count]
}
}

resource "aws_ecs_service" "daemon" {
count = local.daemon_count
name = var.name
cluster = var.cluster_id
task_definition = aws_ecs_task_definition.service[0].arn
launch_type = "EC2"

scheduling_strategy = var.scheduling_strategy

depends_on = [
aws_iam_role.ecs_lb_role,
aws_ecs_task_definition.service,
]


}

resource "aws_alb_listener_rule" "service" {
count = local.enable_count * var.alb_listener_count
listener_arn = var.alb[count.index]["listener_arn"]

action {
type = "forward"
target_group_arn = aws_alb_target_group.service[0].arn
}

condition {
host_header {
values = [
var.alb[count.index]["pattern"]
]
}
}


}

resource "aws_iam_role" "ecs_lb_role" {
count = local.enable_count
name = "${var.name}-alb-role-${var.environment}"
path = "/${var.environment}/"
force_detach_policies = true

assume_role_policy = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": ["ecs.amazonaws.com"]
},
"Effect": "Allow"
}
]
}
EOF
}

resource "aws_iam_role_policy_attachment" "ecs_lb_role" {
count = local.enable_count
role = aws_iam_role.ecs_lb_role[0].id
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole"
}

resource "aws_route53_record" "internal" {
count = local.enable_count * var.route53_count
zone_id = var.route53[count.index]["zone_id"]
name = var.route53[count.index]["name"]
type = "A"

alias {
name = var.route53[count.index]["alias_name"]
zone_id = var.route53[count.index]["alias_zone_id"]
evaluate_target_health = var.route53[count.index]["evaluate_target_health"]
}
}

resource "null_resource" "wait_for_service_deploy" {
count = local.service_count

triggers = {
task_definition = aws_ecs_service.service[0].task_definition
}

provisioner "local-exec" {
command = local.stability_check_command
}
}

resource "null_resource" "wait_for_daemon_deploy" {
count = local.daemon_count

triggers = {
task_definition = aws_ecs_service.daemon[0].task_definition
}

provisioner "local-exec" {
command = local.stability_check_command
}
}

79 changes: 79 additions & 0 deletions ecs-service/scripts/wait_for_service_stable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env python
'''
Wait for the ECS service to be stable
'''

import argparse
import boto3
import os
import sys
import time

ROOT_DIR = os.path.join(os.path.dirname(__file__), "../../../lib/")
sys.path.append(ROOT_DIR)

from assume_role import get_temporary_credentials


def parse_cli():
'''
parse cli
'''
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--region', required=True, type=str, help='AWS region')
parser.add_argument('--cluster', type=str, help='ECS service to check for stability', required=True)
parser.add_argument('--service', type=str, help='ECS service to check for stability', required=True)
parser.add_argument('--role_to_assume', type=str, help='AWS IAM role to assume', required=True)
parser.add_argument('--service_stability_check_timeout',
type=int,
help='Maximum time to wait in seconds for the service to be stable',
required=True)
parser.add_argument('--interval_between_stability_checks',
type=int,
help='Maximum time to wait in seconds for the service to be stable',
required=True)

return parser.parse_args()


def get_ecs_client(args):
'''
Get ECS client
'''
credentials = get_temporary_credentials(role_to_assume=args.role_to_assume,
region=args.region,
session_name='{}-{}'.format(args.service, time.time()),
duration_seconds=args.service_stability_check_timeout * 2)

return boto3.client('ecs',
region_name=args.region,
aws_access_key_id=credentials["AccessKeyId"],
aws_secret_access_key=credentials["SecretAccessKey"],
aws_session_token=credentials["SessionToken"])


def wait_for_service_to_be_stable(ecs_client, args):
'''
Wait for service to be stable
'''

max_attempts = args.service_stability_check_timeout / args.interval_between_stability_checks

waiter = ecs_client.get_waiter('services_stable')

waiter.wait(cluster=args.cluster,
services=[args.service],
WaiterConfig={
'Delay': args.interval_between_stability_checks,
'MaxAttempts': max_attempts
})


def main():
args = parse_cli()
ecs_client = get_ecs_client(args)
wait_for_service_to_be_stable(ecs_client, args)


if __name__ == '__main__':
main()
Loading

0 comments on commit 2ba6127

Please sign in to comment.