Skip to content

Commit

Permalink
use consumption to influence topology
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordan Singer committed Nov 21, 2023
1 parent cac1103 commit f6f6b02
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 34 deletions.
17 changes: 17 additions & 0 deletions pkg/engine2/visualizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,23 @@ func HasPath(topo Topology, sol solution_context.SolutionContext, source, target
if len(targetTemplate.PathSatisfaction.AsTarget) == 0 || len(srcTemplate.PathSatisfaction.AsSource) == 0 {
return false, nil
}
sourceRes, err := sol.RawView().Vertex(source)
if err != nil {
return false, fmt.Errorf("has path could not find source resource %s: %w", source, err)
}
targetRes, err := sol.RawView().Vertex(target)
if err != nil {
return false, fmt.Errorf("has path could not find target resource %s: %w", target, err)
}

consumed, err := knowledgebase.HasConsumedFromResource(sourceRes, targetRes,
solution_context.DynamicCtx(sol))
if err != nil {
return false, err
}
if !consumed {
return false, nil
}
return checkPaths(topo, sol, source, target)

}
Expand Down
132 changes: 98 additions & 34 deletions pkg/knowledge_base2/emitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,22 @@ func ConsumeFromResource(consumer, emitter *construct.Resource, ctx DynamicValue
errs = errors.Join(errs, err)
continue
}

