github.com/lingyao2333/mo-zero@v1.4.1/zrpc/resolver/internal/kubebuilder.go (about)

     1  package internal
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/lingyao2333/mo-zero/core/logx"
     9  	"github.com/lingyao2333/mo-zero/core/proc"
    10  	"github.com/lingyao2333/mo-zero/core/threading"
    11  	"github.com/lingyao2333/mo-zero/zrpc/resolver/internal/kube"
    12  	"google.golang.org/grpc/resolver"
    13  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/client-go/informers"
    15  	"k8s.io/client-go/kubernetes"
    16  	"k8s.io/client-go/rest"
    17  )
    18  
    19  const (
    20  	resyncInterval = 5 * time.Minute
    21  	nameSelector   = "metadata.name="
    22  )
    23  
    24  type kubeBuilder struct{}
    25  
    26  func (b *kubeBuilder) Build(target resolver.Target, cc resolver.ClientConn,
    27  	_ resolver.BuildOptions) (resolver.Resolver, error) {
    28  	svc, err := kube.ParseTarget(target)
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	config, err := rest.InClusterConfig()
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	cs, err := kubernetes.NewForConfig(config)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	handler := kube.NewEventHandler(func(endpoints []string) {
    44  		var addrs []resolver.Address
    45  		for _, val := range subset(endpoints, subsetSize) {
    46  			addrs = append(addrs, resolver.Address{
    47  				Addr: fmt.Sprintf("%s:%d", val, svc.Port),
    48  			})
    49  		}
    50  
    51  		if err := cc.UpdateState(resolver.State{
    52  			Addresses: addrs,
    53  		}); err != nil {
    54  			logx.Error(err)
    55  		}
    56  	})
    57  	inf := informers.NewSharedInformerFactoryWithOptions(cs, resyncInterval,
    58  		informers.WithNamespace(svc.Namespace),
    59  		informers.WithTweakListOptions(func(options *v1.ListOptions) {
    60  			options.FieldSelector = nameSelector + svc.Name
    61  		}))
    62  	in := inf.Core().V1().Endpoints()
    63  	in.Informer().AddEventHandler(handler)
    64  	threading.GoSafe(func() {
    65  		inf.Start(proc.Done())
    66  	})
    67  
    68  	endpoints, err := cs.CoreV1().Endpoints(svc.Namespace).Get(context.Background(), svc.Name, v1.GetOptions{})
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	handler.Update(endpoints)
    74  
    75  	return &nopResolver{cc: cc}, nil
    76  }
    77  
    78  func (b *kubeBuilder) Scheme() string {
    79  	return KubernetesScheme
    80  }