fix(telemetry): use APIReader instead of cached client in operator

The cozystack-operator's manager cache is filtered to only include
specific secrets and namespaces with certain labels. This caused
telemetry collection to fail because resources like kube-system
namespace, nodes, services, and PVs were not in the cache.

Switch to using mgr.GetAPIReader() which bypasses the cache and
queries the API server directly. This is appropriate for telemetry
since it only runs every 15 minutes.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
This commit is contained in:
Andrei Kvapil 2026-01-27 18:06:30 +01:00
parent b864c04069
commit af320a86a0
No known key found for this signature in database
GPG key ID: 931CF7FEACEAF765
2 changed files with 11 additions and 9 deletions

View file

@ -262,7 +262,9 @@ func main() {
}
// Initialize telemetry collector
collector, err := telemetry.NewOperatorCollector(mgr.GetClient(), &telemetryConfig, config)
// Use APIReader (non-cached) because the manager's cache is filtered
// and doesn't include resources needed for telemetry (e.g., kube-system namespace, nodes, etc.)
collector, err := telemetry.NewOperatorCollector(mgr.GetAPIReader(), &telemetryConfig, config)
if err != nil {
setupLog.V(1).Info("unable to create telemetry collector, telemetry will be disabled", "error", err)
}

View file

@ -22,7 +22,7 @@ import (
// OperatorCollector handles telemetry data collection for cozystack-operator
type OperatorCollector struct {
client client.Client
reader client.Reader
discoveryClient discovery.DiscoveryInterface
config *Config
ticker *time.Ticker
@ -30,13 +30,13 @@ type OperatorCollector struct {
}
// NewOperatorCollector creates a new telemetry collector for cozystack-operator
func NewOperatorCollector(c client.Client, config *Config, kubeConfig *rest.Config) (*OperatorCollector, error) {
func NewOperatorCollector(r client.Reader, config *Config, kubeConfig *rest.Config) (*OperatorCollector, error) {
discoveryClient, err := discovery.NewDiscoveryClientForConfig(kubeConfig)
if err != nil {
return nil, fmt.Errorf("failed to create discovery client: %w", err)
}
return &OperatorCollector{
client: c,
reader: r,
discoveryClient: discoveryClient,
config: config,
}, nil
@ -108,7 +108,7 @@ func (c *OperatorCollector) collect(ctx context.Context) {
// Get cluster ID from kube-system namespace
var kubeSystemNS corev1.Namespace
if err := c.client.Get(ctx, types.NamespacedName{Name: "kube-system"}, &kubeSystemNS); err != nil {
if err := c.reader.Get(ctx, types.NamespacedName{Name: "kube-system"}, &kubeSystemNS); err != nil {
logger.Info(fmt.Sprintf("Failed to get kube-system namespace: %v", err))
return
}
@ -124,7 +124,7 @@ func (c *OperatorCollector) collect(ctx context.Context) {
// Get nodes
var nodeList corev1.NodeList
if err := c.client.List(ctx, &nodeList); err != nil {
if err := c.reader.List(ctx, &nodeList); err != nil {
logger.Info(fmt.Sprintf("Failed to list nodes: %v", err))
return
}
@ -183,7 +183,7 @@ func (c *OperatorCollector) collect(ctx context.Context) {
// Collect LoadBalancer services metrics
var serviceList corev1.ServiceList
if err := c.client.List(ctx, &serviceList); err != nil {
if err := c.reader.List(ctx, &serviceList); err != nil {
logger.Info(fmt.Sprintf("Failed to list Services: %v", err))
} else {
lbCount := 0
@ -197,7 +197,7 @@ func (c *OperatorCollector) collect(ctx context.Context) {
// Collect PV metrics grouped by driver and size
var pvList corev1.PersistentVolumeList
if err := c.client.List(ctx, &pvList); err != nil {
if err := c.reader.List(ctx, &pvList); err != nil {
logger.Info(fmt.Sprintf("Failed to list PVs: %v", err))
} else {
pvMetrics := make(map[string]map[string]int) // size -> driver -> count
@ -236,7 +236,7 @@ func (c *OperatorCollector) collect(ctx context.Context) {
// Collect installed packages
var packageList cozyv1alpha1.PackageList
if err := c.client.List(ctx, &packageList); err != nil {
if err := c.reader.List(ctx, &packageList); err != nil {
logger.Info(fmt.Sprintf("Failed to list Packages: %v", err))
} else {
for _, pkg := range packageList.Items {