diff --git a/fixtures/k8s/kubernetes_bundle.yaml b/fixtures/k8s/kubernetes_bundle.yaml index db09368a1..6a2ed1d66 100644 --- a/fixtures/k8s/kubernetes_bundle.yaml +++ b/fixtures/k8s/kubernetes_bundle.yaml @@ -16,7 +16,7 @@ spec: 'pass': k8s.is_healthy(r.Object), 'message': k8s.health(r.Object).message, 'error': k8s.health(r.Object).message, - }).marshalJSON() + }).toJSON() - kind: Pod ready: true name: pod-bundle @@ -28,4 +28,4 @@ spec: 'pass': k8s.is_healthy(r.Object), 'message': k8s.health(r.Object).message, 'error': k8s.health(r.Object).message, - }).marshalJSON() + }).toJSON() diff --git a/fixtures/topology/component-with-for-each.yml b/fixtures/topology/component-with-for-each.yml new file mode 100644 index 000000000..45b7a4857 --- /dev/null +++ b/fixtures/topology/component-with-for-each.yml @@ -0,0 +1,75 @@ +apiVersion: canaries.flanksource.com/v1 +kind: Topology +metadata: + name: test-topology-for-each +spec: + schedule: "@every 10m" + components: + - name: GroupA + type: virtual + icon: server + lookup: + http: + - endpoint: https://httpbin.demo.aws.flanksource.com/status/200 + name: http-lookup + display: + expr: | + [ + { + 'name': 'component-a', + 'type': 'API', + 'properties': [{'name': 'owner', 'text': 'team-a'}, {'name': 'processor'}] + }, + { + 'name': 'component-b', + 'type': 'Frontend', + 'properties': [{'name': 'owner', 'text': 'team-b'}, {'name': 'processor'}] + }, + { + 'name': 'component-c', + 'type': 'Database', + 'properties': [{'name': 'owner', 'text': 'team-b'}, {'name': 'processor'}] + }, + ].toJSON() + forEach: + configs: + - name: ${.component.name} + type: Service + components: + - name: Child-A + - name: Child-B + properties: + # Test property lookup merge as components + - name: processor + lookup: + http: + - endpoint: https://httpbin.demo.aws.flanksource.com/status/200 + name: processor_lookup + display: + expr: | + [ + { + 'name': 'component-a', + 'properties': [{'name': 'processor', 'text': 'intel'}] + }, + { + 'name': 'component-b', + 'properties': [{'name': 'processor', 'text': 'intel'}] + }, + { + 'name': 'component-c', + 'properties': [{'name': 'processor', 'text': 'amd'}] + }, + ].toJSON() + # Test property lookup merge as properties + - name: generic + lookup: + http: + - endpoint: https://httpbin.demo.aws.flanksource.com/status/200 + name: generic_lookup + display: + expr: | + [ + {'name': 'company', 'text': 'Acme'}, + {'name': 'location', 'text': 'Mars'}, + ].toJSON() diff --git a/fixtures/topology/component-with-properties.yml b/fixtures/topology/component-with-properties.yml index af3c61d8f..14ee91f57 100644 --- a/fixtures/topology/component-with-properties.yml +++ b/fixtures/topology/component-with-properties.yml @@ -1,4 +1,3 @@ -#yaml-language-server: $schema=../../generate-schemas/schemas/system.schema.json apiVersion: canaries.flanksource.com/v1 kind: Topology metadata: @@ -31,7 +30,7 @@ spec: 'type': 'Database', 'properties': [{'name': 'error_percentage', 'min': 0, 'max': 100}, {'name': 'owner'}] }, - ].marshalJSON() + ].toJSON() properties: # Test property lookup merge as components - name: error_percentage @@ -54,7 +53,7 @@ spec: 'name': 'component-c', 'properties': [{'name': 'error_percentage', 'value': 50}] }, - ].marshalJSON() + ].toJSON() # Test property lookup merge as components - name: owner lookup: @@ -76,7 +75,7 @@ spec: 'name': 'component-c', 'properties': [{'name': 'owner', 'text': 'team-b'}] }, - ].marshalJSON() + ].toJSON() # Test property lookup merge as properties - name: generic lookup: @@ -88,4 +87,4 @@ spec: [ {'name': 'company', 'text': 'Acme'}, {'name': 'location', 'text': 'Mars'}, - ].marshalJSON() + ].toJSON() diff --git a/go.mod b/go.mod index dceccaf3e..42763adad 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/fergusstrange/embedded-postgres v1.24.0 github.com/flanksource/commons v1.12.0 github.com/flanksource/duty v1.0.191 - github.com/flanksource/gomplate/v3 v3.20.14 + github.com/flanksource/gomplate/v3 v3.20.16 github.com/flanksource/is-healthy v0.0.0-20231003215854-76c51e3a3ff7 github.com/flanksource/kommons v0.31.4 github.com/friendsofgo/errors v0.9.2 diff --git a/go.sum b/go.sum index 91ef3979c..3396d5fc5 100644 --- a/go.sum +++ b/go.sum @@ -824,8 +824,8 @@ github.com/flanksource/commons v1.12.0/go.mod h1:zYEhi6E2+diQ+loVcROUHo/Bgv+Tn61 github.com/flanksource/duty v1.0.191 h1:acnvyTeQlfqmtyXxWprNFGK/vBTUlqkYwxEPLtXSPrk= github.com/flanksource/duty v1.0.191/go.mod h1:ikyl/TcRy6Cc0R5b0wEHT7CecV7gyJvrDGq/4oIZHoc= github.com/flanksource/gomplate/v3 v3.20.4/go.mod h1:27BNWhzzSjDed1z8YShO6W+z6G9oZXuxfNFGd/iGSdc= -github.com/flanksource/gomplate/v3 v3.20.14 h1:mtxwRbBaAwGr35T2OxCaXFEqovfyMGZ6vFjDJFk625I= -github.com/flanksource/gomplate/v3 v3.20.14/go.mod h1:1N1aptaAo0XUaGsyU5CWiwn9GMRpbIKX1AdsypfmZYo= +github.com/flanksource/gomplate/v3 v3.20.16 h1:Bfn+nbD0iK0iGQcu6alV8Nr7O5+KpeDo8OD9WOu831Q= +github.com/flanksource/gomplate/v3 v3.20.16/go.mod h1:2GgHZ2vWmtDspJMBfUIryOuzJSwc8jU7Kw9fDLr0TMA= github.com/flanksource/is-healthy v0.0.0-20230705092916-3b4cf510c5fc/go.mod h1:4pQhmF+TnVqJroQKY8wSnSp+T18oLson6YQ2M0qPHfQ= github.com/flanksource/is-healthy v0.0.0-20231003215854-76c51e3a3ff7 h1:s6jf6P1pRfdvksVFjIXFRfnimvEYUR0/Mmla1EIjiRM= github.com/flanksource/is-healthy v0.0.0-20231003215854-76c51e3a3ff7/go.mod h1:BH5gh9JyEAuuWVP6Q5y9h43VozS0RfKyjNpM9L4v4hw= diff --git a/hack/generate-schemas/go.mod b/hack/generate-schemas/go.mod index b209e6cb4..38bce9949 100644 --- a/hack/generate-schemas/go.mod +++ b/hack/generate-schemas/go.mod @@ -13,7 +13,7 @@ require ( cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/iam v1.1.2 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/flanksource/gomplate/v3 v3.20.14 // indirect + github.com/flanksource/gomplate/v3 v3.20.16 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect diff --git a/hack/generate-schemas/go.sum b/hack/generate-schemas/go.sum index db996fb45..789121f44 100644 --- a/hack/generate-schemas/go.sum +++ b/hack/generate-schemas/go.sum @@ -706,8 +706,8 @@ github.com/flanksource/commons v1.12.0/go.mod h1:zYEhi6E2+diQ+loVcROUHo/Bgv+Tn61 github.com/flanksource/duty v1.0.191 h1:acnvyTeQlfqmtyXxWprNFGK/vBTUlqkYwxEPLtXSPrk= github.com/flanksource/duty v1.0.191/go.mod h1:ikyl/TcRy6Cc0R5b0wEHT7CecV7gyJvrDGq/4oIZHoc= github.com/flanksource/gomplate/v3 v3.20.4/go.mod h1:27BNWhzzSjDed1z8YShO6W+z6G9oZXuxfNFGd/iGSdc= -github.com/flanksource/gomplate/v3 v3.20.14 h1:mtxwRbBaAwGr35T2OxCaXFEqovfyMGZ6vFjDJFk625I= -github.com/flanksource/gomplate/v3 v3.20.14/go.mod h1:1N1aptaAo0XUaGsyU5CWiwn9GMRpbIKX1AdsypfmZYo= +github.com/flanksource/gomplate/v3 v3.20.16 h1:Bfn+nbD0iK0iGQcu6alV8Nr7O5+KpeDo8OD9WOu831Q= +github.com/flanksource/gomplate/v3 v3.20.16/go.mod h1:2GgHZ2vWmtDspJMBfUIryOuzJSwc8jU7Kw9fDLr0TMA= github.com/flanksource/is-healthy v0.0.0-20230705092916-3b4cf510c5fc/go.mod h1:4pQhmF+TnVqJroQKY8wSnSp+T18oLson6YQ2M0qPHfQ= github.com/flanksource/is-healthy v0.0.0-20231003215854-76c51e3a3ff7 h1:s6jf6P1pRfdvksVFjIXFRfnimvEYUR0/Mmla1EIjiRM= github.com/flanksource/is-healthy v0.0.0-20231003215854-76c51e3a3ff7/go.mod h1:BH5gh9JyEAuuWVP6Q5y9h43VozS0RfKyjNpM9L4v4hw= diff --git a/pkg/topology/run.go b/pkg/topology/run.go index c3669d2c0..7395dafa5 100644 --- a/pkg/topology/run.go +++ b/pkg/topology/run.go @@ -85,19 +85,6 @@ func forEachComponent(ctx *ComponentContext, spec *v1.ComponentSpec, component * if err := mergeComponentProperties(pkg.Components{component}, props); err != nil { continue } - - var properties pkg.Properties - if err := json.Unmarshal(props, &properties); err != nil { - return err - } - for _, p := range properties { - found := component.Properties.Find(p.Name) - if found != nil { - found.Merge(p) - continue - } - component.Properties = append(component.Properties, p) - } } ctx.SetCurrentComponent(component) // component properties may have changed diff --git a/pkg/topology/run_test.go b/pkg/topology/run_test.go index 3df038b00..88e56fe77 100644 --- a/pkg/topology/run_test.go +++ b/pkg/topology/run_test.go @@ -53,4 +53,49 @@ var _ = ginkgo.Describe("Test topology run", ginkgo.Ordered, func() { Expect(string(componentB.Properties.AsJSON())).To(MatchJSON(`[{"name":"error_percentage","value":10,"min":0,"max":100},{"name":"owner","text":"team-b"},{"name":"company","text":"Acme"},{"name":"location","text":"Mars"}]`)) Expect(string(componentC.Properties.AsJSON())).To(MatchJSON(`[{"name":"error_percentage","value":50,"min":0,"max":100},{"name":"owner","text":"team-b"},{"name":"company","text":"Acme"},{"name":"location","text":"Mars"}]`)) }) + + ginkgo.It("should create component with forEach functionality", func() { + t, err := yamlFileToTopology("../../fixtures/topology/component-with-for-each.yml") + if err != nil { + ginkgo.Fail("Error converting yaml to v1.Topology:" + err.Error()) + } + + rootComponent := Run(opts, t) + Expect(len(rootComponent[0].Components)).To(Equal(3)) + + componentA := rootComponent[0].Components[0] + componentB := rootComponent[0].Components[1] + componentC := rootComponent[0].Components[2] + + // Test correct merging of properties + Expect(string(componentA.Properties.AsJSON())).To(MatchJSON(`[{"name":"owner","text":"team-a"},{"name":"processor","text":"intel"},{"name":"company","text":"Acme"},{"name":"location","text":"Mars"}]`)) + Expect(string(componentB.Properties.AsJSON())).To(MatchJSON(`[{"name":"owner","text":"team-b"},{"name":"processor","text":"intel"},{"name":"company","text":"Acme"},{"name":"location","text":"Mars"}]`)) + Expect(string(componentC.Properties.AsJSON())).To(MatchJSON(`[{"name":"owner","text":"team-b"},{"name":"processor","text":"amd"},{"name":"company","text":"Acme"},{"name":"location","text":"Mars"}]`)) + + // Each component should have 2 children named Child-A and Child-B + Expect(len(componentA.Components)).To(Equal(2)) + Expect(componentA.Components[0].Name).To(Equal("Child-A")) + Expect(componentA.Components[1].Name).To(Equal("Child-B")) + + Expect(len(componentB.Components)).To(Equal(2)) + Expect(componentB.Components[0].Name).To(Equal("Child-A")) + Expect(componentB.Components[1].Name).To(Equal("Child-B")) + + Expect(len(componentC.Components)).To(Equal(2)) + Expect(componentC.Components[0].Name).To(Equal("Child-A")) + Expect(componentC.Components[1].Name).To(Equal("Child-B")) + + // Each component should have a templated config linked + Expect(len(componentA.Configs)).To(Equal(1)) + Expect(componentA.Configs[0].Name).To(Equal(componentA.Name)) + Expect(componentA.Configs[0].Type).To(Equal("Service")) + + Expect(len(componentB.Configs)).To(Equal(1)) + Expect(componentB.Configs[0].Name).To(Equal(componentB.Name)) + Expect(componentB.Configs[0].Type).To(Equal("Service")) + + Expect(len(componentC.Configs)).To(Equal(1)) + Expect(componentC.Configs[0].Name).To(Equal(componentC.Name)) + Expect(componentC.Configs[0].Type).To(Equal("Service")) + }) })