Skip to content

Commit

Permalink
Merge pull request #94 from klothoplatform/fastapi-postgres
Browse files Browse the repository at this point in the history
Postgres Construct, FastAPI + Container -> RDS(postgres) supported
  • Loading branch information
atorres-klo authored Jul 22, 2024
2 parents 1e690aa + b02be34 commit 084a0da
Show file tree
Hide file tree
Showing 23 changed files with 673 additions and 181 deletions.
57 changes: 42 additions & 15 deletions pkg/k2/constructs/construct_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ import (
"context"
"errors"
"fmt"
"github.com/klothoplatform/klotho/pkg/async"
"reflect"
"regexp"
"strconv"
"strings"
"text/template"

"go.uber.org/zap"

"github.com/dominikbraun/graph"
"github.com/klothoplatform/klotho/pkg/async"
"github.com/klothoplatform/klotho/pkg/construct"
"github.com/klothoplatform/klotho/pkg/engine"
"github.com/klothoplatform/klotho/pkg/engine/solution"
Expand All @@ -24,6 +22,7 @@ import (
"github.com/klothoplatform/klotho/pkg/k2/reflectutil"
"github.com/klothoplatform/klotho/pkg/k2/stack"
"github.com/klothoplatform/klotho/pkg/logging"
"go.uber.org/zap"
)

type ConstructEvaluator struct {
Expand Down Expand Up @@ -701,7 +700,7 @@ func (ce *ConstructEvaluator) evaluateBinding(owner *Construct, b *Binding, stat

if b.From != nil && owner.URN.Equals(b.From.GetURN()) {
// only import "to" resources if the binding is from the current construct
if err = ce.importBindingToResources(b, ctx); err != nil {
if err = ce.importBindingToResources(ctx, b); err != nil {
return fmt.Errorf("could not import binding resources: %w", err)
}
}
Expand Down Expand Up @@ -745,6 +744,8 @@ func (ce *ConstructEvaluator) evaluateEdges(c InfraOwner, interpolationCtx Inter
// applyBinding applies the bindings to the construct by merging the resources, edges, and output declarations
// of the construct's bindings with the construct's resources, edges, and output declarations
func (ce *ConstructEvaluator) applyBinding(c *Construct, binding *Binding) error {
log := logging.GetLogger(context.Background()).Sugar()

// Merge resources
for key, bRes := range binding.Resources {
if res, exists := c.Resources[key]; exists {
Expand All @@ -767,18 +768,48 @@ func (ce *ConstructEvaluator) applyBinding(c *Construct, binding *Binding) error
c.OutputDeclarations[key] = output
} else {
// If output already exists, log a warning or handle the conflict as needed
logging.GetLogger(context.Background()).Sugar().Warnf("Output %s already exists in construct, skipping binding output", key)
log.Warnf("Output %s already exists in construct, skipping binding output", key)
}
}

err := c.InitialGraph.AddVerticesFrom(binding.InitialGraph)
// upsert the vertices
ids, err := construct.TopologicalSort(binding.InitialGraph)
if err != nil {
return fmt.Errorf("could not add vertices from binding %s graph: %w", binding, err)
return fmt.Errorf("could not topologically sort binding %s graph: %w", binding, err)
}

err = c.InitialGraph.AddEdgesFrom(binding.InitialGraph)
resources, err := construct.ResolveIds(binding.InitialGraph, ids)
if err != nil {
return fmt.Errorf("could not add edges from binding %s graph: %w", binding, err)
return fmt.Errorf("could not resolve ids from binding %s graph: %w", binding, err)
}

for _, vertex := range resources {
if err := c.InitialGraph.AddVertex(vertex); err != nil {
if errors.Is(err, graph.ErrVertexAlreadyExists) {
log.Debugf("Vertex already exists, skipping: %v", vertex)
continue
}
return fmt.Errorf("could not add vertex %v from binding %s graph: %w", vertex, binding, err)
}
}

// upsert the edges
edges, err := binding.InitialGraph.Edges()
if err != nil {
return fmt.Errorf("could not get edges from binding %s graph: %w", binding, err)
}

for _, edge := range edges {
// Attempt to add the edge to the initial graph
err = c.InitialGraph.AddEdge(edge.Source, edge.Target)
if err != nil {
if errors.Is(err, graph.ErrEdgeAlreadyExists) {
// Skip this edge if it already exists
log.Debugf("Edge already exists, skipping: %v -> %v\n", edge.Source, edge.Target)
continue
}
return fmt.Errorf("could not add edge %v -> %v from binding %s graph: %w", edge.Source, edge.Target, binding, err)
}
}

return nil
Expand Down Expand Up @@ -851,11 +882,7 @@ func (ce *ConstructEvaluator) evaluateInputRule(o InfraOwner, rule InputRuleTemp
return fmt.Errorf("template execution failed: %w", err)
}

boolResult := rawResult.String() != "" && strings.ToLower(rawResult.String()) != "false"
if err != nil {
return fmt.Errorf("result parsing failed: %w", err)
}
executeThen := boolResult
executeThen := rawResult.String() != "" && strings.ToLower(rawResult.String()) != "false"

var body ConditionalExpressionTemplate
if executeThen {
Expand Down Expand Up @@ -1210,7 +1237,7 @@ func (ce *ConstructEvaluator) importResources(o InfraOwner, ctx context.Context)
return nil
}

func (ce *ConstructEvaluator) importBindingToResources(b *Binding, ctx context.Context) error {
func (ce *ConstructEvaluator) importBindingToResources(ctx context.Context, b *Binding) error {
return ce.importFrom(ctx, b, b.To)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
from: klotho.aws.Container
to: klotho.aws.Postgres
type: read
resources:
TaskDefinition:
ContainerDefinitions[0].Environment:
# - ${...from.resources:TaskDefinition.ContainerDefinitions[0].Environment}
- Name: ${to.inputs:Name}_POSTGRES_ENDPOINT
Value: ${to:outputs.Endpoint}
- Name: ${to.inputs:Name}_POSTGRES_DATABASE
Value: ${to:outputs.DatabaseName}
- Name: ${to.inputs:Name}_POSTGRES_USER
Value: ${to:outputs.Username}
- Name: ${to.inputs:Name}_POSTGRES_PASSWORD
Value: ${to:outputs.Password}
- Name: ${to.inputs:Name}_POSTGRES_PORT
Value: ${to:outputs.Port}
- Name: ${to.inputs:Name}_POSTGRES_CONNECTION_STRING
Value: ${to.outputs:ConnectionString}

edges:
- from: ${from.resources:Service}
to: ${to.resources:RDSInstance}
10 changes: 5 additions & 5 deletions pkg/k2/constructs/templates/aws/container/container.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ inputs:
validation:
minLength: 1
maxLength: 63
EnableExecuteCommand:
name: Enable Execute Command
description: Whether to enable the execute command functionality for the container
type: boolean
default: false
EnableExecuteCommand:
name: Enable Execute Command
description: Whether to enable the execute command functionality for the container
type: boolean
default: false
Memory:
name: Memory
description: The amount of memory to allocate to the container
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from: klotho.aws.FastAPI
to: klotho.aws.Postgres

edges:
- from: ${from.resources:Service}
to: ${to.resources:RDSInstance}
119 changes: 87 additions & 32 deletions pkg/k2/constructs/templates/aws/fastapi/fastapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@ resources:
properties:
Cpu: ${inputs:Cpu}
Memory: ${inputs:Memory}
ContainerDefinitions[0].PortMappings:
- ContainerPort: ${inputs:Port}
HostPort: ${inputs:Port}
Protocol: TCP
ContainerDefinitions[0].Cpu: ${inputs:Cpu}
ContainerDefinitions[0].Memory: ${inputs:Memory}
ContainerDefinitions:
- Name: ${inputs:Name}
Cpu: ${inputs:Cpu}
Memory: ${inputs:Memory}
Environment: ${inputs:EnvironmentVariables}
PortMappings:
- ContainerPort: ${inputs:Port}
HostPort: ${inputs:Port}
Protocol: TCP
RequiresCompatibilities:
- FARGATE
Service:
Expand All @@ -41,31 +44,22 @@ resources:
TaskDefinition: ${resources:TaskDefinition}
LoadBalancers[0].ContainerPort: ${inputs:Port}
EnableExecuteCommand: ${inputs:EnableExecuteCommand}

TargetGroup:
type: aws:target_group
name: ${inputs:Name}-tg
properties:
Port: ${inputs:Port}
Protocol: TCP
Vpc: ${inputs:Network.Resources.Vpc}

edges:
- from: Listener
to: TargetGroup

- from: LoadBalancer
to: Service

- from: TargetGroup
to: Service

inputs:
SourceHash:
name: Source Hash
description: The hash of the source code computed by the language SDK to determine if the function has changed and needs to be redeployed
type: string
hidden: true
Cpu:
name: CPU
description: The amount of CPU to allocate to the container
Expand All @@ -74,19 +68,6 @@ inputs:
validation:
minimum: 1
maximum: 4096
EnableExecuteCommand:
name: Enable Execute Command
description: Whether to enable the execute command functionality for the container
type: boolean
default: false
Memory:
name: Memory
description: The amount of memory to allocate to the container
type: number
default: 512
validation:
minimum: 1
maximum: 4096
Context:
name: Context
description: The context to use to build the container
Expand All @@ -103,13 +84,36 @@ inputs:
validation:
minLength: 1
maxLength: 63
EnvironmentVariables:
name: EnvironmentVariables
description: The environment variables to set in the container
type: KeyValueList
configuration:
keyField: Name
Image:
name: Image
description: The image to use for the container
type: string
validation:
minLength: 1
maxLength: 63
EnableExecuteCommand:
name: Enable Execute Command
description: Whether to enable the execute command functionality for the container
type: boolean
default: false
Memory:
name: Memory
description: The amount of memory to allocate to the container
type: number
default: 512
validation:
minimum: 1
maximum: 4096
Network:
name: Network
description: The network to deploy the container to
type: Construct(klotho.aws.Network)
Port:
name: Port
description: The port to expose on the container
Expand All @@ -118,10 +122,26 @@ inputs:
validation:
minimum: 1
maximum: 65535
Network:
name: Network
description: The network to deploy the container to
type: Construct<klotho.aws.Network>
HealthCheckPath:
name: Health Check Path
description: The path to use for the health check
type: string
default: /
HealthCheckMatcher:
name: Health Check Matcher
description: The matcher to use for the health check
type: string
default: 200
HealthCheckHealthyThreshold:
name: Health Check Healthy Threshold
description: The number of consecutive successful health checks required before considering the target healthy
type: number
default: 3
HealthCheckUnhealthyThreshold:
name: Health Check Unhealthy Threshold
description: The number of consecutive failed health checks required before considering the target unhealthy
type: number
default: 3

input_rules:
- if: '{{ and (inputs "Dockerfile") (not (inputs "Image")) }}'
Expand All @@ -142,6 +162,41 @@ input_rules:
properties:
ContainerDefinitions[0].Image: ${inputs:Image}

- if: '{{or (inputs "HealthCheckPath") (inputs "HealthCheckMatcher")}}'
then:
resources:
TargetGroup:
properties:
HealthCheck.Protocol: HTTP

- if: '{{ (inputs "HealthCheckPath")}}'
then:
resources:
TargetGroup:
properties:
HealthCheck.Path: ${inputs:HealthCheckPath}

- if: '{{ (inputs "HealthCheckMatcher")}}'
then:
resources:
TargetGroup:
properties:
HealthCheck.Matcher: ${inputs:HealthCheckMatcher}

- if: '{{ (inputs "HealthCheckHealthyThreshold")}}'
then:
resources:
TargetGroup:
properties:
HealthCheck.HealthyThreshold: ${inputs:HealthCheckHealthyThreshold}

- if: '{{ (inputs "HealthCheckUnhealthyThreshold")}}'
then:
resources:
TargetGroup:
properties:
HealthCheck.UnhealthyThreshold: ${inputs:HealthCheckUnhealthyThreshold}

outputs:
LoadBalancerUrl:
value: ${resources:LoadBalancer#NlbUri}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from: klotho.aws.Container
to: klotho.aws.Postgres

resources:
SecurityGroup:
properties:
IngressRules:
- CidrBlocks:
- ${to.inputs:Network.Resources.PrivateSubnet1#CidrBlock}
- ${to.inputs:Network.Resources.PrivateSubnet2#CidrBlock}
FromPort: 0
Protocol: '-1'
ToPort: 0
Description: Allow ingress traffic from within the default network
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from: klotho.aws.FastAPI
to: klotho.aws.Postgres

resources:
SecurityGroup:
properties:
IngressRules:
- CidrBlocks:
- ${to.inputs:Network.Resources.PrivateSubnet1#CidrBlock}
- ${to.inputs:Network.Resources.PrivateSubnet2#CidrBlock}
FromPort: 0
Protocol: '-1'
ToPort: 0
Description: Allow ingress traffic from within the default network
Loading

0 comments on commit 084a0da

Please sign in to comment.