k8s.io/kubernetes@v1.29.3/pkg/controller/endpointslicemirroring/reconciler_helpers.go (about) 1 /* 2 Copyright 2020 The Kubernetes 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 endpointslicemirroring 18 19 import ( 20 v1 "k8s.io/api/core/v1" 21 discovery "k8s.io/api/discovery/v1" 22 endpointsliceutil "k8s.io/endpointslice/util" 23 ) 24 25 // slicesByAction includes lists of slices to create, update, or delete. 26 type slicesByAction struct { 27 toCreate, toUpdate, toDelete []*discovery.EndpointSlice 28 } 29 30 // append appends slices from another slicesByAction struct. 31 func (s *slicesByAction) append(slices slicesByAction) { 32 s.toCreate = append(s.toCreate, slices.toCreate...) 33 s.toUpdate = append(s.toUpdate, slices.toUpdate...) 34 s.toDelete = append(s.toDelete, slices.toDelete...) 35 } 36 37 // totalsByAction includes total numbers for added and removed. 38 type totalsByAction struct { 39 added, updated, removed int 40 } 41 42 // add adds totals from another totalsByAction struct. 43 func (t *totalsByAction) add(totals totalsByAction) { 44 t.added += totals.added 45 t.updated += totals.updated 46 t.removed += totals.removed 47 } 48 49 // newDesiredCalc initializes and returns a new desiredCalc. 50 func newDesiredCalc() *desiredCalc { 51 return &desiredCalc{ 52 portsByKey: map[addrTypePortMapKey][]discovery.EndpointPort{}, 53 endpointsByKey: map[addrTypePortMapKey]endpointsliceutil.EndpointSet{}, 54 numDesiredEndpoints: 0, 55 } 56 } 57 58 // desiredCalc helps calculate desired endpoints and ports. 59 type desiredCalc struct { 60 portsByKey map[addrTypePortMapKey][]discovery.EndpointPort 61 endpointsByKey map[addrTypePortMapKey]endpointsliceutil.EndpointSet 62 numDesiredEndpoints int 63 } 64 65 // multiAddrTypePortMapKey stores addrTypePortMapKey for different address 66 // types. 67 type multiAddrTypePortMapKey map[discovery.AddressType]addrTypePortMapKey 68 69 // initPorts initializes ports for a subset and address type and returns the 70 // corresponding addrTypePortMapKey. 71 func (d *desiredCalc) initPorts(subsetPorts []v1.EndpointPort) multiAddrTypePortMapKey { 72 endpointPorts := epPortsToEpsPorts(subsetPorts) 73 addrTypes := []discovery.AddressType{discovery.AddressTypeIPv4, discovery.AddressTypeIPv6} 74 multiKey := multiAddrTypePortMapKey{} 75 76 for _, addrType := range addrTypes { 77 multiKey[addrType] = newAddrTypePortMapKey(endpointPorts, addrType) 78 if _, ok := d.endpointsByKey[multiKey[addrType]]; !ok { 79 d.endpointsByKey[multiKey[addrType]] = endpointsliceutil.EndpointSet{} 80 } 81 d.portsByKey[multiKey[addrType]] = endpointPorts 82 } 83 84 return multiKey 85 } 86 87 // addAddress adds an EndpointAddress to the desired state if it is valid. It 88 // returns false if the address was invalid. 89 func (d *desiredCalc) addAddress(address v1.EndpointAddress, multiKey multiAddrTypePortMapKey, ready bool) bool { 90 endpoint := addressToEndpoint(address, ready) 91 addrType := getAddressType(address.IP) 92 if addrType == nil { 93 return false 94 } 95 96 d.endpointsByKey[multiKey[*addrType]].Insert(endpoint) 97 d.numDesiredEndpoints++ 98 return true 99 } 100 101 type slicesByAddrType map[discovery.AddressType][]*discovery.EndpointSlice 102 103 // recycleSlices will recycle the slices marked for deletion by replacing 104 // creates with updates of slices that would otherwise be deleted. 105 func recycleSlices(slices *slicesByAction) { 106 toCreateByAddrType := toSlicesByAddrType(slices.toCreate) 107 toDeleteByAddrType := toSlicesByAddrType(slices.toDelete) 108 109 for addrType, slicesToCreate := range toCreateByAddrType { 110 slicesToDelete := toDeleteByAddrType[addrType] 111 for i := 0; len(slicesToCreate) > i && len(slicesToDelete) > i; i++ { 112 slices.toCreate = removeSlice(slices.toCreate, slicesToCreate[i]) 113 slices.toDelete = removeSlice(slices.toDelete, slicesToDelete[i]) 114 slice := slicesToCreate[i] 115 slice.Name = slicesToDelete[i].Name 116 slices.toUpdate = append(slices.toUpdate, slice) 117 } 118 } 119 } 120 121 // removeSlice removes an EndpointSlice from a list of EndpointSlices. 122 func removeSlice(slices []*discovery.EndpointSlice, sliceToRemove *discovery.EndpointSlice) []*discovery.EndpointSlice { 123 for i, slice := range slices { 124 if slice.Name == sliceToRemove.Name { 125 return append(slices[:i], slices[i+1:]...) 126 } 127 } 128 return slices 129 } 130 131 // toSliceByAddrType returns lists of EndpointSlices grouped by address. 132 func toSlicesByAddrType(slices []*discovery.EndpointSlice) slicesByAddrType { 133 byAddrType := slicesByAddrType{} 134 for _, slice := range slices { 135 byAddrType[slice.AddressType] = append(byAddrType[slice.AddressType], slice) 136 } 137 return byAddrType 138 }