Skip to content

Commit ed91da8

Browse files
authoredMay 13, 2024··
✨ Managed cluster events inventory for global hub manager (stolostron#911)
* Managed cluster events inventory Signed-off-by: myan <[email protected]> * replacing controler Signed-off-by: myan <[email protected]> * add manager Signed-off-by: myan <[email protected]> --------- Signed-off-by: myan <[email protected]>
1 parent 9b7bdcc commit ed91da8

File tree

11 files changed

+185
-0
lines changed

11 files changed

+185
-0
lines changed
 

‎manager/pkg/statussyncer/conflator/conflation_priority.go

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const (
88
HubClusterHeartbeatPriority ConflationPriority = iota
99
HubClusterInfoPriority ConflationPriority = iota
1010
ManagedClustersPriority ConflationPriority = iota
11+
ManagedClusterEventPriority ConflationPriority = iota
1112
LocalPolicySpecPriority ConflationPriority = iota
1213
LocalCompliancePriority ConflationPriority = iota
1314
LocalCompleteCompliancePriority ConflationPriority = iota

‎manager/pkg/statussyncer/syncers.go

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func registerHandler(cmr *conflator.ConflationManager, enableGlobalResource bool
4747
dbsyncer.NewHubClusterHeartbeatHandler().RegisterHandler(cmr)
4848
dbsyncer.NewHubClusterInfoHandler().RegisterHandler(cmr)
4949
dbsyncer.NewManagedClusterHandler().RegisterHandler(cmr)
50+
dbsyncer.NewManagedClusterEventHandler().RegisterHandler(cmr)
5051
dbsyncer.NewLocalPolicySpecHandler().RegisterHandler(cmr)
5152
dbsyncer.NewLocalPolicyComplianceHandler().RegisterHandler(cmr)
5253
dbsyncer.NewLocalPolicyCompleteHandler().RegisterHandler(cmr)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package dbsyncer
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
cloudevents "github.com/cloudevents/sdk-go/v2"
9+
"github.com/go-logr/logr"
10+
"gorm.io/gorm/clause"
11+
ctrl "sigs.k8s.io/controller-runtime"
12+
13+
"github.com/stolostron/multicluster-global-hub/manager/pkg/statussyncer/conflator"
14+
"github.com/stolostron/multicluster-global-hub/pkg/bundle/event"
15+
eventversion "github.com/stolostron/multicluster-global-hub/pkg/bundle/version"
16+
"github.com/stolostron/multicluster-global-hub/pkg/database"
17+
"github.com/stolostron/multicluster-global-hub/pkg/enum"
18+
)
19+
20+
type managedClusterEventHandler struct {
21+
log logr.Logger
22+
eventType string
23+
eventSyncMode enum.EventSyncMode
24+
eventPriority conflator.ConflationPriority
25+
}
26+
27+
func NewManagedClusterEventHandler() conflator.Handler {
28+
eventType := string(enum.ManagedClusterEventType)
29+
logName := strings.Replace(eventType, enum.EventTypePrefix, "", -1)
30+
return &managedClusterEventHandler{
31+
log: ctrl.Log.WithName(logName),
32+
eventType: eventType,
33+
eventSyncMode: enum.DeltaStateMode,
34+
eventPriority: conflator.ManagedClusterEventPriority,
35+
}
36+
}
37+
38+
func (h *managedClusterEventHandler) RegisterHandler(conflationManager *conflator.ConflationManager) {
39+
conflationManager.Register(conflator.NewConflationRegistration(
40+
h.eventPriority,
41+
h.eventSyncMode,
42+
h.eventType,
43+
h.handleEvent,
44+
))
45+
}
46+
47+
func (h *managedClusterEventHandler) handleEvent(ctx context.Context, evt *cloudevents.Event) error {
48+
version := evt.Extensions()[eventversion.ExtVersion]
49+
leafHubName := evt.Source()
50+
h.log.V(2).Info(startMessage, "type", evt.Type(), "LH", evt.Source(), "version", version)
51+
52+
managedClusterEvents := event.ManagedClusterEventBundle{}
53+
if err := evt.DataAs(&managedClusterEvents); err != nil {
54+
return err
55+
}
56+
57+
for _, managedClusterEvent := range managedClusterEvents {
58+
managedClusterEvent.LeafHubName = leafHubName
59+
}
60+
61+
if len(managedClusterEvents) <= 0 {
62+
h.log.Info("empty managed cluster event payload", "event", evt)
63+
return nil
64+
}
65+
66+
db := database.GetGorm()
67+
err := db.Clauses(clause.OnConflict{
68+
Columns: []clause.Column{{Name: "leaf_hub_name"}, {Name: "event_name"}, {Name: "created_at"}},
69+
DoNothing: true,
70+
}).CreateInBatches(managedClusterEvents, 100).Error
71+
if err != nil {
72+
return fmt.Errorf("failed handling leaf hub LocalPolicyStatusEvent event - %w", err)
73+
}
74+
75+
h.log.V(2).Info(finishMessage, "type", evt.Type(), "LH", evt.Source(), "version", version)
76+
return nil
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package dbsyncer_test
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
. "github.com/onsi/ginkgo/v2"
8+
. "github.com/onsi/gomega"
9+
10+
"github.com/stolostron/multicluster-global-hub/pkg/bundle/event"
11+
eventversion "github.com/stolostron/multicluster-global-hub/pkg/bundle/version"
12+
"github.com/stolostron/multicluster-global-hub/pkg/database"
13+
"github.com/stolostron/multicluster-global-hub/pkg/database/models"
14+
"github.com/stolostron/multicluster-global-hub/pkg/enum"
15+
)
16+
17+
// go test ./manager/pkg/statussyncer/syncers -v -ginkgo.focus "ManagedClusterEventHandler"
18+
var _ = Describe("ManagedClusterEventHandler", Ordered, func() {
19+
It("should be able to sync replicate policy event", func() {
20+
By("Create hubClusterInfo event")
21+
22+
leafHubName := "hub1"
23+
version := eventversion.NewVersion()
24+
version.Incr()
25+
26+
data := event.ManagedClusterEventBundle{}
27+
data = append(data, models.ManagedClusterEvent{
28+
EventNamespace: "managed-cluster1",
29+
EventName: "managed-cluster1.17cd5c3642c43a8a",
30+
ClusterID: "13b2e003-2bdf-4c82-9bdf-f1aa7ccf608d",
31+
LeafHubName: "hub1",
32+
Message: "The managed cluster (managed-cluster1) cannot connect to the hub cluster.",
33+
Reason: "AvailableUnknown",
34+
ReportingController: "registration-controller",
35+
ReportingInstance: "registration-controller-cluster-manager-registration-controller-6794cf54d9-j7lgm",
36+
EventType: "Warning",
37+
CreatedAt: time.Now(),
38+
})
39+
40+
evt := ToCloudEvent(leafHubName, string(enum.ManagedClusterEventType), version, data)
41+
42+
By("Sync event with transport")
43+
err := producer.SendEvent(ctx, *evt)
44+
Expect(err).Should(Succeed())
45+
46+
By("Check the leaf hubs table")
47+
Eventually(func() error {
48+
db := database.GetGorm()
49+
items := []models.ManagedClusterEvent{}
50+
if err := db.Find(&items).Error; err != nil {
51+
return err
52+
}
53+
54+
count := 0
55+
for _, item := range items {
56+
fmt.Println(item.LeafHubName, item.EventName, item.Message, item.CreatedAt)
57+
count++
58+
}
59+
if count > 0 {
60+
return nil
61+
}
62+
return fmt.Errorf("not found expected resource on the table")
63+
}, 30*time.Second, 100*time.Millisecond).ShouldNot(HaveOccurred())
64+
})
65+
})

‎operator/pkg/controllers/hubofhubs/database/2.tables.sql

+14
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ CREATE TABLE IF NOT EXISTS status.leaf_hubs (
5959
CREATE INDEX IF NOT EXISTS leafhub_deleted_at_idx ON status.leaf_hubs (deleted_at);
6060

6161
-- Partition tables
62+
CREATE TABLE IF NOT EXISTS event.managed_clusters (
63+
event_namespace text NOT NULL,
64+
event_name text NOT NULL,
65+
cluster_id uuid NOT NULL,
66+
leaf_hub_name character varying(256) NOT NULL,
67+
message text,
68+
reason text,
69+
reporting_controller text,
70+
reporting_instance text,
71+
event_type character varying(64) NOT NULL,
72+
created_at timestamp without time zone DEFAULT now() NOT NULL,
73+
CONSTRAINT managed_clusters_unique_constraint UNIQUE (leaf_hub_name, event_name, created_at)
74+
) PARTITION BY RANGE (created_at);
75+
6276
CREATE TABLE IF NOT EXISTS event.local_policies (
6377
event_name text NOT NULL,
6478
policy_id uuid NOT NULL,

‎operator/pkg/controllers/hubofhubs/database/4.trigger.sql

+3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ EXECUTE FUNCTION public.update_local_compliance_cluster_id();
1616
SELECT create_monthly_range_partitioned_table('event.local_root_policies', to_char(current_date, 'YYYY-MM-DD'));
1717
SELECT create_monthly_range_partitioned_table('event.local_policies', to_char(current_date, 'YYYY-MM-DD'));
1818
SELECT create_monthly_range_partitioned_table('history.local_compliance', to_char(current_date, 'YYYY-MM-DD'));
19+
SELECT create_monthly_range_partitioned_table('event.managed_clusters', to_char(current_date, 'YYYY-MM-DD'));
1920

2021
--- create the previous month partitioned tables for receiving the data from the previous month
2122
SELECT create_monthly_range_partitioned_table('event.local_root_policies', to_char(current_date - interval '1 month', 'YYYY-MM-DD'));
2223
SELECT create_monthly_range_partitioned_table('event.local_policies', to_char(current_date - interval '1 month', 'YYYY-MM-DD'));
2324
SELECT create_monthly_range_partitioned_table('history.local_compliance', to_char(current_date - interval '1 month', 'YYYY-MM-DD'));
25+
SELECT create_monthly_range_partitioned_table('event.managed_clusters', to_char(current_date - interval '1 month', 'YYYY-MM-DD'));
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package event
2+
3+
import "github.com/stolostron/multicluster-global-hub/pkg/database/models"
4+
5+
type ManagedClusterEventBundle []models.ManagedClusterEvent

‎pkg/database/models/event.go

+17
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,20 @@ type DataRetentionJobLog struct {
4848
func (DataRetentionJobLog) TableName() string {
4949
return "event.data_retention_job_log"
5050
}
51+
52+
type ManagedClusterEvent struct {
53+
EventNamespace string `gorm:"column:event_namespace;type:varchar(63);not null" json:"eventNamespace"`
54+
EventName string `gorm:"column:event_name;type:varchar(63);not null" json:"eventName"`
55+
ClusterID string `gorm:"column:cluster_id;type:uuid;not null" json:"clusterId"`
56+
LeafHubName string `gorm:"size:256;not null" json:"-"`
57+
Message string `gorm:"column:message;type:text" json:"message"`
58+
Reason string `gorm:"column:reason;type:text" json:"reason"`
59+
ReportingController string `gorm:"column:reporting_controller;type:text" json:"reportingController"`
60+
ReportingInstance string `gorm:"column:reporting_instance;type:text" json:"reportingInstance"`
61+
EventType string `gorm:"size:256;not null" json:"type"`
62+
CreatedAt time.Time `gorm:"column:created_at;default:now();not null" json:"createdAt"`
63+
}
64+
65+
func (ManagedClusterEvent) TableName() string {
66+
return "event.managed_clusters"
67+
}

‎pkg/enum/event_type.go

+2
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,6 @@ const (
3333
LocalPlacementRuleSpecType EventType = "io.open-cluster-management.operator.multiclusterglobalhubs.placementrule.localspec"
3434
PlacementRuleSpecType EventType = "io.open-cluster-management.operator.multiclusterglobalhubs.placementrule.spec"
3535
PlacementSpecType EventType = "io.open-cluster-management.operator.multiclusterglobalhubs.placement.spec"
36+
37+
ManagedClusterEventType EventType = "io.open-cluster-management.operator.multiclusterglobalhubs.event.managedcluster"
3638
)

0 commit comments

Comments
 (0)
Please sign in to comment.