Skip to content

Commit

Permalink
Terraform infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
yusu-banana committed Jan 1, 2024
1 parent 1ec3ee8 commit b746b7b
Show file tree
Hide file tree
Showing 15 changed files with 2,616 additions and 99 deletions.
2,300 changes: 2,202 additions & 98 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"typescript": "^5.0.2"
},
"dependencies": {
"@aws-sdk/client-ssm": "^3.484.0",
"@dice-roller/rpg-dice-roller": "^5.2.1",
"@discordx/importer": "^1.2.1",
"@discordx/pagination": "^3.4.1",
Expand Down
17 changes: 16 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { isPromise } from 'util/types'
import { CronJob } from 'cron'
import { clearOrphanedRoles } from './standalones/clearOrphanedRoles'
import { decayElo } from './standalones/eloDecay'
import { SSM } from 'aws-sdk'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
;(BigInt.prototype as any).toJSON = function () {
Expand Down Expand Up @@ -116,7 +117,21 @@ async function run() {
DIService.engine = tsyringeDependencyRegistryEngine.setInjector(container)

await importx(`${__dirname}/{events,commands,persistence}/**/*.{ts,js}`)
bot.login(process.env.DISCORD_TOKEN ?? '') // provide your bot token

let discord_token
if (process.env.PRODUCTION) {
const ssm = new SSM()
discord_token = await ssm
.getParameter({
Name: 'discord-token',
WithDecryption: true,
})
.promise()
} else {
discord_token = process.env.DISCORD_TOKEN ?? '' // provide your bot token
}

bot.login(discord_token)
}

run()
44 changes: 44 additions & 0 deletions terraform/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions terraform/cloudwatch.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource "aws_cloudwatch_log_group" "cloudwatch_log_group_ecs" {
name = "TwiggyBot"
retention_in_days = 7
}
24 changes: 24 additions & 0 deletions terraform/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
data "aws_iam_policy_document" "assume_role_policy_ecs_tasks" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]

principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}

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

principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}