pval, _ := consumer.GetProperty(consume.PropertyPath)
if pval == nil {
id := consumer.ID
if consume.Resource != "" {
data := DynamicValueData{Resource: consumer.ID}
err = ctx.ExecuteDecode(consume.Resource, data, &id)
if err != nil {
errs = errors.Join(errs, err)
continue
}
id := consumer.ID
if consume.Resource != "" {
data := DynamicValueData{Resource: consumer.ID}
err = ctx.ExecuteDecode(consume.Resource, data, &id)
if err != nil {
errs = errors.Join(errs, err)
continue
}
}
resource, err := ctx.Graph.Vertex(id)
if err != nil {
errs = errors.Join(errs, err)
continue
}
pval, _ := resource.GetProperty(consume.PropertyPath)
if pval == nil {
if consume.Converter != "" {
val, err = consume.Convert(val, id, ctx)
if err != nil {
Expand All @@ -77,7 +81,7 @@ func ConsumeFromResource(consumer, emitter *construct.Resource, ctx DynamicValue
continue
}

err = consume.Consume(val, ctx, consumer)
err = consume.Consume(val, ctx, resource)
if err != nil {
errs = errors.Join(errs, err)
continue
Expand All @@ -88,6 +92,78 @@ func ConsumeFromResource(consumer, emitter *construct.Resource, ctx DynamicValue
return delays, errs
}

// HasConsumedFromResource returns true if the consumer has consumed from the emitter
// In order to return true, only one of the emitted values has to be set correctly
func HasConsumedFromResource(consumer, emitter *construct.Resource, ctx DynamicValueContext) (bool, error) {
consumerTemplate, err := ctx.KnowledgeBase.GetResourceTemplate(consumer.ID)
if err != nil {
return false, err
}
emitterTemplate, err := ctx.KnowledgeBase.GetResourceTemplate(emitter.ID)
if err != nil {
return false, err
}
noEmittedMatches := true
var errs error
for _, consume := range consumerTemplate.Consumption.Consumed {
for _, emit := range emitterTemplate.Consumption.Emitted {
if consume.Model == emit.Model {
noEmittedMatches = false
val, err := emit.Emit(ctx, emitter.ID)
if err != nil {
errs = errors.Join(errs, err)
continue
}

id := consumer.ID
if consume.Resource != "" {
data := DynamicValueData{Resource: consumer.ID}
err = ctx.ExecuteDecode(consume.Resource, data, &id)
if err != nil {
errs = errors.Join(errs, err)
continue
}
}
resource, err := ctx.Graph.Vertex(id)
if err != nil {
errs = errors.Join(errs, err)
continue
}
pval, _ := resource.GetProperty(consume.PropertyPath)
if pval == nil {
continue
}
if consume.Converter != "" {
val, err = consume.Convert(val, id, ctx)
if err != nil {
errs = errors.Join(errs, err)
continue
}
}
rt, err := ctx.KnowledgeBase.GetResourceTemplate(resource.ID)
if err != nil {
errs = errors.Join(errs, err)
continue
}
prop := rt.GetProperty(consume.PropertyPath)
if prop == nil {
errs = errors.Join(errs, fmt.Errorf("property %s not found", consume.PropertyPath))
continue
}
ptype, err := prop.PropertyType()
if err != nil {
errs = errors.Join(errs, err)
continue
}
if ptype.Contains(pval, val) {
return true, nil
}
}
}
}
return noEmittedMatches, nil
}

func (c *ConsumptionObject) Convert(value any, res construct.ResourceId, ctx DynamicValueContext) (any, error) {
if c.Converter == "" {
return value, fmt.Errorf("no converter specified")
Expand All @@ -109,9 +185,16 @@ func (c *ConsumptionObject) Convert(value any, res construct.ResourceId, ctx Dyn
return value, err
}
bstr := strings.TrimSpace(buf.String())
// We convert here just to make sure it gets translated to the right type of input
// We will convert again when consuming to ensure strings/etc are converted to their respective struct
// if they match a property ref/id/etc
val, err := TransformToPropertyValue(res, c.PropertyPath, bstr, ctx, DynamicValueData{Resource: res})
if err == nil {
return val, nil
if err != nil {
return val, err
}
val, err = TransformToPropertyValue(res, c.PropertyPath, val, ctx, DynamicValueData{Resource: res})
if err != nil {
return val, err
}
return val, nil
}
Expand Down Expand Up @@ -143,26 +226,7 @@ func (c *ConsumptionObject) Emit(ctx DynamicValueContext, resource construct.Res
}

func (c *ConsumptionObject) Consume(val any, ctx DynamicValueContext, resource *construct.Resource) error {
var err error
if c.Resource != "" {
newId := construct.ResourceId{}
data := DynamicValueData{Resource: resource.ID}
err = ctx.ExecuteDecode(c.Resource, data, &newId)
if err != nil {
return err
}
resource, err = ctx.Graph.Vertex(newId)
if err != nil {
return err
}
}
if c.Converter != "" {
val, err = c.Convert(val, resource.ID, ctx)
if err != nil {
return err
}
}
err = resource.SetProperty(c.PropertyPath, val)
err := resource.SetProperty(c.PropertyPath, val)
if err != nil {
return err
}
Expand Down
100 changes: 100 additions & 0 deletions pkg/knowledge_base2/property_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package knowledgebase2
import (
"errors"
"fmt"
"reflect"
"strings"

"github.com/klothoplatform/klotho/pkg/collectionutil"
Expand All @@ -15,6 +16,7 @@ type (
Parse(value any, ctx DynamicContext, data DynamicValueData) (any, error)
SetProperty(property *Property)
ZeroValue() any
Contains(value any, contains any) bool
}

MapPropertyType struct {
Expand Down Expand Up @@ -545,3 +547,101 @@ func (r *ResourcePropertyType) ZeroValue() any {
func (p *PropertyRefPropertyType) ZeroValue() any {
return construct.PropertyRef{}
}

func (m *MapPropertyType) Contains(value any, contains any) bool {
mapVal, ok := value.(map[string]any)
if !ok {
return false
}
containsMap, ok := contains.(map[string]any)
if !ok {
return false
}
for k, v := range containsMap {
if val, found := mapVal[k]; found || reflect.DeepEqual(val, v) {
return true
}
}
for _, v := range mapVal {
for _, cv := range containsMap {
if reflect.DeepEqual(v, cv) {
return true
}
}
}
return false
}

func (l *ListPropertyType) Contains(value any, contains any) bool {
list, ok := value.([]any)
if !ok {
return false
}
containsList, ok := contains.([]any)
if !ok {
return false
}
for _, v := range list {
for _, cv := range containsList {
if reflect.DeepEqual(v, cv) {
return true
}
}
}
return false
}

func (s *SetPropertyType) Contains(value any, contains any) bool {
valSet, ok := value.(set.HashedSet[string, any])
if !ok {
return false
}
containsSet, ok := contains.(set.HashedSet[string, any])
if !ok {
return false
}
for _, v := range containsSet.M {
for _, val := range valSet.M {
if reflect.DeepEqual(v, val) {
return true
}
}
}
return false
}

func (s *StringPropertyType) Contains(value any, contains any) bool {
vString, ok := value.(string)
if !ok {
return false
}
cString, ok := contains.(string)
if !ok {
return false
}
return strings.Contains(vString, cString)
}

func (i *IntPropertyType) Contains(value any, contains any) bool {
return value == contains
}

func (f *FloatPropertyType) Contains(value any, contains any) bool {
return value == contains
}

func (b *BoolPropertyType) Contains(value any, contains any) bool {
return value == contains
}

func (b *AnyPropertyType) Contains(value any, contains any) bool {
return value == contains
}

func (r *ResourcePropertyType) Contains(value any, contains any) bool {
return value == contains
}

func (p *PropertyRefPropertyType) Contains(value any, contains any) bool {
return value == contains
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source: aws:private_dns_namespace
target: aws:ecs_service

classification:
- service_endpoint
5 changes: 5 additions & 0 deletions pkg/templates/aws/resources/ecs_service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,15 @@ consumption:
- model: EnvironmentVariables
property_path: EnvironmentVariables
resource: '{{ fieldValue "TaskDefinition" .Self }}'
emitted:
- model: EnvironmentVariables
value:
'{{ .Self.Name }}_ECS_SERVICE_NAME': '{{ .Self.Name }}'

path_satisfaction:
as_target:
- network
- service_endpoint
as_source:
- network#Subnets

Expand Down

0 comments on commit f6f6b02

Please sign in to comment.