Skip to content

Commit

Permalink
feat: new config relationship function
Browse files Browse the repository at this point in the history
  • Loading branch information
adityathebe authored and moshloop committed Feb 12, 2024
1 parent 7e135e8 commit 39bed82
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 1 deletion.
13 changes: 13 additions & 0 deletions models/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,16 @@ func (e ExternalID) CacheKey() string {
func (e ExternalID) WhereClause(db *gorm.DB) *gorm.DB {
return db.Where("type = ? AND external_id @> ?", e.ConfigType, pq.StringArray(e.ExternalID))
}

type RelatedConfigType string

const (
RelatedConfigTypeIncoming RelatedConfigType = "incoming"
RelatedConfigTypeOutgoing RelatedConfigType = "outgoing"
)

type RelatedConfig struct {
Relation string `json:"relation"`
Type RelatedConfigType `json:"relation_type" gorm:"column:relation_type"`
Config types.JSONMap `json:"config"`
}
34 changes: 34 additions & 0 deletions tests/config_relationship_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package tests

import (
"github.com/flanksource/duty/models"
"github.com/flanksource/duty/tests/fixtures/dummy"
ginkgo "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = ginkgo.Describe("Config relationship", ginkgo.Ordered, func() {
ginkgo.It("should return OUTGOING relationships", func() {
var relatedConfigs []models.RelatedConfig
err := DefaultContext.DB().Raw("SELECT * FROM related_configs(?, false)", dummy.KubernetesCluster.ID).Find(&relatedConfigs).Error
Expect(err).To(BeNil())

Expect(len(relatedConfigs)).To(Equal(2))
for _, rc := range relatedConfigs {
Expect(rc.Relation).To(Equal("ClusterNode"))
Expect(rc.Type).To(Equal(models.RelatedConfigTypeOutgoing))
Expect(rc.Config["id"]).To(BeElementOf([]string{dummy.KubernetesNodeA.ID.String(), dummy.KubernetesNodeB.ID.String()}))
}
})

ginkgo.It("should return INCOOMING relationships", func() {
var relatedConfigs []models.RelatedConfig
err := DefaultContext.DB().Raw("SELECT * FROM related_configs(?, false)", dummy.KubernetesNodeA.ID).Find(&relatedConfigs).Error
Expect(err).To(BeNil())

Expect(len(relatedConfigs)).To(Equal(1))
Expect(relatedConfigs[0].Relation).To(Equal("ClusterNode"))
Expect(relatedConfigs[0].Type).To(Equal(models.RelatedConfigTypeIncoming))
Expect(relatedConfigs[0].Config["id"]).To(Equal(dummy.KubernetesCluster.ID.String()))
})
})
26 changes: 26 additions & 0 deletions tests/fixtures/dummy/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type DummyData struct {
ComponentRelationships []models.ComponentRelationship

Configs []models.ConfigItem
ConfigRelationships []models.ConfigRelationship
ConfigScrapers []models.ConfigScraper
ConfigChanges []models.ConfigChange
ConfigAnalyses []models.ConfigAnalysis
Expand Down Expand Up @@ -94,6 +95,13 @@ func (t *DummyData) Populate(gormDB *gorm.DB) error {
return err
}
}
for _, c := range t.ConfigRelationships {
c.CreatedAt = createTime
err = gormDB.Create(&c).Error
if err != nil {
return err
}
}
for _, c := range t.ConfigChanges {
err = gormDB.Create(&c).Error
if err != nil {
Expand Down Expand Up @@ -320,6 +328,7 @@ func GetStaticDummyData(db *gorm.DB) DummyData {
ComponentRelationships: append([]models.ComponentRelationship{}, AllDummyComponentRelationships...),
Configs: append([]models.ConfigItem{}, AllDummyConfigs...),
ConfigChanges: append([]models.ConfigChange{}, AllDummyConfigChanges...),
ConfigRelationships: append([]models.ConfigRelationship{}, AllConfigRelationships...),
ConfigAnalyses: append([]models.ConfigAnalysis{}, AllDummyConfigAnalysis()...),
ConfigComponentRelationships: append([]models.ConfigComponentRelationship{}, AllDummyConfigComponentRelationships...),
Teams: append([]models.Team{}, AllDummyTeams...),
Expand Down Expand Up @@ -832,6 +841,22 @@ func GenerateDynamicDummyData(db *gorm.DB) DummyData {
LogisticsDBRDS,
}

var ClusterNodeARelationship = models.ConfigRelationship{
ConfigID: KubernetesCluster.ID.String(),
RelatedID: KubernetesNodeA.ID.String(),
Relation: "ClusterNode",
CreatedAt: DummyCreatedAt,
}

var ClusterNodeBRelationship = models.ConfigRelationship{
ConfigID: KubernetesCluster.ID.String(),
RelatedID: KubernetesNodeB.ID.String(),
Relation: "ClusterNode",
CreatedAt: DummyCreatedAt,
}

var configRelationships = []models.ConfigRelationship{ClusterNodeARelationship, ClusterNodeBRelationship}

var LogisticsDBRDSAnalysis = models.ConfigAnalysis{
ID: uuid.New(),
ConfigID: LogisticsDBRDS.ID,
Expand Down Expand Up @@ -1106,6 +1131,7 @@ func GenerateDynamicDummyData(db *gorm.DB) DummyData {
Components: components,
ComponentRelationships: componentRelationships,

ConfigRelationships: configRelationships,
ConfigScrapers: configScrapers,
Configs: configs,
ConfigChanges: configChanges,
Expand Down
14 changes: 14 additions & 0 deletions tests/fixtures/dummy/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,17 @@ var AzureConfigScraper = models.ConfigScraper{
}

var AllConfigScrapers = []models.ConfigScraper{AzureConfigScraper}

var ClusterNodeARelationship = models.ConfigRelationship{
ConfigID: KubernetesCluster.ID.String(),
RelatedID: KubernetesNodeA.ID.String(),
Relation: "ClusterNode",
}

var ClusterNodeBRelationship = models.ConfigRelationship{
ConfigID: KubernetesCluster.ID.String(),
RelatedID: KubernetesNodeB.ID.String(),
Relation: "ClusterNode",
}

var AllConfigRelationships = []models.ConfigRelationship{ClusterNodeARelationship, ClusterNodeBRelationship}
63 changes: 62 additions & 1 deletion views/006_config_views.sql
Original file line number Diff line number Diff line change
Expand Up @@ -423,4 +423,65 @@ CREATE OR REPLACE VIEW config_detail AS
ON ci.id = config_changes.config_id
LEFT JOIN
(SELECT config_id, count(*) as playbook_runs_count FROM playbook_runs GROUP BY config_id) as playbook_runs
ON ci.id = playbook_runs.config_id;
ON ci.id = playbook_runs.config_id;

DROP FUNCTION IF EXISTS related_configs(UUID, BOOLEAN);

CREATE FUNCTION related_configs (
config_id UUID,
include_deleted_configs BOOLEAN
)
RETURNS TABLE (
relation TEXT,
relation_type TEXT,
config JSONB
) AS $$
BEGIN
RETURN query
SELECT
config_relationships.relation,
'outgoing' AS relation_type,
jsonb_build_object(
'id', c.id,
'name', c.name,
'type', c.type,
'tags', c.tags,
'changes', c.changes,
'analysis', c.analysis,
'cost_per_minute', c.cost_per_minute,
'cost_total_1d', c.cost_total_1d,
'cost_total_7d', c.cost_total_7d,
'cost_total_30d', c.cost_total_30d,
'created_at', c.created_at,
'updated_at', c.updated_at
) AS config
FROM config_relationships
INNER JOIN configs AS c ON config_relationships.related_id = c.id AND ($2 OR c.deleted_at IS NULL)
WHERE
config_relationships.deleted_at IS NULL
AND config_relationships.config_id = $1
UNION
SELECT
config_relationships.relation,
'incoming' AS relation_type,
jsonb_build_object(
'id', c.id,
'name', c.name,
'type', c.type,
'tags', c.tags,
'changes', c.changes,
'analysis', c.analysis,
'cost_per_minute', c.cost_per_minute,
'cost_total_1d', c.cost_total_1d,
'cost_total_7d', c.cost_total_7d,
'cost_total_30d', c.cost_total_30d,
'created_at', c.created_at,
'updated_at', c.updated_at
) AS config
FROM config_relationships
INNER JOIN configs AS c ON config_relationships.config_id = c.id AND ($2 OR c.deleted_at IS NULL)
WHERE
config_relationships.deleted_at IS NULL
AND config_relationships.related_id = $1;
END;
$$ LANGUAGE plpgsql;

0 comments on commit 39bed82

Please sign in to comment.