github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/service-discovery/service_single_port_sd.go (about) 1 /* 2 Copyright 2022 The Katalyst Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package service_discovery 18 19 import ( 20 "context" 21 "fmt" 22 "net" 23 "time" 24 25 v1 "k8s.io/api/core/v1" 26 corelisters "k8s.io/client-go/listers/core/v1" 27 "k8s.io/client-go/tools/cache" 28 "k8s.io/klog/v2" 29 30 katalystbase "github.com/kubewharf/katalyst-core/cmd/base" 31 "github.com/kubewharf/katalyst-core/pkg/config/generic" 32 ) 33 34 func init() { 35 RegisterSDManagerInitializers(ServiceDiscoveryServiceSinglePort, NewServiceSinglePortSDManager) 36 } 37 38 const ServiceDiscoveryServiceSinglePort = "service-single-port" 39 40 type serviceSinglePortSDManager struct { 41 ctx context.Context 42 43 namespace string 44 name string 45 portName string 46 47 svcLister corelisters.ServiceLister 48 epLister corelisters.EndpointsLister 49 syncedFunc []cache.InformerSynced 50 } 51 52 func NewServiceSinglePortSDManager(ctx context.Context, agentCtx *katalystbase.GenericContext, 53 conf *generic.ServiceDiscoveryConf, 54 ) (ServiceDiscoveryManager, error) { 55 klog.Infof("%v sd manager enabled with conf: %+v", ServiceDiscoveryServiceSinglePort, conf.ServiceSinglePortSDConf) 56 svcInformer := agentCtx.KubeInformerFactory.Core().V1().Services() 57 epInformer := agentCtx.KubeInformerFactory.Core().V1().Endpoints() 58 59 s := &serviceSinglePortSDManager{ 60 ctx: ctx, 61 62 namespace: conf.ServiceSinglePortSDConf.Namespace, 63 name: conf.ServiceSinglePortSDConf.Name, 64 portName: conf.ServiceSinglePortSDConf.PortName, 65 66 epLister: epInformer.Lister(), 67 svcLister: svcInformer.Lister(), 68 syncedFunc: []cache.InformerSynced{ 69 svcInformer.Informer().HasSynced, 70 epInformer.Informer().HasSynced, 71 }, 72 } 73 return s, nil 74 } 75 76 func (s *serviceSinglePortSDManager) Name() string { return ServiceDiscoveryServiceSinglePort } 77 78 func (s *serviceSinglePortSDManager) GetEndpoints() ([]string, error) { 79 svc, err := s.svcLister.Services(s.namespace).Get(s.name) 80 if err != nil { 81 return nil, err 82 } 83 84 eps, err := s.epLister.Endpoints(s.namespace).Get(svc.Name) 85 if err != nil { 86 return nil, err 87 } 88 if len(eps.Subsets) == 0 { 89 return nil, fmt.Errorf("no endpoints available for service %q", svc.Name) 90 } 91 92 var res []string 93 for i := range eps.Subsets { 94 if urls, err := s.getValidAddresses(&eps.Subsets[i]); err != nil { 95 klog.Errorf("subsets %v get valid address err: %v", eps.Subsets[i].String(), err) 96 } else { 97 res = append(res, urls...) 98 } 99 } 100 return res, nil 101 } 102 103 func (s *serviceSinglePortSDManager) Run() error { 104 if !cache.WaitForCacheSync(s.ctx.Done(), s.syncedFunc...) { 105 return fmt.Errorf("unable to sync caches for podSinglePortSDManager") 106 } 107 return nil 108 } 109 110 func (s *serviceSinglePortSDManager) getValidAddresses(ss *v1.EndpointSubset) ([]string, error) { 111 results := make([]string, 0) 112 for i := range ss.Ports { 113 if ss.Ports[i].Name == s.portName { 114 for _, address := range ss.Addresses { 115 url := fmt.Sprintf("[%s]:%d", address.IP, ss.Ports[i].Port) 116 if conn, err := net.DialTimeout("tcp", url, time.Second*5); err == nil { 117 if conn != nil { 118 _ = conn.Close() 119 } 120 results = append(results, url) 121 } else { 122 klog.Errorf("dial %v failed: %v", url, err) 123 } 124 } 125 } 126 } 127 128 if len(results) == 0 { 129 return results, fmt.Errorf("no valid endpoint exists") 130 } else { 131 return results, nil 132 } 133 }