Skip to content

Commit

Permalink
Merge pull request #1585 from flanksource/field-selector-refactor
Browse files Browse the repository at this point in the history
refactor: component selector logic
  • Loading branch information
moshloop authored Jan 15, 2024
2 parents b126476 + 91aa38b commit b9c6ace
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 38 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ require (
github.com/fergusstrange/embedded-postgres v1.25.0
github.com/flanksource/artifacts v1.0.4
github.com/flanksource/commons v1.20.0
github.com/flanksource/duty v1.0.280
github.com/flanksource/duty v1.0.287
github.com/flanksource/gomplate/v3 v3.21.0
github.com/flanksource/is-healthy v0.0.0-20231003215854-76c51e3a3ff7
github.com/flanksource/kommons v0.31.4
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -827,8 +827,8 @@ github.com/flanksource/artifacts v1.0.4 h1:KjQTwsvQ73uHqTK7o4Jwt/RW8fyxJOTJ6JLgz
github.com/flanksource/artifacts v1.0.4/go.mod h1:wkbdseaTkDo4Q6k6T86vXd4Uy47M6NPCmexgHvCTDl0=
github.com/flanksource/commons v1.20.0 h1:1z7FHGsCY7F7zMx4m0OlzYCUvCc1caREPp7vf1xyeCQ=
github.com/flanksource/commons v1.20.0/go.mod h1:bs2nMwaTCpTQGZNtJv8KNqEVyfGjFZTGUDaAbPHB1cw=
github.com/flanksource/duty v1.0.280 h1:O02u0a09FwR3pxxR3cbRQYogypac92bL9m8iZtg86EA=
github.com/flanksource/duty v1.0.280/go.mod h1:zDVxlWxpSZjbpuBv0i9ke4vlG2elgyKjYY+656XhfPs=
github.com/flanksource/duty v1.0.287 h1:vuXyoxoTkEWh2m08d3JcaB/ZkFuTAEmLwBHQuW5e2AE=
github.com/flanksource/duty v1.0.287/go.mod h1:zDVxlWxpSZjbpuBv0i9ke4vlG2elgyKjYY+656XhfPs=
github.com/flanksource/gomplate/v3 v3.20.4/go.mod h1:27BNWhzzSjDed1z8YShO6W+z6G9oZXuxfNFGd/iGSdc=
github.com/flanksource/gomplate/v3 v3.21.0 h1:HbgJ7GCv2fGjjKhGBBtMmo+uA9T6pI9FVm+M/eEurOA=
github.com/flanksource/gomplate/v3 v3.21.0/go.mod h1:m2WVc04GMVBOcZhtDaz/LTtrVWKejeJhFM1Jy/h9VZQ=
Expand Down
2 changes: 1 addition & 1 deletion hack/generate-schemas/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ require (
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
github.com/exaring/otelpgx v0.5.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/flanksource/duty v1.0.280 // indirect
github.com/flanksource/duty v1.0.287 // indirect
github.com/flanksource/is-healthy v0.0.0-20231003215854-76c51e3a3ff7 // indirect
github.com/flanksource/kommons v0.31.4 // indirect
github.com/flanksource/postq v1.0.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions hack/generate-schemas/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -719,8 +719,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flanksource/commons v1.20.0 h1:1z7FHGsCY7F7zMx4m0OlzYCUvCc1caREPp7vf1xyeCQ=
github.com/flanksource/commons v1.20.0/go.mod h1:bs2nMwaTCpTQGZNtJv8KNqEVyfGjFZTGUDaAbPHB1cw=
github.com/flanksource/duty v1.0.280 h1:O02u0a09FwR3pxxR3cbRQYogypac92bL9m8iZtg86EA=
github.com/flanksource/duty v1.0.280/go.mod h1:zDVxlWxpSZjbpuBv0i9ke4vlG2elgyKjYY+656XhfPs=
github.com/flanksource/duty v1.0.287 h1:vuXyoxoTkEWh2m08d3JcaB/ZkFuTAEmLwBHQuW5e2AE=
github.com/flanksource/duty v1.0.287/go.mod h1:zDVxlWxpSZjbpuBv0i9ke4vlG2elgyKjYY+656XhfPs=
github.com/flanksource/gomplate/v3 v3.20.4/go.mod h1:27BNWhzzSjDed1z8YShO6W+z6G9oZXuxfNFGd/iGSdc=
github.com/flanksource/gomplate/v3 v3.21.0 h1:HbgJ7GCv2fGjjKhGBBtMmo+uA9T6pI9FVm+M/eEurOA=
github.com/flanksource/gomplate/v3 v3.21.0/go.mod h1:m2WVc04GMVBOcZhtDaz/LTtrVWKejeJhFM1Jy/h9VZQ=
Expand Down
1 change: 1 addition & 0 deletions pkg/system_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func (components Components) Walk() Components {
type Component struct {
Name string `json:"name,omitempty"`
ID uuid.UUID `json:"id,omitempty" gorm:"default:generate_ulid()"` //nolint
AgentID uuid.UUID `json:"agent_id,omitempty"` //nolint
Text string `json:"text,omitempty"`
Schedule string `json:"schedule,omitempty"`
TopologyType string `json:"topology_type,omitempty"`
Expand Down
203 changes: 171 additions & 32 deletions pkg/topology/component_relationship_test.go
Original file line number Diff line number Diff line change
@@ -1,97 +1,236 @@
package topology

import (
"fmt"

"github.com/flanksource/canary-checker/pkg"
"github.com/flanksource/commons/collections/set"
"github.com/flanksource/duty/models"
"github.com/flanksource/duty/types"
"github.com/google/uuid"
ginkgo "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func matchComponentsInRelationships(components pkg.Components, relationships []models.ComponentRelationship) error {
if len(components) != len(relationships) {
return fmt.Errorf("length of components & relationships should be equal")
}

cset := set.New[string]()
for _, c := range components {
cset.Add(c.ID.String())
}
for _, r := range relationships {
cset.Remove(r.ComponentID.String())
}
if len(cset) != 0 {
return fmt.Errorf("mismatch in ids: %s", cset)
}
return nil
}

var _ = ginkgo.Describe("Topology relationships", ginkgo.Ordered, func() {
agent := models.Agent{ID: uuid.New(), Name: "agent"}
topology := pkg.Topology{Name: "Topology ComponentRelationship"}
parentComponent := pkg.Component{
Name: "Component",
Selectors: []types.ResourceSelector{
{
Name: "ComponentSelector",
LabelSelector: "service=payments",

parentComponents := pkg.Components{
{
Name: "Component",
Selectors: []types.ResourceSelector{
{
LabelSelector: "service=payments",
FieldSelector: "type=api",
},
},
},
{
Name: "Component2",
Selectors: []types.ResourceSelector{
{
FieldSelector: "type=api,agent_id=all",
},
},
},
{
Name: "Component3",
Selectors: []types.ResourceSelector{
{
FieldSelector: "type=api",
},
},
},
{
Name: "Component4",
Selectors: []types.ResourceSelector{
{
LabelSelector: "service=logistics",
},
},
},
{
Name: "Component5",
Selectors: []types.ResourceSelector{
{
FieldSelector: "agent_id=" + agent.ID.String(),
},
},
},
{
Name: "Component6",
Selectors: []types.ResourceSelector{
{
LabelSelector: "service=payments",
FieldSelector: "type=api",
},
{
LabelSelector: "service=logistics",
},
},
},
}
childComponent1 := pkg.Component{
Name: "Child-1",
Labels: map[string]string{"service": "payments"},
}
childComponent2 := pkg.Component{
Name: "Child-2",
Labels: map[string]string{"service": "logistics"},
}
childComponent3 := pkg.Component{
Name: "Child-3",
Labels: map[string]string{"service": "payments"},
childrenComponents := pkg.Components{
{
Name: "Child-1",
Labels: map[string]string{"service": "payments"},
Type: "api",
},
{
Name: "Child-2",
Labels: map[string]string{"service": "logistics"},
},
{
Name: "Child-3",
Labels: map[string]string{"service": "payments"},
Type: "api",
},
{
Name: "Child-4",
Labels: map[string]string{"service": "payments"},
Type: "ui",
},
{
Name: "Child-5",
Labels: map[string]string{"service": "logistics"},
Type: "api",
},
{
Name: "Child-6",
AgentID: agent.ID,
Labels: map[string]string{"service": "logistics"},
Type: "api",
},
}

ginkgo.BeforeAll(func() {
err := DefaultContext.DB().Create(&topology).Error
Expect(err).To(BeNil())
err = DefaultContext.DB().Create(&agent).Error
Expect(err).To(BeNil())

parentComponent.TopologyID = topology.ID
for _, c := range parentComponents {
c.TopologyID = topology.ID
}
ComponentRelationshipSync.Context = DefaultContext
err = DefaultContext.DB().Create(&parentComponent).Error
err = DefaultContext.DB().Create(parentComponents).Error
Expect(err).To(BeNil())

childComponent1.TopologyID = topology.ID
childComponent2.TopologyID = topology.ID
childComponent3.TopologyID = topology.ID
err = DefaultContext.DB().Create(pkg.Components{&childComponent1, &childComponent2, &childComponent3}).Error
for _, c := range childrenComponents {
c.TopologyID = topology.ID
}
err = DefaultContext.DB().Create(childrenComponents).Error
Expect(err).To(BeNil())
})

ginkgo.It("should create component relationships", func() {
ComponentRelationshipSync.Run()
expectJobToPass(ComponentRelationshipSync)

relationships, err := parentComponent.GetChildren(DefaultContext.DB())
relationships, err := parentComponents.Find("Component").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

// Child-1 and Child-3 should be present but not Child-2
// Child-1 and Child-3
Expect(len(relationships)).To(Equal(2))
Expect(matchComponentsInRelationships(pkg.Components{childrenComponents.Find("Child-1"), childrenComponents.Find("Child-3")}, relationships)).To(BeNil())

relationships, err = parentComponents.Find("Component2").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

// Child-1 Child-3 Child-5 Child-6
Expect(matchComponentsInRelationships(pkg.Components{
childrenComponents.Find("Child-1"), childrenComponents.Find("Child-3"),
childrenComponents.Find("Child-5"), childrenComponents.Find("Child-6")}, relationships)).
To(BeNil())
Expect(len(relationships)).To(Equal(4))

relationships, err = parentComponents.Find("Component3").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

Expect(matchComponentsInRelationships(pkg.Components{
childrenComponents.Find("Child-1"), childrenComponents.Find("Child-3"),
childrenComponents.Find("Child-5")}, relationships)).
To(BeNil())
Expect(len(relationships)).To(Equal(3))

relationships, err = parentComponents.Find("Component4").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

Expect(matchComponentsInRelationships(pkg.Components{childrenComponents.Find("Child-2"), childrenComponents.Find("Child-5")}, relationships)).To(BeNil())
Expect(len(relationships)).To(Equal(2))

relationships, err = parentComponents.Find("Component5").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

Expect(matchComponentsInRelationships(pkg.Components{childrenComponents.Find("Child-6")}, relationships)).To(BeNil())
Expect(len(relationships)).To(Equal(1))

relationships, err = parentComponents.Find("Component6").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

Expect(matchComponentsInRelationships(pkg.Components{
childrenComponents.Find("Child-1"), childrenComponents.Find("Child-2"),
childrenComponents.Find("Child-3"), childrenComponents.Find("Child-5")}, relationships)).
To(BeNil())

Expect(len(relationships)).To(Equal(4))

})

ginkgo.It("should handle component relationship deletions", func() {
err := DefaultContext.DB().Delete(&childComponent3).Error
err := DefaultContext.DB().Delete(&childrenComponents[2]).Error
Expect(err).To(BeNil())

ComponentRelationshipSync.Run()
expectJobToPass(ComponentRelationshipSync)

relationships, err := parentComponent.GetChildren(DefaultContext.DB())
relationships, err := parentComponents.Find("Component").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

// Only child 1 should be present
Expect(len(relationships)).To(Equal(1))

err = DefaultContext.DB().Create(&childComponent3).Error
err = DefaultContext.DB().Create(&childrenComponents[2]).Error
Expect(err).To(BeNil())

ComponentRelationshipSync.Run()
expectJobToPass(ComponentRelationshipSync)

relationships, err = parentComponent.GetChildren(DefaultContext.DB())
relationships, err = parentComponents.Find("Component").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

// Child-1 and Child-3 should be present but not Child-2
Expect(len(relationships)).To(Equal(2))

})

ginkgo.It("should handle component label updates", func() {
childComponent3.Labels = map[string]string{"service": "logistics"}
err := DefaultContext.DB().Save(&childComponent3).Error
childrenComponents[2].Labels = map[string]string{"service": "logistics"}
err := DefaultContext.DB().Save(&childrenComponents[2]).Error
Expect(err).To(BeNil())
ComponentRelationshipSync.Run()
expectJobToPass(ComponentRelationshipSync)

relationships, err := parentComponent.GetChildren(DefaultContext.DB())
relationships, err := parentComponents.Find("Component").GetChildren(DefaultContext.DB())
Expect(err).To(BeNil())

// Only child 1 should be present as we updated the labels
Expand Down

0 comments on commit b9c6ace

Please sign in to comment.