Skip to content

Commit

Permalink
Add Wordpress Fargate RDS example (#475)
Browse files Browse the repository at this point in the history
* Add Wordpress Fargate RDS example
  • Loading branch information
polkx authored Apr 23, 2024
1 parent 7981647 commit f4618b5
Show file tree
Hide file tree
Showing 8 changed files with 499 additions and 1 deletion.
2 changes: 1 addition & 1 deletion examples/aws-webserver/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: aws-java-webserver
name: aws-webserver
runtime: scala
description: Basic example of an AWS web server accessible over HTTP
template:
Expand Down
55 changes: 55 additions & 0 deletions examples/aws-wordpress-fargate-rds/Backend.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import besom.*
import besom.api.aws

case class DbArgs(
dbName: Input[String],
dbUser: Input[String],
dbPassword: Input[String],
subnetIds: Input[List[String]],
securityGroupIds: Input[List[String]]
)

case class Db(
dbAddress: Output[String],
dbName: Output[String],
dbUser: Output[String],
dbPassword: Output[String]
)(using ComponentBase)
extends ComponentResource
derives RegistersOutputs

object Db:
extension (c: Output[Db])
def dbAddress: Output[String] = c.flatMap(_.dbAddress)
def dbName: Output[String] = c.flatMap(_.dbName)
def dbUser: Output[String] = c.flatMap(_.dbUser)
def dbPassword: Output[String] = c.flatMap(_.dbPassword)

def apply(using Context)(name: NonEmptyString, args: DbArgs, options: ComponentResourceOptions = ComponentResourceOptions()): Output[Db] =
component(name, "custom:resource:DB", options) {

val rdsSubnetGroup = aws.rds.SubnetGroup(
name = s"$name-sng",
aws.rds.SubnetGroupArgs(subnetIds = args.subnetIds)
)

val db = aws.rds.Instance(
name = s"$name-rds",
aws.rds.InstanceArgs(
dbName = args.dbName,
username = args.dbUser,
password = args.dbPassword,
vpcSecurityGroupIds = args.securityGroupIds,
dbSubnetGroupName = rdsSubnetGroup.name,
allocatedStorage = 20,
engine = "mysql",
engineVersion = "5.7",
instanceClass = aws.rds.enums.InstanceType.T3_Micro,
storageType = aws.rds.enums.StorageType.GP2,
skipFinalSnapshot = true,
publiclyAccessible = false
)
)

Db(dbAddress = db.address, dbName = db.dbName, dbUser = db.username, dbPassword = db.password.map(_.get))
}
152 changes: 152 additions & 0 deletions examples/aws-wordpress-fargate-rds/Frontent.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import besom.*
import besom.api.{aws, awsx}
import besom.json.*

case class WebServiceArgs(
dbHost: Input[String],
dbName: Input[String],
dbUser: Input[String],
dbPassword: Input[String],
dbPort: Input[String],
vpcId: Input[String],
subnetIds: Input[List[String]],
securityGroupIds: Input[List[String]]
)

case class WebService(
serviceId: Output[ResourceId],
dnsName: Output[String],
clusterName: Output[String]
)(using ComponentBase)
extends ComponentResource
derives RegistersOutputs

object WebService:
extension (c: Output[WebService])
def dnsName: Output[String] = c.flatMap(_.dnsName)
def clusterName: Output[String] = c.flatMap(_.clusterName)

def apply(using
Context
)(name: NonEmptyString, args: WebServiceArgs, options: ComponentResourceOptions = ComponentResourceOptions()): Output[WebService] =
component(name, "custom:resource:WebService", options) {
val cluster = aws.ecs.Cluster(s"$name-ecs")

val alb = aws.lb.LoadBalancer(
name = s"$name-alb",
aws.lb.LoadBalancerArgs(
securityGroups = args.securityGroupIds,
subnets = args.subnetIds
)
)

val atg = aws.lb.TargetGroup(
name = s"$name-tg",
aws.lb.TargetGroupArgs(
port = 80,
protocol = "HTTP",
targetType = "ip",
vpcId = args.vpcId,
healthCheck = aws.lb.inputs.TargetGroupHealthCheckArgs(
healthyThreshold = 2,
interval = 5,
timeout = 4,
protocol = "HTTP",
matcher = "200-399"
)
)
)

val wl = aws.lb.Listener(
name = s"$name-listener",
aws.lb.ListenerArgs(
loadBalancerArn = alb.arn,
port = 80,
defaultActions = List(
aws.lb.inputs.ListenerDefaultActionArgs(
`type` = "forward",
targetGroupArn = atg.arn
)
)
)
)
val role = aws.iam.Role(
name = s"$name-task-role",
aws.iam.RoleArgs(
assumeRolePolicy = json"""{
"Version": "2012-10-17",
"Statement": [{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
}""".map(_.prettyPrint)
)
)

val rpa = aws.iam.RolePolicyAttachment(
name = s"$name-task-policy",
aws.iam.RolePolicyAttachmentArgs(
role = role.name,
policyArn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
)
)

val task = awsx.ecs.FargateTaskDefinition(
name = s"$name-app-task",
awsx.ecs.FargateTaskDefinitionArgs(
container = awsx.ecs.inputs.TaskDefinitionContainerDefinitionArgs(
name = s"$name-app-container",
image = "wordpress",
cpu = 256,
memory = 512,
environment = List(
envValue(name = "WORDPRESS_DB_HOST", value = p"${args.dbHost}:${args.dbPort}"),
envValue(name = "WORDPRESS_DB_NAME", value = args.dbName),
envValue(name = "WORDPRESS_DB_USER", value = args.dbUser),
envValue(name = "WORDPRESS_DB_PASSWORD", value = args.dbPassword)
),
portMappings = List(
awsx.ecs.inputs.TaskDefinitionPortMappingArgs(
containerPort = 80,
hostPort = 80,
protocol = "tcp"
)
)
)
)
)

val service = awsx.ecs.FargateService(
name = s"$name-app-svc",
awsx.ecs.FargateServiceArgs(
networkConfiguration = aws.ecs.inputs.ServiceNetworkConfigurationArgs(
assignPublicIp = true,
subnets = args.subnetIds,
securityGroups = args.securityGroupIds
),
loadBalancers = List(
aws.ecs.inputs.ServiceLoadBalancerArgs(
containerName = s"$name-app-container",
containerPort = 80,
targetGroupArn = atg.arn
)
),
cluster = cluster.arn,
taskDefinition = task.taskDefinition.arn,
desiredCount = 1
),
opts = opts(dependsOn = List(wl, rpa))
)

WebService(serviceId = service.id, dnsName = alb.dnsName, clusterName = cluster.name)
}
end WebService

private def envValue(name: String, value: Input[String])(using
Context
): awsx.ecs.inputs.TaskDefinitionKeyValuePairArgs =
awsx.ecs.inputs.TaskDefinitionKeyValuePairArgs(name = name, value = value)
58 changes: 58 additions & 0 deletions examples/aws-wordpress-fargate-rds/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import besom.*
import besom.api.random

@main def main = Pulumi.run {
val serviceName = "wp-fargate-rds"
val dbName = config.getString("dbName").getOrElse("wordpress")
val dbUser = config.getString("dbUser").getOrElse("admin")

val dbPassword = config
.getString("dbPassword")
.getOrElse(
random
.RandomPassword(
"dbPassword",
random.RandomPasswordArgs(
length = 16,
special = true,
overrideSpecial = "_%"
)
)
.result
)

val vpc = AwsVpc(s"$serviceName-net")

val db = Db(
name = s"$serviceName-db",
DbArgs(
dbName = dbName,
dbUser = dbUser,
dbPassword = dbPassword,
subnetIds = vpc.subnetIds,
securityGroupIds = vpc.rdsSecurityGroupIds
)
)

val fe = WebService(
s"$serviceName-fe",
WebServiceArgs(
dbHost = db.dbAddress,
dbPort = "3306",
dbName = db.dbName,
dbUser = db.dbUser,
dbPassword = db.dbPassword,
vpcId = vpc.vpcId,
subnetIds = vpc.subnetIds,
securityGroupIds = vpc.feSecurityGroupIds
)
)

Stack.exports(
webServiceUrl = p"http://${fe.dnsName}",
ecsClusterName = fe.clusterName,
databaseEndpoint = db.dbAddress,
databaseUserName = db.dbUser,
databasePassword = db.dbPassword
)
}
Loading

0 comments on commit f4618b5

Please sign in to comment.