Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cmd/glad/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ tasks:
cmds:
- go test -v -tags integration ./{{.LAMBDA_PATH}}

test:api:
desc: 'Testing some flows against the real API.
Note: The tests should will run successfully just for the first time. The database should be cleared in order to run them again
This limitation will be handled with the next iterations'
cmds:
- docker compose -f docker-compose.http-test.yml run --rm http-client

cdk:synth:
desc: 'Synthesize app CDK template'
dir: '{{.DEPLOYMENT_PATH}}'
Expand Down
8 changes: 6 additions & 2 deletions cmd/glad/internal/database/constants.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package database

const (
import (
"github.com/hackmajoris/glad-stack/pkg/config"
)

var (
// TableName is the single table for all entities
TableName = "glad-entities"
TableName = config.Load().Database.TableName

GSIBySkill = "BySkill"
)
57 changes: 42 additions & 15 deletions deployments/glad/app_stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/aws/aws-cdk-go/awscdk/v2/awsapigateway"
"github.com/aws/aws-cdk-go/awscdk/v2/awsiam"
"github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
"github.com/aws/aws-cdk-go/awscdk/v2/awslogs"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
Expand All @@ -15,36 +16,58 @@ type AppStackProps struct {
awscdk.StackProps
}

func NewAppStack(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack {
func NewAppStack(scope constructs.Construct, id string, props *AppStackProps, env string) awscdk.Stack {
var sprops awscdk.StackProps

if props != nil {
sprops = props.StackProps
}

stack := awscdk.NewStack(scope, &id, &sprops)

ENVIRONMENT := "production"
awscdk.Tags_Of(stack).Add(jsii.String("Environment"), jsii.String(ENVIRONMENT), nil)
awscdk.Tags_Of(stack).Add(jsii.String("Environment"), jsii.String(env), nil)

gladFunc := createLambdaResource(stack, id, env)
createApiGatewayResource(stack, id, gladFunc, env)

return stack
}

func createLambdaResource(stack awscdk.Stack, id string, env string) awslambda.Function {

// Import table from database stack
tableName := awscdk.Fn_ImportValue(jsii.String("GladTableName"))
tableArn := awscdk.Fn_ImportValue(jsii.String("GladTableArn"))
tableName := awscdk.Fn_ImportValue(jsii.String("GladTableName-" + env))
tableArn := awscdk.Fn_ImportValue(jsii.String("GladTableArn-" + env))

getResourceName := func(input string) *string {
return jsii.String(input + "-" + env)
}

// Configure log retention via custom resource
funcLogGrop := awslogs.NewLogGroup(stack, jsii.String(id+"-log-group"), &awslogs.LogGroupProps{
LogGroupName: getResourceName("glad-function-log-group"),
Retention: awslogs.RetentionDays_ONE_DAY,
RemovalPolicy: awscdk.RemovalPolicy_DESTROY,
})

// Create Lambda using Docker image
myFunc := awslambda.NewDockerImageFunction(stack, jsii.String(id+"-go-func"), &awslambda.DockerImageFunctionProps{
gladFunc := awslambda.NewDockerImageFunction(stack, jsii.String(id+"-go-func"), &awslambda.DockerImageFunctionProps{
Code: awslambda.DockerImageCode_FromImageAsset(jsii.String("../../"), &awslambda.AssetImageCodeProps{
File: jsii.String("Dockerfile.lambda"),
}),
FunctionName: getResourceName("glad-function"),
Timeout: awscdk.Duration_Seconds(jsii.Number(30)),
MemorySize: jsii.Number(512),
Description: jsii.String("GLAD Lambda function using Docker image"),
Architecture: awslambda.Architecture_X86_64(),
LogGroup: funcLogGrop,
})

myFunc.AddEnvironment(jsii.String("ENVIRONMENT"), jsii.String(ENVIRONMENT), nil)
myFunc.AddEnvironment(jsii.String("DYNAMODB_TABLE"), tableName, nil)
gladFunc.AddEnvironment(jsii.String("ENVIRONMENT"), jsii.String(env), nil)
gladFunc.AddEnvironment(jsii.String("DYNAMODB_TABLE"), tableName, nil)

// Grant Lambda access to DynamoDB table
myFunc.AddToRolePolicy(awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
gladFunc.AddToRolePolicy(awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
Effect: awsiam.Effect_ALLOW,
Actions: jsii.Strings(
"dynamodb:PutItem",
Expand All @@ -60,8 +83,13 @@ func NewAppStack(scope constructs.Construct, id string, props *AppStackProps) aw
),
}))

api := awsapigateway.NewRestApi(stack, jsii.String(id+"-api-gateway"), &awsapigateway.RestApiProps{
RestApiName: jsii.String("glad-api gateway"),
return gladFunc

}

func createApiGatewayResource(stack awscdk.Stack, id string, gladFunc awslambda.DockerImageFunction, env string) {
api := awsapigateway.NewRestApi(stack, jsii.String(id+"-api-gateway-"+env), &awsapigateway.RestApiProps{
RestApiName: jsii.String("glad-api-gateway-" + env),
Description: jsii.String("GLAD Stack API"),
Deploy: jsii.Bool(false),
CloudWatchRole: jsii.Bool(true),
Expand All @@ -73,12 +101,12 @@ func NewAppStack(scope constructs.Construct, id string, props *AppStackProps) aw
},
})

integration := awsapigateway.NewLambdaIntegration(myFunc, &awsapigateway.LambdaIntegrationOptions{
integration := awsapigateway.NewLambdaIntegration(gladFunc, &awsapigateway.LambdaIntegrationOptions{
Proxy: jsii.Bool(true),
})

// Add single wildcard permission for all API Gateway methods
myFunc.AddPermission(jsii.String("ApiGatewayInvoke"), &awslambda.Permission{
gladFunc.AddPermission(jsii.String("ApiGatewayInvoke"), &awslambda.Permission{
Principal: awsiam.NewServicePrincipal(jsii.String("apigateway.amazonaws.com"), nil),
Action: jsii.String("lambda:InvokeFunction"),
SourceArn: jsii.String(fmt.Sprintf("arn:aws:execute-api:%s:%s:%s/*/*",
Expand Down Expand Up @@ -172,7 +200,7 @@ func NewAppStack(scope constructs.Construct, id string, props *AppStackProps) aw
Api: api,
Description: jsii.String("Deployment triggered by Lambda changes"),
})
deployment.Node().AddDependency(myFunc)
deployment.Node().AddDependency(gladFunc)

// Create stage with fixed logical ID
stage := awsapigateway.NewStage(stack, jsii.String(id+"-api-stage"), &awsapigateway.StageProps{
Expand Down Expand Up @@ -208,5 +236,4 @@ func NewAppStack(scope constructs.Construct, id string, props *AppStackProps) aw
ExportName: jsii.String("GladApiUrl"),
})

return stack
}
12 changes: 6 additions & 6 deletions deployments/glad/database_stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ type DatabaseStackProps struct {
awscdk.StackProps
}

func NewDatabaseStack(scope constructs.Construct, id string, props *DatabaseStackProps) awscdk.Stack {
func NewDatabaseStack(scope constructs.Construct, id string, props *DatabaseStackProps, env string) awscdk.Stack {
var sprops awscdk.StackProps

if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)

ENVIRONMENT := "production"
awscdk.Tags_Of(stack).Add(jsii.String("Environment"), jsii.String(ENVIRONMENT), nil)
awscdk.Tags_Of(stack).Add(jsii.String("Environment"), jsii.String(env), nil)

// Create DynamoDB table
entitiesTable := awsdynamodb.NewTableV2(stack, jsii.String(id+"-entities-table"), &awsdynamodb.TablePropsV2{
TableName: jsii.String("glad-entities"),
TableName: jsii.String("glad-entities-" + env),
PartitionKey: &awsdynamodb.Attribute{
Name: jsii.String("EntityType"),
Type: awsdynamodb.AttributeType_STRING,
Expand Down Expand Up @@ -78,13 +78,13 @@ func NewDatabaseStack(scope constructs.Construct, id string, props *DatabaseStac
awscdk.NewCfnOutput(stack, jsii.String("TableName"), &awscdk.CfnOutputProps{
Value: entitiesTable.TableName(),
Description: jsii.String("DynamoDB table name"),
ExportName: jsii.String("GladTableName"),
ExportName: jsii.String("GladTableName-" + env),
})

awscdk.NewCfnOutput(stack, jsii.String("TableArn"), &awscdk.CfnOutputProps{
Value: entitiesTable.TableArn(),
Description: jsii.String("DynamoDB table ARN"),
ExportName: jsii.String("GladTableArn"),
ExportName: jsii.String("GladTableArn-" + env),
})

return stack
Expand Down
14 changes: 10 additions & 4 deletions deployments/glad/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,25 @@ func main() {

app := awscdk.NewApp(nil)

ENVIRONMENT := "production"

getResourceId := func(input string) string {
return input + "-" + ENVIRONMENT
}

// Create database stack first
NewDatabaseStack(app, "glad-database-stack", &DatabaseStackProps{
NewDatabaseStack(app, getResourceId("glad-database-stack"), &DatabaseStackProps{
awscdk.StackProps{
Env: env(),
},
})
}, ENVIRONMENT)

// Create application stack (depends on database stack)
NewAppStack(app, "glad-app-stack", &AppStackProps{
NewAppStack(app, getResourceId("glad-app-stack"), &AppStackProps{
awscdk.StackProps{
Env: env(),
},
})
}, ENVIRONMENT)

app.Synth(nil)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func Load() *Config {
SigningAlg: getEnv("JWT_SIGNING_ALG", "HS256"),
},
Database: DatabaseConfig{
TableName: getEnv("DYNAMODB_TABLE", "users"),
TableName: getEnv("DYNAMODB_TABLE", "entities-table"),
Region: getEnv("AWS_REGION", "us-east-1"),
},

Expand Down
Loading