-
Notifications
You must be signed in to change notification settings - Fork 38
NETOBSERV-2675: Centralized K8s informers to reduce API load #1221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 7 commits
1117b70
195bf1c
27651ee
c6960fc
5831373
e5cbc92
ab6e2fc
dbc00d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -19,8 +19,11 @@ package main | |||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||
| "context" | ||||||||||||||||||||||||||||||||||||
| "crypto/tls" | ||||||||||||||||||||||||||||||||||||
| "crypto/x509" | ||||||||||||||||||||||||||||||||||||
| "encoding/json" | ||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||
| "net" | ||||||||||||||||||||||||||||||||||||
| "net/http" | ||||||||||||||||||||||||||||||||||||
| "os" | ||||||||||||||||||||||||||||||||||||
| "path/filepath" | ||||||||||||||||||||||||||||||||||||
|
|
@@ -33,12 +36,17 @@ import ( | |||||||||||||||||||||||||||||||||||
| "github.com/netobserv/flowlogs-pipeline/pkg/config" | ||||||||||||||||||||||||||||||||||||
| "github.com/netobserv/flowlogs-pipeline/pkg/operational" | ||||||||||||||||||||||||||||||||||||
| "github.com/netobserv/flowlogs-pipeline/pkg/pipeline" | ||||||||||||||||||||||||||||||||||||
| "github.com/netobserv/flowlogs-pipeline/pkg/pipeline/transform/kubernetes" | ||||||||||||||||||||||||||||||||||||
| "github.com/netobserv/flowlogs-pipeline/pkg/pipeline/transform/kubernetes/datasource" | ||||||||||||||||||||||||||||||||||||
| "github.com/netobserv/flowlogs-pipeline/pkg/pipeline/transform/kubernetes/k8scache" | ||||||||||||||||||||||||||||||||||||
| "github.com/netobserv/flowlogs-pipeline/pkg/pipeline/utils" | ||||||||||||||||||||||||||||||||||||
| "github.com/netobserv/flowlogs-pipeline/pkg/prometheus" | ||||||||||||||||||||||||||||||||||||
| log "github.com/sirupsen/logrus" | ||||||||||||||||||||||||||||||||||||
| "github.com/spf13/cobra" | ||||||||||||||||||||||||||||||||||||
| "github.com/spf13/pflag" | ||||||||||||||||||||||||||||||||||||
| "github.com/spf13/viper" | ||||||||||||||||||||||||||||||||||||
| "google.golang.org/grpc" | ||||||||||||||||||||||||||||||||||||
| "google.golang.org/grpc/credentials" | ||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| var ( | ||||||||||||||||||||||||||||||||||||
|
|
@@ -145,6 +153,12 @@ func initFlags() { | |||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().StringVar(&opts.Health.Address, "health.address", "0.0.0.0", "Health server address") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().IntVar(&opts.Health.Port, "health.port", 0, "Health server port (default: disable health server) ") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().IntVar(&opts.Profile.Port, "profile.port", 0, "Go pprof tool port (default: disabled)") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().StringVar(&opts.K8sCacheServer.Address, "k8scache.address", "0.0.0.0", "K8s cache sync server address") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().IntVar(&opts.K8sCacheServer.Port, "k8scache.port", 0, "K8s cache sync server port (default: disabled)") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().BoolVar(&opts.K8sCacheServer.TLSEnabled, "k8scache.tls-enabled", false, "Enable TLS for K8s cache sync server") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().StringVar(&opts.K8sCacheServer.TLSCertPath, "k8scache.tls-cert-path", "", "Path to TLS server certificate") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().StringVar(&opts.K8sCacheServer.TLSKeyPath, "k8scache.tls-key-path", "", "Path to TLS server private key") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().StringVar(&opts.K8sCacheServer.TLSCAPath, "k8scache.tls-ca-path", "", "Path to TLS CA certificate for client verification") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().StringVar(&opts.PipeLine, "pipeline", "", "json of config file pipeline field") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().StringVar(&opts.Parameters, "parameters", "", "json of config file parameters field") | ||||||||||||||||||||||||||||||||||||
| rootCmd.PersistentFlags().StringVar(&opts.DynamicParameters, "dynamicParameters", "", "json of configmap location for dynamic parameters") | ||||||||||||||||||||||||||||||||||||
|
|
@@ -183,6 +197,11 @@ func run() { | |||||||||||||||||||||||||||||||||||
| utils.SetupElegantExit() | ||||||||||||||||||||||||||||||||||||
| promServer := prometheus.InitializePrometheus(&cfg.MetricsSettings) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Enable k8scache mode if configured (disables local informers to save resources) | ||||||||||||||||||||||||||||||||||||
| if opts.K8sCacheServer.Port > 0 { | ||||||||||||||||||||||||||||||||||||
| kubernetes.SetK8sCacheEnabled(true) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Create new flows pipeline | ||||||||||||||||||||||||||||||||||||
| mainPipeline, err = pipeline.NewPipeline(&cfg) | ||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||
|
|
@@ -204,6 +223,12 @@ func run() { | |||||||||||||||||||||||||||||||||||
| healthServer = operational.NewHealthServer(&opts, mainPipeline.IsAlive, mainPipeline.IsReady) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Start K8s cache server | ||||||||||||||||||||||||||||||||||||
| var grpcServer *grpc.Server | ||||||||||||||||||||||||||||||||||||
| if opts.K8sCacheServer.Port > 0 { | ||||||||||||||||||||||||||||||||||||
| grpcServer = startK8sCacheServer(&opts.K8sCacheServer) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Starts the flows pipeline | ||||||||||||||||||||||||||||||||||||
| mainPipeline.Run() | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
@@ -213,9 +238,102 @@ func run() { | |||||||||||||||||||||||||||||||||||
| if healthServer != nil { | ||||||||||||||||||||||||||||||||||||
| _ = healthServer.Shutdown(context.Background()) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| if grpcServer != nil { | ||||||||||||||||||||||||||||||||||||
| log.Info("stopping K8s cache sync server") | ||||||||||||||||||||||||||||||||||||
| grpcServer.GracefulStop() | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+241
to
+243
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's find and examine the main.go file around lines 241-243
find . -name main.go -path "*/cmd/flowlogs-pipeline/*" | head -1Repository: netobserv/flowlogs-pipeline Length of output: 102 🏁 Script executed: # Get context around the shutdown code
cat -n cmd/flowlogs-pipeline/main.go | sed -n '230,260p'Repository: netobserv/flowlogs-pipeline Length of output: 1253 🏁 Script executed: # Find the gRPC service definition and StreamUpdates implementation
find . -type f -name "*.go" | xargs grep -l "StreamUpdates" | head -5Repository: netobserv/flowlogs-pipeline Length of output: 370 🏁 Script executed: # Check for any timeout configurations related to gRPC server
rg "GracefulStop|time\.After|context" cmd/flowlogs-pipeline/ -A 2 -B 2Repository: netobserv/flowlogs-pipeline Length of output: 889 🏁 Script executed: # Examine the gRPC service definition for StreamUpdates
cat -n pkg/pipeline/transform/kubernetes/k8scache/k8scache_grpc.pb.go | grep -A 20 "StreamUpdates"Repository: netobserv/flowlogs-pipeline Length of output: 7670 🏁 Script executed: # Also check the server.go implementation
cat -n pkg/pipeline/transform/kubernetes/k8scache/server.goRepository: netobserv/flowlogs-pipeline Length of output: 5814 Guard
Suggested change if grpcServer != nil {
log.Info("stopping K8s cache sync server")
- grpcServer.GracefulStop()
+ stopped := make(chan struct{})
+ go func() {
+ grpcServer.GracefulStop()
+ close(stopped)
+ }()
+ select {
+ case <-stopped:
+ case <-time.After(5 * time.Second):
+ log.Warn("timed out waiting for K8s cache sync streams to drain; forcing stop")
+ grpcServer.Stop()
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Give all threads a chance to exit and then exit the process | ||||||||||||||||||||||||||||||||||||
| time.Sleep(time.Second) | ||||||||||||||||||||||||||||||||||||
| log.Debugf("exiting main run") | ||||||||||||||||||||||||||||||||||||
| os.Exit(0) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // startK8sCacheServer initializes and starts the gRPC server for K8s cache synchronization | ||||||||||||||||||||||||||||||||||||
| // Returns nil if the datasource is not available (e.g., no kubernetes enrichment configured) | ||||||||||||||||||||||||||||||||||||
| func startK8sCacheServer(cfg *config.K8sCacheServer) *grpc.Server { | ||||||||||||||||||||||||||||||||||||
| // Check if kubernetes datasource is available | ||||||||||||||||||||||||||||||||||||
| ds := kubernetes.GetDatasource() | ||||||||||||||||||||||||||||||||||||
| if ds == nil { | ||||||||||||||||||||||||||||||||||||
| log.Warn("K8s cache server requested but kubernetes datasource not initialized. " + | ||||||||||||||||||||||||||||||||||||
| "Make sure kubernetes enrichment is configured in the pipeline.") | ||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Attach a Kubernetes store so the cache server can apply received updates; enrichment will use it for lookups | ||||||||||||||||||||||||||||||||||||
| ds.SetKubernetesStore(datasource.NewKubernetesStore()) | ||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Create cache server | ||||||||||||||||||||||||||||||||||||
| cacheServer := k8scache.NewKubernetesCacheServer(ds) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Create gRPC server with optional TLS | ||||||||||||||||||||||||||||||||||||
| var grpcServer *grpc.Server | ||||||||||||||||||||||||||||||||||||
| if cfg.TLSEnabled { | ||||||||||||||||||||||||||||||||||||
| tlsConfig, err := createServerTLSConfig(cfg) | ||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||
| log.WithError(err).Fatal("failed to configure TLS for K8s cache server") | ||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+274
to
+276
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unreachable code after
Suggested fix if cfg.TLSEnabled {
tlsConfig, err := createServerTLSConfig(cfg)
if err != nil {
- log.WithError(err).Fatal("failed to configure TLS for K8s cache server")
- return nil
+ log.WithError(err).Error("failed to configure TLS for K8s cache server")
+ os.Exit(1)
}Or simply remove 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
| grpcServer = grpc.NewServer(grpc.Creds(tlsConfig)) | ||||||||||||||||||||||||||||||||||||
| log.Info("K8s cache server TLS enabled") | ||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||
| grpcServer = grpc.NewServer() | ||||||||||||||||||||||||||||||||||||
| log.Warn("K8s cache server TLS disabled - connections are insecure (not recommended for production)") | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| k8scache.RegisterKubernetesCacheServiceServer(grpcServer, cacheServer) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Start listening | ||||||||||||||||||||||||||||||||||||
| address := fmt.Sprintf("%s:%d", cfg.Address, cfg.Port) | ||||||||||||||||||||||||||||||||||||
| listener, err := net.Listen("tcp", address) | ||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||
| log.WithError(err).WithField("address", address).Fatal("failed to start K8s cache server") | ||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+288
to
+291
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue: unreachable 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Start server in background | ||||||||||||||||||||||||||||||||||||
| go func() { | ||||||||||||||||||||||||||||||||||||
| log.WithField("address", address).Info("starting K8s cache sync server") | ||||||||||||||||||||||||||||||||||||
| if err := grpcServer.Serve(listener); err != nil { | ||||||||||||||||||||||||||||||||||||
| log.WithError(err).Error("K8s cache sync server stopped with error") | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| }() | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| return grpcServer | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // createServerTLSConfig creates TLS credentials for the gRPC server | ||||||||||||||||||||||||||||||||||||
| func createServerTLSConfig(cfg *config.K8sCacheServer) (credentials.TransportCredentials, error) { | ||||||||||||||||||||||||||||||||||||
| // Load server certificate and private key | ||||||||||||||||||||||||||||||||||||
| if cfg.TLSCertPath == "" || cfg.TLSKeyPath == "" { | ||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("TLS enabled but cert/key paths not provided") | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| cert, err := tls.LoadX509KeyPair(cfg.TLSCertPath, cfg.TLSKeyPath) | ||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to load server cert/key: %w", err) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| tlsConfig := &tls.Config{ | ||||||||||||||||||||||||||||||||||||
| Certificates: []tls.Certificate{cert}, | ||||||||||||||||||||||||||||||||||||
| ClientAuth: tls.NoClientCert, // Default: no client cert required | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+316
to
+319
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Set Without Suggested fix tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.NoClientCert, // Default: no client cert required
+ MinVersion: tls.VersionTLS12,
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // If CA is provided, require and verify client certificates | ||||||||||||||||||||||||||||||||||||
| if cfg.TLSCAPath != "" { | ||||||||||||||||||||||||||||||||||||
| caCert, err := os.ReadFile(cfg.TLSCAPath) | ||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to read CA cert: %w", err) | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| caCertPool := x509.NewCertPool() | ||||||||||||||||||||||||||||||||||||
| if !caCertPool.AppendCertsFromPEM(caCert) { | ||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to append CA cert") | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| tlsConfig.ClientCAs = caCertPool | ||||||||||||||||||||||||||||||||||||
| tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert | ||||||||||||||||||||||||||||||||||||
| log.Info("K8s cache server: mutual TLS enabled (client certificates required)") | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| return credentials.NewTLS(tlsConfig), nil | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: netobserv/flowlogs-pipeline
Length of output: 1048
Include TLS flags in the help output.
The code defines
--k8scache.tls-enabled,--k8scache.tls-cert-path,--k8scache.tls-key-path, and--k8scache.tls-ca-path, but the README only documents the address and port flags. Regenerate the help output to include all k8scache options.🤖 Prompt for AI Agents