269 lines
7 KiB
Go
269 lines
7 KiB
Go
package main
|
|
|
|
import (
|
|
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"
|
|
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/iam"
|
|
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/lambda"
|
|
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/rds"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
|
)
|
|
|
|
func vpc(ctx *pulumi.Context) (*ec2.Vpc, error) {
|
|
|
|
return ec2.NewVpc(ctx, "writeonce-vpc", &ec2.VpcArgs{
|
|
CidrBlock: pulumi.String("10.0.0.0/16"),
|
|
InstanceTenancy: pulumi.String("default"),
|
|
Tags: pulumi.StringMap{
|
|
"dbFor": pulumi.String("blogs"),
|
|
},
|
|
})
|
|
}
|
|
|
|
func securityGroup(ctx *pulumi.Context, vpc *ec2.Vpc) (*ec2.SecurityGroup, error) {
|
|
|
|
return ec2.NewSecurityGroup(ctx, "blog-db-sg", &ec2.SecurityGroupArgs{
|
|
VpcId: vpc.ID(),
|
|
Description: pulumi.String("Allow DB access"),
|
|
Ingress: ec2.SecurityGroupIngressArray{
|
|
&ec2.SecurityGroupIngressArgs{
|
|
Protocol: pulumi.String("tcp"),
|
|
FromPort: pulumi.Int(5432),
|
|
ToPort: pulumi.Int(5432),
|
|
CidrBlocks: pulumi.StringArray{vpc.CidrBlock},
|
|
},
|
|
},
|
|
Egress: ec2.SecurityGroupEgressArray{
|
|
&ec2.SecurityGroupEgressArgs{
|
|
Protocol: pulumi.String("-1"),
|
|
FromPort: pulumi.Int(0),
|
|
ToPort: pulumi.Int(0),
|
|
CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
|
|
},
|
|
},
|
|
Tags: pulumi.StringMap{
|
|
"Name": pulumi.String("blog-db-sg"),
|
|
},
|
|
})
|
|
}
|
|
|
|
func subnetA(ctx *pulumi.Context, vpc *ec2.Vpc) (*ec2.Subnet, error) {
|
|
|
|
return ec2.NewSubnet(ctx, "aurora-subnet-a", &ec2.SubnetArgs{
|
|
VpcId: vpc.ID(),
|
|
CidrBlock: pulumi.String("10.0.1.0/24"),
|
|
AvailabilityZone: pulumi.String("eu-central-1a"),
|
|
Tags: pulumi.StringMap{
|
|
"Name": pulumi.String("aurora-subnet-a"),
|
|
},
|
|
})
|
|
}
|
|
func subnetB(ctx *pulumi.Context, vpc *ec2.Vpc) (*ec2.Subnet, error) {
|
|
|
|
return ec2.NewSubnet(ctx, "aurora-subnet-b", &ec2.SubnetArgs{
|
|
VpcId: vpc.ID(),
|
|
CidrBlock: pulumi.String("10.0.2.0/24"),
|
|
AvailabilityZone: pulumi.String("eu-central-1b"),
|
|
Tags: pulumi.StringMap{
|
|
"Name": pulumi.String("aurora-subnet-b"),
|
|
},
|
|
})
|
|
}
|
|
|
|
func cluster(ctx *pulumi.Context, sg *ec2.SecurityGroup, subnets []*ec2.Subnet) (*rds.Cluster, error) {
|
|
subnetIds := pulumi.StringArray{}
|
|
for _, s := range subnets {
|
|
subnetIds = append(subnetIds, s.ID())
|
|
}
|
|
|
|
subnetGroup, err := rds.NewSubnetGroup(ctx, "aurora-subnet-group", &rds.SubnetGroupArgs{
|
|
SubnetIds: subnetIds,
|
|
Tags: pulumi.StringMap{
|
|
"Name": pulumi.String("aurora-db-subnet-group"),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result, err := rds.NewCluster(ctx, "postgresql", &rds.ClusterArgs{
|
|
ClusterIdentifier: pulumi.String("aurora-cluster"),
|
|
Engine: pulumi.String(rds.EngineTypeAuroraPostgresql),
|
|
EngineMode: pulumi.String(rds.EngineModeProvisioned),
|
|
EngineVersion: pulumi.String("16.6"),
|
|
DatabaseName: pulumi.String("writeonce"),
|
|
MasterUsername: pulumi.String("writeonce"),
|
|
MasterPassword: pulumi.String("writeonce"),
|
|
VpcSecurityGroupIds: pulumi.StringArray{
|
|
sg.ID().ToStringOutput(),
|
|
},
|
|
DbSubnetGroupName: subnetGroup.Name,
|
|
StorageEncrypted: pulumi.Bool(true),
|
|
Serverlessv2ScalingConfiguration: &rds.ClusterServerlessv2ScalingConfigurationArgs{
|
|
MaxCapacity: pulumi.Float64(1),
|
|
MinCapacity: pulumi.Float64(0),
|
|
SecondsUntilAutoPause: pulumi.Int(3600),
|
|
},
|
|
SkipFinalSnapshot: pulumi.Bool(true),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_, err = rds.NewClusterInstance(ctx, "postgresql-instance", &rds.ClusterInstanceArgs{
|
|
ClusterIdentifier: result.ID(),
|
|
InstanceClass: pulumi.String("db.serverless"),
|
|
Engine: result.Engine,
|
|
EngineVersion: result.EngineVersion,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return result, nil
|
|
|
|
}
|
|
|
|
func lambdaFunction(ctx *pulumi.Context, cluster *rds.Cluster, securityGroup *ec2.SecurityGroup, subnets []*ec2.Subnet) error {
|
|
|
|
subnetIds := pulumi.StringArray{}
|
|
for _, s := range subnets {
|
|
subnetIds = append(subnetIds, s.ID())
|
|
}
|
|
|
|
layer, err := lambda.NewLayerVersion(ctx, "pg_libpq-layer", &lambda.LayerVersionArgs{
|
|
Code: pulumi.NewFileArchive("layer/libpq-layer.zip"),
|
|
LayerName: pulumi.String("libpq-layer"),
|
|
CompatibleRuntimes: pulumi.StringArray{
|
|
pulumi.String("provided.al2023"),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Create an IAM role.
|
|
role, err := iam.NewRole(ctx, "task-exec-role", &iam.RoleArgs{
|
|
AssumeRolePolicy: pulumi.String(`{
|
|
"Version": "2012-10-17",
|
|
"Statement": [{
|
|
"Sid": "",
|
|
"Effect": "Allow",
|
|
"Principal": {
|
|
"Service": "lambda.amazonaws.com"
|
|
},
|
|
"Action": "sts:AssumeRole"
|
|
}]
|
|
}`),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// change later
|
|
funcPolicy, err := iam.NewRolePolicy(ctx, "post-article-aurora-pgsql-policy", &iam.RolePolicyArgs{
|
|
Role: role.Name,
|
|
Policy: pulumi.String(`{
|
|
"Version": "2012-10-17",
|
|
"Statement": [{
|
|
"Effect": "Allow",
|
|
"Action": [
|
|
"logs:CreateLogGroup",
|
|
"logs:CreateLogStream",
|
|
"logs:PutLogEvents"
|
|
],
|
|
"Resource": "arn:aws:logs:*:*:*"
|
|
},
|
|
{
|
|
"Effect": "Allow",
|
|
"Action": [
|
|
"ec2:CreateNetworkInterface",
|
|
"ec2:DescribeNetworkInterfaces",
|
|
"ec2:DeleteNetworkInterface"
|
|
],
|
|
"Resource": "*"
|
|
},
|
|
{
|
|
"Effect": "Allow",
|
|
"Action": [
|
|
"rds-db:connect",
|
|
"secretsmanager:GetSecretValue"
|
|
],
|
|
"Resource": "*"
|
|
}]
|
|
}`),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set arguments for constructing the function resource.
|
|
args := &lambda.FunctionArgs{
|
|
Handler: pulumi.String("bootstrap"),
|
|
Role: role.Arn,
|
|
Runtime: pulumi.String("provided.al2023"),
|
|
Code: pulumi.NewFileArchive("../../target/lambda/lambda-post-article/bootstrap.zip"),
|
|
Environment: &lambda.FunctionEnvironmentArgs{
|
|
Variables: pulumi.StringMap{
|
|
"DATABASE_URL": cluster.Endpoint,
|
|
},
|
|
},
|
|
VpcConfig: &lambda.FunctionVpcConfigArgs{
|
|
SecurityGroupIds: pulumi.StringArray{
|
|
securityGroup.ID(),
|
|
},
|
|
SubnetIds: subnetIds,
|
|
},
|
|
Layers: pulumi.StringArray{
|
|
layer.Arn,
|
|
},
|
|
}
|
|
|
|
// Create the lambda using the args.
|
|
function, err := lambda.NewFunction(
|
|
ctx,
|
|
"post-article-aurora-pgsql-function",
|
|
args,
|
|
pulumi.DependsOn([]pulumi.Resource{funcPolicy}),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Export the lambda ARN.
|
|
ctx.Export("lambda", function.Arn)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func main() {
|
|
pulumi.Run(func(ctx *pulumi.Context) error {
|
|
|
|
vpc, err := vpc(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sg, err := securityGroup(ctx, vpc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
subA, err := subnetA(ctx, vpc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
subB, err := subnetB(ctx, vpc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cluster, err := cluster(ctx, sg, []*ec2.Subnet{subA, subB})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lambdaFunction(ctx, cluster, sg, []*ec2.Subnet{subA, subB})
|
|
ctx.Export("vpcId", vpc.ID())
|
|
ctx.Export("securityGroupId", sg.ID())
|
|
ctx.Export("clusterEndpoint", cluster.Endpoint)
|
|
|
|
return nil
|
|
|
|
})
|
|
}
|