Skip to content

Commit

Permalink
feat: save config health updates as config changes via DB trigger (#1188
Browse files Browse the repository at this point in the history
)

* feat: save config health updates as config changes via DB trigger

* fix: failing tests

* fix: ignore agent configs
  • Loading branch information
adityathebe authored Nov 11, 2024
1 parent 862e452 commit 60452ac
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 21 deletions.
24 changes: 12 additions & 12 deletions tests/config_type_summary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ var _ = ginkgo.Describe("Check config_class_summary view", ginkgo.Ordered, func(
Expect(err).To(BeNil())

expectedTypeSummary := []summaryRow{
{Type: "Test::type-A", Count: 3, Changes: 6, Health: map[string]any{"healthy": float64(2), "unhealthy": float64(1)}, Analysis: map[string]any{"availability": float64(2), "cost": float64(3), "security": float64(2)}},
{Type: "Test::type-B", Count: 2, Changes: 6, Health: map[string]any{"healthy": float64(2)}, Analysis: map[string]any{"availability": float64(1), "cost": float64(1), "security": float64(2)}},
{Type: "Test::type-C", Count: 1, Changes: 0, Health: map[string]any{"unhealthy": float64(1)}, Analysis: map[string]any{}},
{Type: "Test::type-A", Count: 3, Changes: 9, Health: map[string]any{"healthy": float64(2), "unhealthy": float64(1)}, Analysis: map[string]any{"availability": float64(2), "cost": float64(3), "security": float64(2)}},
{Type: "Test::type-B", Count: 2, Changes: 8, Health: map[string]any{"healthy": float64(2)}, Analysis: map[string]any{"availability": float64(1), "cost": float64(1), "security": float64(2)}},
{Type: "Test::type-C", Count: 1, Changes: 1, Health: map[string]any{"unhealthy": float64(1)}, Analysis: map[string]any{}},
}

for _, expected := range expectedTypeSummary {
Expand Down Expand Up @@ -178,9 +178,9 @@ var _ = ginkgo.Describe("Check config_class_summary view", ginkgo.Ordered, func(
Expect(err).To(BeNil())

expectedTypeSummary7d := []summaryRow{
{Type: "Test::type-A", Count: 3, Changes: 5, Health: map[string]any{"healthy": float64(2), "unhealthy": float64(1)}, Analysis: map[string]any{"availability": float64(2), "cost": float64(2), "security": float64(2)}},
{Type: "Test::type-B", Count: 2, Changes: 6, Health: map[string]any{"healthy": float64(2)}, Analysis: map[string]any{"availability": float64(1), "cost": float64(1), "security": float64(2)}},
{Type: "Test::type-C", Count: 1, Changes: 0, Health: map[string]any{"unhealthy": float64(1)}, Analysis: map[string]any{}},
{Type: "Test::type-A", Count: 3, Changes: 8, Health: map[string]any{"healthy": float64(2), "unhealthy": float64(1)}, Analysis: map[string]any{"availability": float64(2), "cost": float64(2), "security": float64(2)}},
{Type: "Test::type-B", Count: 2, Changes: 8, Health: map[string]any{"healthy": float64(2)}, Analysis: map[string]any{"availability": float64(1), "cost": float64(1), "security": float64(2)}},
{Type: "Test::type-C", Count: 1, Changes: 1, Health: map[string]any{"unhealthy": float64(1)}, Analysis: map[string]any{}},
}

for _, expected := range expectedTypeSummary7d {
Expand All @@ -205,9 +205,9 @@ var _ = ginkgo.Describe("Check config_class_summary view", ginkgo.Ordered, func(
Expect(err).To(BeNil())

expectedTypeSummary3d := []summaryRow{
{Type: "Test::type-A", Count: 3, Changes: 5, Health: map[string]any{"healthy": float64(2), "unhealthy": float64(1)}, Analysis: map[string]any{"availability": float64(2), "cost": float64(2), "security": float64(2)}},
{Type: "Test::type-B", Count: 2, Changes: 6, Health: map[string]any{"healthy": float64(2)}, Analysis: map[string]any{"availability": float64(1), "cost": float64(1), "security": float64(2)}},
{Type: "Test::type-C", Count: 1, Changes: 0, Health: map[string]any{"unhealthy": float64(1)}, Analysis: map[string]any{}},
{Type: "Test::type-A", Count: 3, Changes: 8, Health: map[string]any{"healthy": float64(2), "unhealthy": float64(1)}, Analysis: map[string]any{"availability": float64(2), "cost": float64(2), "security": float64(2)}},
{Type: "Test::type-B", Count: 2, Changes: 8, Health: map[string]any{"healthy": float64(2)}, Analysis: map[string]any{"availability": float64(1), "cost": float64(1), "security": float64(2)}},
{Type: "Test::type-C", Count: 1, Changes: 1, Health: map[string]any{"unhealthy": float64(1)}, Analysis: map[string]any{}},
}

for _, expected := range expectedTypeSummary3d {
Expand All @@ -232,9 +232,9 @@ var _ = ginkgo.Describe("Check config_class_summary view", ginkgo.Ordered, func(
Expect(err).To(BeNil())

expectedTypeSummary10d := []summaryRow{
{Type: "Test::type-A", Count: 3, Changes: 5, Health: map[string]any{"healthy": float64(2), "unhealthy": float64(1)}, Analysis: map[string]any{"availability": float64(2), "cost": float64(2), "security": float64(2)}},
{Type: "Test::type-B", Count: 2, Changes: 6, Health: map[string]any{"healthy": float64(2)}, Analysis: map[string]any{"availability": float64(1), "cost": float64(1), "security": float64(2)}},
{Type: "Test::type-C", Count: 1, Changes: 0, Health: map[string]any{"unhealthy": float64(1)}, Analysis: nil},
{Type: "Test::type-A", Count: 3, Changes: 8, Health: map[string]any{"healthy": float64(2), "unhealthy": float64(1)}, Analysis: map[string]any{"availability": float64(2), "cost": float64(2), "security": float64(2)}},
{Type: "Test::type-B", Count: 2, Changes: 8, Health: map[string]any{"healthy": float64(2)}, Analysis: map[string]any{"availability": float64(1), "cost": float64(1), "security": float64(2)}},
{Type: "Test::type-C", Count: 1, Changes: 1, Health: map[string]any{"unhealthy": float64(1)}, Analysis: nil},
}

for _, expected := range expectedTypeSummary10d {
Expand Down
93 changes: 84 additions & 9 deletions views/029_config_triggers.sql
Original file line number Diff line number Diff line change
@@ -1,15 +1,90 @@
CREATE OR REPLACE FUNCTION populate_config_item_name()
RETURNS TRIGGER AS $$
CREATE OR REPLACE FUNCTION populate_config_item_name ()
RETURNS TRIGGER
AS $$
BEGIN
IF NEW.name IS NULL OR new.NAME = '' THEN
NEW.name = RIGHT(NEW.id::TEXT, 12);
IF NEW.name IS NULL OR NEW.NAME = '' THEN
NEW.name = RIGHT (NEW.id::text, 12);
END IF;

RETURN NEW;
END;
$$ LANGUAGE plpgsql;
$$
LANGUAGE plpgsql;

CREATE OR REPLACE TRIGGER check_config_item_name
BEFORE INSERT ON config_items
FOR EACH ROW
EXECUTE PROCEDURE populate_config_item_name();
BEFORE INSERT ON config_items
FOR EACH ROW
EXECUTE PROCEDURE populate_config_item_name ();

-- Insert config health updates as config changes
CREATE OR REPLACE FUNCTION insert_config_health_updates_as_config_changes ()
RETURNS TRIGGER
AS $$
DECLARE
change_type text;
severity text := 'info';
summary text := '';
BEGIN
-- If record belongs to agent, we ignore it
IF NEW.agent_id != '00000000-0000-0000-0000-000000000000' THEN
RETURN NEW;
END IF;

IF OLD.health = NEW.health OR (OLD.health IS NULL AND NEW.health IS NULL) THEN
RETURN NULL;
END IF;

IF NEW.health = 'unknown' OR NEW.health = '' THEN
change_type := 'HealthUnknown';
ELSE
change_type := initcap(NEW.health);
END IF;

CASE NEW.health
WHEN 'unhealthy' THEN severity := 'medium';
WHEN 'warning' THEN severity := 'low';
ELSE severity := 'info';
END CASE;

IF NEW.status IS NOT NULL THEN
summary := NEW.status;
END IF;

IF NEW.description IS NOT NULL THEN
IF summary != '' THEN
summary := summary || ': ';
END IF;

summary := summary || NEW.description;
END IF;

INSERT INTO config_changes (config_id, change_type, source, count, severity, summary, details) VALUES (
NEW.id,
change_type,
'config-db',
1,
severity,
summary,
jsonb_build_object(
'previous', jsonb_build_object(
'status', OLD.status,
'ready', OLD.ready,
'description', OLD.description
),
'current', jsonb_build_object(
'status', NEW.status,
'ready', NEW.ready,
'description', NEW.description
)
)
);

RETURN NULL;
END;
$$
LANGUAGE plpgsql;

CREATE OR REPLACE TRIGGER config_health_as_config_changes
AFTER INSERT OR UPDATE ON config_items
FOR EACH ROW
EXECUTE PROCEDURE insert_config_health_updates_as_config_changes();

0 comments on commit 60452ac

Please sign in to comment.