diff --git a/controller/runnable/initializer.go b/controller/runnable/initializer.go new file mode 100644 index 0000000..3dfb9bc --- /dev/null +++ b/controller/runnable/initializer.go @@ -0,0 +1,48 @@ +/* +Copyright 2025 The KusionStack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package runnable + +import ( + "github.com/go-logr/logr" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/manager" + + "kusionstack.io/kube-utils/metrics" +) + +var runnable []manager.Runnable + +// InitializeRunnable initialize runnable for manager +func InitializeRunnable(mgr manager.Manager, opts controllerruntime.Options) error { + // register leader metrics + metrics.RegisterLeaderRunningMetrics() + // register runnable + addRunnable(opts, mgr.GetLogger()) + for _, runnable := range runnable { + if err := mgr.Add(runnable); err != nil { + return err + } + } + return nil +} + +func addRunnable(opts controllerruntime.Options, logger logr.Logger) { + runnable = append(runnable, + &LeaderMetricsRunnable{leaseName: opts.LeaderElectionID, logger: logger}, + &NoneLeaderMetricRunnable{enableLeaderElection: opts.LeaderElection, leaseName: opts.LeaderElectionID, logger: logger}, + ) +} diff --git a/controller/runnable/leader_monitor.go b/controller/runnable/leader_monitor.go new file mode 100644 index 0000000..c80cac3 --- /dev/null +++ b/controller/runnable/leader_monitor.go @@ -0,0 +1,65 @@ +/* +Copyright 2025 The KusionStack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package runnable + +import ( + "context" + + "github.com/go-logr/logr" + + "kusionstack.io/kube-utils/metrics" +) + +// LeaderMetricsRunnable is a runnable that records the leader metrics +type LeaderMetricsRunnable struct { + logger logr.Logger + leaseName string +} + +func (l LeaderMetricsRunnable) NeedLeaderElection() bool { + return true +} + +func (l LeaderMetricsRunnable) Start(_ context.Context) error { + m := metrics.LeaderRunningMetrics{Lease: l.leaseName} + m.Lead() + l.logger.Info("leader election enabled, start LeaderMetricsRunnable, record leader metrics") + return nil +} + +// NoneLeaderMetricRunnable is a runnable that records the none leader metrics +type NoneLeaderMetricRunnable struct { + logger logr.Logger + leaseName string + enableLeaderElection bool +} + +func (nl NoneLeaderMetricRunnable) NeedLeaderElection() bool { + return false +} + +func (nl NoneLeaderMetricRunnable) Start(_ context.Context) error { + m := metrics.LeaderRunningMetrics{Lease: nl.leaseName} + if nl.enableLeaderElection { + m.UnLead() + nl.logger.Info("leader election enabled, start NoneLeaderMetricRunnable, record none leader metrics") + } else { + m.Lead() + nl.logger.Info("leader election disabled, start NoneLeaderMetricRunnable, record leader metrics") + } + return nil +} diff --git a/metrics/leader_election.go b/metrics/leader_election.go new file mode 100644 index 0000000..24b64b4 --- /dev/null +++ b/metrics/leader_election.go @@ -0,0 +1,49 @@ +/* +Copyright 2025 The KusionStack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" + "sigs.k8s.io/controller-runtime/pkg/metrics" +) + +var leaderRunningCount = "leader_running_gauge" + +var leaderRunningGaugeVec = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Subsystem: ReconcileSubSystem, + Name: leaderRunningCount, + Help: "leader controller set gauge to 1, otherwise set to 0", + }, + []string{"Lease"}, +) + +func RegisterLeaderRunningMetrics() { + metrics.Registry.MustRegister(leaderRunningGaugeVec) +} + +type LeaderRunningMetrics struct { + Lease string +} + +func (m *LeaderRunningMetrics) Lead() { + leaderRunningGaugeVec.WithLabelValues(m.Lease).Set(1) +} + +func (m *LeaderRunningMetrics) UnLead() { + leaderRunningGaugeVec.WithLabelValues(m.Lease).Set(0) +}