actions = ["sts:AssumeRole"]
}
}
21 changes: 21 additions & 0 deletions terraform/ec2.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
resource "aws_vpc" "vpc" {
cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "subnet" {
vpc_id = aws_vpc.vpc.id
cidr_block = "10.0.0.0/16"
}

resource "aws_security_group" "security_group" {
name = "twiggy"
vpc_id = aws_vpc.vpc.id

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}
26 changes: 26 additions & 0 deletions terraform/ecr.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
resource "aws_ecr_repository" "ecr_repository" {
name = "twiggy"
}

resource "aws_ecr_lifecycle_policy" "ecr_lifecycle_policy" {
repository = aws_ecr_repository.ecr_repository.name

policy = jsonencode({
rules : [
{
rulePriority : 1
description : "Delete untagged images"
selection : {
tagStatus : "untagged"
countType : "sinceImagePushed"
countUnit : "days"
countNumber : 1
}
action : {
type : "expire"
}
}
]
})
depends_on = [aws_ecr_repository.ecr_repository]
}
104 changes: 104 additions & 0 deletions terraform/ecs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
resource "aws_ecs_cluster" "ecs_cluster" {
name = "twiggy"
}

resource "aws_ecs_service" "ecs_primary_service" {
name = "twiggy-primary"
cluster = aws_ecs_cluster.ecs_cluster.arn

desired_count = 1
capacity_provider_strategy {
capacity_provider = "FARGATE_SPOT"
weight = 1
}
platform_version = "LATEST"
task_definition = aws_ecs_task_definition.ecs_task_definition.arn
deployment_maximum_percent = 200
deployment_minimum_healthy_percent = 100
enable_execute_command = true
propagate_tags = "SERVICE"

network_configuration {
assign_public_ip = true
subnets = [
aws_subnet.subnet.id
]
security_groups = [
aws_security_group.security_group.id
]
}
health_check_grace_period_seconds = 0
scheduling_strategy = "REPLICA"

lifecycle {
ignore_changes = [capacity_provider_strategy]
}
}

resource "aws_ecs_service" "ecs_fallback_service" {
name = "twiggy-fallback"
cluster = aws_ecs_cluster.ecs_cluster.arn

desired_count = 0
capacity_provider_strategy {
capacity_provider = "FARGATE"
weight = 1
}
platform_version = "LATEST"
task_definition = aws_ecs_task_definition.ecs_task_definition.arn
deployment_maximum_percent = 200
deployment_minimum_healthy_percent = 100
enable_execute_command = true
propagate_tags = "SERVICE"

network_configuration {
assign_public_ip = true
subnets = [
aws_subnet.subnet.id
]
security_groups = [
aws_security_group.security_group.id
]
}
health_check_grace_period_seconds = 0
scheduling_strategy = "REPLICA"
}

resource "aws_ecs_task_definition" "ecs_task_definition" {
family = "twiggy"
task_role_arn = aws_iam_role.ecs_task_role.arn
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
network_mode = "awsvpc"
requires_compatibilities = [
"FARGATE"
]
cpu = "256"
memory = "512"
runtime_platform {
cpu_architecture = "X86_64"
operating_system_family = "LINUX"
}
container_definitions = jsonencode([
{
name : "twiggy"
essential : true
image : "${aws_ecr_repository.ecr_repository.repository_url}:twiggy"
logConfiguration : {
logDriver : "awslogs"
options : {
awslogs-create-group : "true"
awslogs-group : aws_cloudwatch_log_group.cloudwatch_log_group_ecs.name
awslogs-region : "eu-west-1"
awslogs-stream-prefix : "twiggy"
}
},

environment : [
{
name : "PRODUCTION"
value : "1"
}
]
}
])
}
36 changes: 36 additions & 0 deletions terraform/events.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
resource "aws_cloudwatch_event_rule" "cloudwatch_event_rule" {
name_prefix = "ecs-fargate-fallback-rule"
event_pattern = jsonencode({
source : [
"aws.ecs"
],
detail-type : [
"ECS Service Action"
],
resources : [
aws_ecs_service.ecs_primary_service.id
]
detail : {
eventName : ["SERVICE_STEADY_STATE", "SERVICE_TASK_PLACEMENT_FAILURE"],
}
})
}

resource "aws_cloudwatch_event_target" "cloudwatch_event_target" {
arn = aws_lambda_function.lambda_function.arn
rule = aws_cloudwatch_event_rule.cloudwatch_event_rule.id

input_transformer {
input_paths = {
event_name = "$.detail.eventName"
}
input_template = <<EOF
{
"cluster_arn": "${aws_ecs_cluster.ecs_cluster.arn}",
"primary_service_arn": "${aws_ecs_service.ecs_primary_service.id}",
"fallback_service_arn": "${aws_ecs_service.ecs_fallback_service.id}",
"event_name": "<event_name>"
}
EOF
}
}
69 changes: 69 additions & 0 deletions terraform/iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
resource "aws_iam_role" "ecs_task_role" {
name = "twiggy-ecs_task_role"
path = "/service-role/"
assume_role_policy = data.aws_iam_policy_document.assume_role_policy_ecs_tasks.json
inline_policy {
name = "ecs-exec"
policy = jsonencode({
Statement : [
{
Effect : "Allow",
Action : [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel"
],
Resource : "*"
}
]
})
}
inline_policy {
name = "systems-manager-parameter-store-access"
policy = jsonencode({
Statement : [
{
Effect : "Allow",
Action : "ssm:GetParameter",
Resource : "arn:aws:ssm:eu-west-1:866826529066:discord-token"
}
]
})
}
}

resource "aws_iam_role" "ecs_task_execution_role" {
name = "twiggy-ecs_task_execution_role"
path = "/service-role/"
assume_role_policy = data.aws_iam_policy_document.assume_role_policy_ecs_tasks.json
managed_policy_arns = [
"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
]
}

resource "aws_iam_role" "lambda" {
name = "twiggy-lambda"
assume_role_policy = data.aws_iam_policy_document.assume_role_policy_lambda.json
managed_policy_arns = [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
]
inline_policy {
name = "ecs-update-service"
policy = jsonencode({
Statement : [
{
Effect : "Allow",
Action : [
"ecs:DescribeServices",
"ecs:UpdateService",
],
Resource = [
aws_ecs_service.ecs_primary_service.id,
aws_ecs_service.ecs_fallback_service.id,
]
}
]
})
}
}
Loading

0 comments on commit b746b7b

Please sign in to comment.