diff --git a/tests/config_type_summary_test.go b/tests/config_type_summary_test.go index f17e45a5..cc294533 100644 --- a/tests/config_type_summary_test.go +++ b/tests/config_type_summary_test.go @@ -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 { @@ -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 { @@ -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 { @@ -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 { diff --git a/views/029_config_triggers.sql b/views/029_config_triggers.sql index ecd87ade..8598da65 100644 --- a/views/029_config_triggers.sql +++ b/views/029_config_triggers.sql @@ -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();