Skip to content

Commit

Permalink
add alb support (#792)
Browse files Browse the repository at this point in the history
  • Loading branch information
jhsinger-klotho authored Nov 28, 2023
1 parent fd6754b commit 7654a53
Show file tree
Hide file tree
Showing 31 changed files with 236 additions and 31 deletions.
21 changes: 14 additions & 7 deletions pkg/engine2/operational_eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (eval *Evaluator) Evaluate() error {
evaluated := make(set.Set[Key])
eval.evaluatedOrder = append(eval.evaluatedOrder, evaluated)

ready, err := eval.popReady()
ready, err := eval.pollReady()
if err != nil {
return err
}
Expand All @@ -39,14 +39,25 @@ func (eval *Evaluator) Evaluate() error {
var errs error
for _, v := range ready {
k := v.Key()
_, err := eval.unevaluated.Vertex(k)
switch {
case err != nil && !errors.Is(err, graph.ErrVertexNotFound):
errs = errors.Join(errs, err)
continue
case errors.Is(err, graph.ErrVertexNotFound):
// vertex was removed by earlier ready vertex
continue
}
log.Debugf("Evaluating %s", k)
evaluated.Add(k)
eval.currentKey = &k
err := v.Evaluate(eval)
err = v.Evaluate(eval)
if err != nil {
eval.errored.Add(k)
errs = errors.Join(errs, fmt.Errorf("failed to evaluate %s: %w", k, err))
}
errs = errors.Join(errs, graph_addons.RemoveVertexAndEdges(eval.unevaluated, v.Key()))

}
if errs != nil {
return fmt.Errorf("failed to evaluate group %d: %w", len(eval.evaluatedOrder), errs)
Expand All @@ -58,7 +69,7 @@ func (eval *Evaluator) Evaluate() error {
}
}

func (eval *Evaluator) popReady() ([]Vertex, error) {
func (eval *Evaluator) pollReady() ([]Vertex, error) {
log := eval.Log().With("op", "dequeue")
adj, err := eval.unevaluated.AdjacencyMap()
if err != nil {
Expand Down Expand Up @@ -118,10 +129,6 @@ func (eval *Evaluator) popReady() ([]Vertex, error) {
return a.Less(b)
})

for _, v := range ready {
errs = errors.Join(errs, graph_addons.RemoveVertexAndEdges(eval.unevaluated, v.Key()))
}

return ready, errs
}

Expand Down
5 changes: 1 addition & 4 deletions pkg/engine2/operational_eval/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,8 @@ func (eval *Evaluator) edgeVertices(

func (eval *Evaluator) removeKey(k Key) error {
err := graph_addons.RemoveVertexAndEdges(eval.unevaluated, k)
if err == nil {
if err == nil || errors.Is(err, graph.ErrVertexNotFound) {
return graph_addons.RemoveVertexAndEdges(eval.graph, k)
} else if errors.Is(err, graph.ErrVertexNotFound) {
// the key was already evaluated, leave it in the graph for debugging purposes
return nil
}
return err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/engine2/operational_rule/operational_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (ctx OperationalRuleContext) HandleConfigurationRule(config knowledgebase.C
return err
}
prop := resTempalte.GetProperty(config.Config.Field)
if prop != nil && (strings.Contains(prop.Type, "list") || strings.Contains(prop.Type, "set") || strings.Contains(prop.Type, "map")) {
if prop != nil && (strings.HasPrefix(prop.Type, "list") || strings.HasPrefix(prop.Type, "set") || strings.HasPrefix(prop.Type, "map")) {
action = "add"
}
}
Expand Down
27 changes: 27 additions & 0 deletions pkg/engine2/operational_rule/operational_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"

"github.com/dominikbraun/graph"
construct "github.com/klothoplatform/klotho/pkg/construct2"
"github.com/klothoplatform/klotho/pkg/engine2/reconciler"
"github.com/klothoplatform/klotho/pkg/engine2/solution_context"
Expand Down Expand Up @@ -110,6 +111,10 @@ func (ctx OperationalRuleContext) CleanProperty(rule knowledgebase.OperationalRu
if err != nil {
return err
}
err = ForceRemoveDependency(ctx.Data.Resource, prop, ctx.Solution)
if err != nil {
return err
}
return reconciler.RemoveResource(ctx.Solution, prop, false)

case []construct.ResourceId:
Expand Down Expand Up @@ -137,6 +142,7 @@ func (ctx OperationalRuleContext) CleanProperty(rule knowledgebase.OperationalRu
var errs error
for rem := range toRemove {
log.Infof("removing %s, does not match selectors", prop)
errs = errors.Join(errs, ForceRemoveDependency(ctx.Data.Resource, rem, ctx.Solution))
errs = errors.Join(errs, reconciler.RemoveResource(ctx.Solution, rem, false))
}

Expand Down Expand Up @@ -174,6 +180,7 @@ func (ctx OperationalRuleContext) CleanProperty(rule knowledgebase.OperationalRu
var errs error
for rem := range toRemove {
log.Infof("removing %s, does not match selectors", prop)
errs = errors.Join(errs, ForceRemoveDependency(ctx.Data.Resource, rem, ctx.Solution))
errs = errors.Join(errs, reconciler.RemoveResource(ctx.Solution, rem, false))
}

Expand All @@ -190,6 +197,10 @@ func (ctx OperationalRuleContext) CleanProperty(rule knowledgebase.OperationalRu
if err != nil {
return err
}
err = ForceRemoveDependency(ctx.Data.Resource, prop.Resource, ctx.Solution)
if err != nil {
return err
}
return reconciler.RemoveResource(ctx.Solution, prop.Resource, false)
}

Expand All @@ -212,3 +223,19 @@ func EvaluateIfCondition(
}
return result, nil
}

func ForceRemoveDependency(
res1, res2 construct.ResourceId,
sol solution_context.SolutionContext,
) error {

err := sol.RawView().RemoveEdge(res1, res2)
if err != nil && !errors.Is(err, graph.ErrEdgeNotFound) {
return err
}
err = sol.RawView().RemoveEdge(res2, res1)
if err != nil && !errors.Is(err, graph.ErrEdgeNotFound) {
return err
}
return nil
}
9 changes: 9 additions & 0 deletions pkg/infra/iac3/templates/aws/acm_certificate/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as aws from '@pulumi/aws'

interface Args {
Name: string
}

function create(args: Args): aws.acm.Certificate {
return new aws.acm.Certificate(args.Name, {})
}
6 changes: 6 additions & 0 deletions pkg/infra/iac3/templates/aws/acm_certificate/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "ami",
"dependencies": {
"@pulumi/aws": "^5.37.0"
}
}
15 changes: 15 additions & 0 deletions pkg/infra/iac3/templates/aws/listener_certificate/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as aws from '@pulumi/aws'

interface Args {
Name: string
Listener: aws.lb.Listener
Certificate: aws.acm.Certificate
}

// noinspection JSUnusedLocalSymbols
function create(args: Args): aws.lb.LoadBalancer {
return new aws.lb.ListenerCertificate('exampleListenerCertificate', {
listenerArn: args.Listener.arn,
certificateArn: args.Certificate.arn,
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "load_balancer",
"dependencies": {
"@pulumi/aws": "^5.37.0"
}
}
16 changes: 15 additions & 1 deletion pkg/infra/iac3/templates/aws/load_balancer/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ interface Args {
// noinspection JSUnusedLocalSymbols
function create(args: Args): aws.lb.LoadBalancer {
return new aws.lb.LoadBalancer(args.Name, {
internal: args.Scheme == 'internal',
//TMPL {{- if eq .Scheme "internal" }}
internal: true,
//TMPL {{- else }}
internal: false,
//TMPL {{- end }}
loadBalancerType: args.Type,
subnets: args.Subnets.map((subnet) => subnet.id),
//TMPL {{- if .Tags }}
Expand All @@ -31,3 +35,13 @@ function properties(object: aws.lb.LoadBalancer, args: Args) {
NlbUri: pulumi.interpolate`http://${object.dnsName}`,
}
}

function infraExports(
object: ReturnType<typeof create>,
args: Args,
props: ReturnType<typeof properties>
) {
return {
DomainName: object.dnsName,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source: aws:listener_certificate
target: aws:acm_certificate

unique:
source: true
13 changes: 13 additions & 0 deletions pkg/templates/aws/edges/load_balancer-load_balancer_listener.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
source: aws:load_balancer
target: aws:load_balancer_listener
deployment_order_reversed: true
operational_rules:
- if: '{{eq (fieldValue "Type" .Source) "application"}}'
configuration_rules:
- resource: '{{ .Target }}'
configuration:
field: Protocol
value: HTTP
- if: '{{ eq (fieldValue "Type" .Source) "network" }}'
configuration_rules:
- resource: '{{ .Target }}'
configuration:
field: Protocol
value: TCP
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
source: aws:load_balancer_listener
target: aws:listener_certificate
deployment_order_reversed: true
operational_rules:
- configuration_rules:
- resource: '{{ .Target }}'
configuration:
field: Listener
value: '{{ .Source }}'

unique:
source: true
target: true
12 changes: 10 additions & 2 deletions pkg/templates/aws/edges/load_balancer_listener-target_group.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@ source: aws:load_balancer_listener
target: aws:target_group
operational_rules:
- configuration_rules:
- resource: '{{ .Source }}'
- resource: '{{ .Target }}'
configuration:
field: Protocol
value: '{{ fieldValue "Protocol" .Target }}'
value: '{{ fieldValue "Protocol" .Source }}'
- resource: '{{ .Source }}'
configuration:
field: DefaultActions
value:
- TargetGroup: '{{ .Target }}'
Type: forward

- if: '{{eq (fieldValue "Protocol" .Source) "HTTPS"}}'
steps:
- resource: '{{ .Source }}'
direction: downstream
resources:
- aws:listener_certificate

classification:
- target
15 changes: 14 additions & 1 deletion pkg/templates/aws/edges/security_group-load_balancer.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
source: aws:security_group
target: aws:load_balancer
deployment_order_reversed: true
deployment_order_reversed: true
operational_rules:
- if: '{{ eq (fieldValue "Scheme" .Target) "internet-facing"}}'
configuration_rules:
- resource: '{{ .Source }}'
configuration:
field: IngressRules
value:
- Description: Allow ingress traffic from within the same security group
FromPort: 0
Protocol: '-1'
ToPort: 0
CidrBlocks:
- 0.0.0.0/0
11 changes: 11 additions & 0 deletions pkg/templates/aws/resources/acm_certificate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
qualified_type_name: aws:acm_certificate
display_name: ACM Certificate

classification:
is:
- certificate

delete_context:
requires_no_upstream: true
views:
dataflow: small
2 changes: 1 addition & 1 deletion pkg/templates/aws/resources/ami.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ classification:
- machine_image

delete_context:
require_no_upstream: true
requires_no_upstream: true
views:
dataflow: small
2 changes: 1 addition & 1 deletion pkg/templates/aws/resources/ecs_task_definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,6 @@ consumption:
property_path: EnvironmentVariables

delete_context:
require_no_upstream: true
requires_no_upstream: true
views:
dataflow: small
21 changes: 21 additions & 0 deletions pkg/templates/aws/resources/listener_certificate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
qualified_type_name: aws:listener_certificate
display_name: Listener Certificate

properties:
Certificate:
type: resource(aws:acm_certificate)
operational_rule:
steps:
- direction: downstream
resources:
- aws:acm_certificate
required: true
Listener:
type: resource(aws:load_balancer_listener)
required: true


delete_context:
requires_no_upstream_or_downstream: true
views:
dataflow: small
15 changes: 13 additions & 2 deletions pkg/templates/aws/resources/load_balancer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ properties:
# which is required for secure connectivity from an API Gateway VPC Link.
# See: https://github.com/hashicorp/terraform-provider-aws/pull/33767
type: list(resource(aws:security_group))
operational_rule:
if: '{{ fieldValue "Scheme" .Self | eq "internet-facing" }}'
steps:
- direction: upstream
resources:
- aws:security_group
unique: true
Subnets:
type: list(resource(aws:subnet))
operational_rule:
Expand All @@ -37,8 +44,12 @@ properties:
resources:
- selector: aws:subnet
properties:
Type: private
- aws:subnet
Type: |
{{- if eq (fieldValue "Scheme" .Self) "internet-facing"}}
public
{{- else}}
private
{{- end}}
num_needed: 2
Tags:
type: map(string,string)
Expand Down
1 change: 0 additions & 1 deletion pkg/templates/aws/resources/load_balancer_listener.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ properties:
default_value: 80
Protocol:
type: string
default_value: TCP
LoadBalancer:
type: resource(aws:load_balancer)
default_value: '{{ upstream "aws:load_balancer" .Self }}'
Expand Down
Loading

0 comments on commit 7654a53

Please sign in to comment.