github.com/imran-kn/cilium-fork@v1.6.9/pkg/k8s/endpoints.go (about) 1 // Copyright 2018-2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package k8s 16 17 import ( 18 "fmt" 19 "net" 20 "sort" 21 "strconv" 22 "strings" 23 24 "github.com/cilium/cilium/pkg/ip" 25 "github.com/cilium/cilium/pkg/k8s/types" 26 "github.com/cilium/cilium/pkg/loadbalancer" 27 "github.com/cilium/cilium/pkg/service" 28 ) 29 30 // Endpoints is an abstraction for the Kubernetes endpoints object. Endpoints 31 // consists of a set of backend IPs in combination with a set of ports and 32 // protocols. The name of the backend ports must match the names of the 33 // frontend ports of the corresponding service. 34 type Endpoints struct { 35 // Backends is a map containing all backend IPs and ports. The key to 36 // the map is the backend IP in string form. The value defines the list 37 // of ports for that backend IP in the form of a PortConfiguration. 38 Backends map[string]service.PortConfiguration 39 } 40 41 // String returns the string representation of an endpoints resource, with 42 // backends and ports sorted. 43 func (e *Endpoints) String() string { 44 if e == nil { 45 return "" 46 } 47 48 backends := []string{} 49 for ip, ports := range e.Backends { 50 for _, port := range ports { 51 backends = append(backends, fmt.Sprintf("%s/%s", net.JoinHostPort(ip, strconv.Itoa(int(port.Port))), port.Protocol)) 52 } 53 } 54 55 sort.Strings(backends) 56 57 return strings.Join(backends, ",") 58 } 59 60 // newEndpoints returns a new Endpoints 61 func newEndpoints() *Endpoints { 62 return &Endpoints{ 63 Backends: map[string]service.PortConfiguration{}, 64 } 65 } 66 67 // DeepEquals returns true if both endpoints are deep equal. 68 func (e *Endpoints) DeepEquals(o *Endpoints) bool { 69 switch { 70 case (e == nil) != (o == nil): 71 return false 72 case (e == nil) && (o == nil): 73 return true 74 } 75 76 if len(e.Backends) != len(o.Backends) { 77 return false 78 } 79 80 for ip1, ports1 := range e.Backends { 81 ports2, ok := o.Backends[ip1] 82 if !ok { 83 return false 84 } 85 86 if !ports1.DeepEquals(ports2) { 87 return false 88 } 89 } 90 91 return true 92 } 93 94 // CIDRPrefixes returns the endpoint's backends as a slice of IPNets. 95 func (e *Endpoints) CIDRPrefixes() ([]*net.IPNet, error) { 96 prefixes := make([]string, len(e.Backends)) 97 index := 0 98 for ip := range e.Backends { 99 prefixes[index] = ip 100 index++ 101 } 102 103 valid, invalid := ip.ParseCIDRs(prefixes) 104 if len(invalid) > 0 { 105 return nil, fmt.Errorf("invalid IPs specified as backends: %+v", invalid) 106 } 107 108 return valid, nil 109 } 110 111 // ParseEndpointsID parses a Kubernetes endpoints and returns the ServiceID 112 func ParseEndpointsID(svc *types.Endpoints) ServiceID { 113 return ServiceID{ 114 Name: svc.ObjectMeta.Name, 115 Namespace: svc.ObjectMeta.Namespace, 116 } 117 } 118 119 // ParseEndpoints parses a Kubernetes Endpoints resource 120 func ParseEndpoints(ep *types.Endpoints) (ServiceID, *Endpoints) { 121 endpoints := newEndpoints() 122 123 for _, sub := range ep.Subsets { 124 for _, addr := range sub.Addresses { 125 backend, ok := endpoints.Backends[addr.IP] 126 if !ok { 127 backend = service.PortConfiguration{} 128 endpoints.Backends[addr.IP] = backend 129 } 130 131 for _, port := range sub.Ports { 132 lbPort := loadbalancer.NewL4Addr(loadbalancer.L4Type(port.Protocol), uint16(port.Port)) 133 backend[port.Name] = lbPort 134 } 135 } 136 } 137 138 return ParseEndpointsID(ep), endpoints 139 } 140 141 // externalEndpoints is the collection of external endpoints in all remote 142 // clusters. The map key is the name of the remote cluster. 143 type externalEndpoints struct { 144 endpoints map[string]*Endpoints 145 } 146 147 // newExternalEndpoints returns a new ExternalEndpoints 148 func newExternalEndpoints() externalEndpoints { 149 return externalEndpoints{ 150 endpoints: map[string]*Endpoints{}, 151 } 152 }