diff --git a/Makefile b/Makefile index 94982c1..3863ccb 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ manager: generate fmt vet -X 'github.com/metal-stack/v.Revision=$(GITVERSION)' \ -X 'github.com/metal-stack/v.GitSHA1=$(SHA)' \ -X 'github.com/metal-stack/v.BuildDate=$(BUILDDATE)'" \ - -o bin/firewall-controller-manager main.go + -o bin/firewall-controller-manager . strip bin/firewall-controller-manager # Run against the mini-lab diff --git a/health.go b/health.go new file mode 100644 index 0000000..1f0ba4b --- /dev/null +++ b/health.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "log/slog" + "net/http" + + v2 "github.com/metal-stack/firewall-controller-manager/api/v2" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func healthCheckFunc(log *slog.Logger, seedClient client.Client, namespace string) func(req *http.Request) error { + return func(req *http.Request) error { + log.Debug("health check called") + + fws := &v2.FirewallList{} + err := seedClient.List(req.Context(), fws, client.InNamespace(namespace)) + if err != nil { + return fmt.Errorf("unable to list firewalls in namespace %s", namespace) + } + return nil + } +} diff --git a/main.go b/main.go index 2c6bad6..f1b9f67 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( "fmt" "log" "log/slog" - "net/http" "os" "time" @@ -21,7 +20,7 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" - controllerclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/metrics/server" "sigs.k8s.io/controller-runtime/pkg/webhook" @@ -40,19 +39,6 @@ const ( metalAuthHMACEnvVar = "METAL_AUTH_HMAC" ) -func healthCheckFunc(log *slog.Logger, seedClient controllerclient.Client, namespace string) func(req *http.Request) error { - return func(req *http.Request) error { - log.Debug("health check called") - - fws := &v2.FirewallList{} - err := seedClient.List(req.Context(), fws, controllerclient.InNamespace(namespace)) - if err != nil { - return fmt.Errorf("unable to list firewalls in namespace %s", namespace) - } - return nil - } -} - func main() { var ( scheme = helper.MustNewFirewallScheme() @@ -150,7 +136,7 @@ func main() { // cannot use seedMgr.GetClient() because it gets initialized at a later point in time // we have to create an own client - seedClient, err := controllerclient.New(seedMgr.GetConfig(), controllerclient.Options{ + seedClient, err := client.New(seedMgr.GetConfig(), client.Options{ Scheme: scheme, }) if err != nil { @@ -164,6 +150,8 @@ func main() { log.Fatalf("unable to set up ready check %v", err) } + mustRegisterCustomMetrics(l.WithGroup("metrics"), seedClient, namespace) + var ( externalShootAccess = &v2.ShootAccess{ GenericKubeconfigSecretName: shootKubeconfigSecret, diff --git a/metrics.go b/metrics.go new file mode 100644 index 0000000..fdf9574 --- /dev/null +++ b/metrics.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "log/slog" + "time" + + v2 "github.com/metal-stack/firewall-controller-manager/api/v2" + "github.com/prometheus/client_golang/prometheus" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/metrics" +) + +var ( + firewallDeploymentReadyReplicasDesc = prometheus.NewDesc( + "firewall_deployment_ready_replicas", + "provide information on firewall deployment ready replicas", + []string{"name", "namespace"}, + nil, + ) + firewallDeploymentTargetReplicasDesc = prometheus.NewDesc( + "firewall_deployment_target_replicas", + "provide information on firewall deployment target replicas", + []string{"name", "namespace"}, + nil, + ) +) + +type collector struct { + log *slog.Logger + seedClient client.Client + namespace string +} + +func mustRegisterCustomMetrics(log *slog.Logger, seedClient client.Client, namespace string) { + c := &collector{ + log: log, + seedClient: seedClient, + namespace: namespace, + } + + metrics.Registry.MustRegister(c) +} + +func (c *collector) Describe(ch chan<- *prometheus.Desc) { + ch <- firewallDeploymentReadyReplicasDesc + ch <- firewallDeploymentTargetReplicasDesc +} + +func (c *collector) Collect(ch chan<- prometheus.Metric) { + c.log.Info("collecting custom metrics") + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + deploys := &v2.FirewallDeploymentList{} + err := c.seedClient.List(ctx, deploys, client.InNamespace(c.namespace)) + if err != nil { + c.log.Error("unable to list firewall deployments", "error", err) + return + } + + for _, deploy := range deploys.Items { + ch <- prometheus.MustNewConstMetric(firewallDeploymentReadyReplicasDesc, prometheus.GaugeValue, + float64(deploy.Status.ReadyReplicas), + deploy.Name, + deploy.Namespace, + ) + ch <- prometheus.MustNewConstMetric(firewallDeploymentTargetReplicasDesc, prometheus.GaugeValue, + float64(deploy.Status.TargetReplicas), + deploy.Name, + deploy.Namespace, + ) + } +}