package main import ( "log" "git.k6n.net/mats/go-cart-actor/pkg/discovery" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" ) // GetDiscovery returns the k8s pod-watcher that finds peer profile replicas, or // nil when POD_IP is unset (single-node / local dev — clustering disabled). The // watch is scoped to this pod's own namespace so it only needs a namespaced Role // (pods: get/list/watch), not a cluster-wide role. func GetDiscovery() discovery.Discovery { if podIp == "" { return nil } config, kerr := rest.InClusterConfig() if kerr != nil { log.Fatalf("Error creating kubernetes client: %v\n", kerr) } client, err := kubernetes.NewForConfig(config) if err != nil { log.Fatalf("Error creating client: %v\n", err) } timeout := int64(30) return discovery.NewK8sDiscoveryInNamespace(client, discovery.InClusterNamespace(), v1.ListOptions{ LabelSelector: "actor-pool=profile", TimeoutSeconds: &timeout, }) } // UseDiscovery starts the watch loop that adds/removes peer hosts from the pool // as profile replicas become ready or go away. A nil discovery (POD_IP unset) // logs and returns, leaving the pool in single-node mode. func UseDiscovery(pool discovery.DiscoveryTarget) { go func(hw discovery.Discovery) { if hw == nil { log.Print("No discovery service available") return } ch, err := hw.Watch() if err != nil { log.Printf("Discovery error: %v", err) return } for evt := range ch { if evt.Host == "" { continue } switch evt.IsReady { case false: if pool.IsKnown(evt.Host) { log.Printf("Host %s is not ready, removing", evt.Host) pool.RemoveHost(evt.Host) } default: if !pool.IsKnown(evt.Host) { log.Printf("Discovered host %s", evt.Host) pool.AddRemoteHost(evt.Host) } } } }(GetDiscovery()) }