Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to EndpointSlices #154

Merged
merged 1 commit into from
Jul 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion pkg/cmd/infra/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ type RouterSelection struct {
ExtendedValidation bool

ListenAddr string

// WatchEndpoints when true will watch Endpoints instead of
// EndpointSlices.
WatchEndpoints bool
}

// Bind sets the appropriate labels
Expand All @@ -92,6 +96,7 @@ func (o *RouterSelection) Bind(flag *pflag.FlagSet) {
flag.Bool("enable-ingress", false, "Enable configuration via ingress resources.")
flag.MarkDeprecated("enable-ingress", "Ingress resources are now synchronized to routes automatically.")
flag.StringVar(&o.ListenAddr, "listen-addr", env("ROUTER_LISTEN_ADDR", ""), "The name of an interface to listen on to expose metrics and health checking. If not specified, will not listen. Overrides stats port.")
flag.BoolVar(&o.WatchEndpoints, "watch-endpoints", isTrue(env("ROUTER_WATCH_ENDPOINTS", "")), "Watch Endpoints instead of the EndpointSlice resource.")
}

// RouteUpdate updates the route before it is seen by the cache.
Expand Down Expand Up @@ -239,7 +244,7 @@ func (o *RouterSelection) Complete() error {

// NewFactory initializes a factory that will watch the requested routes
func (o *RouterSelection) NewFactory(routeclient routeclientset.Interface, projectclient projectclient.ProjectInterface, kc kclientset.Interface) *controllerfactory.RouterControllerFactory {
factory := controllerfactory.NewDefaultRouterControllerFactory(routeclient, projectclient, kc)
factory := controllerfactory.NewDefaultRouterControllerFactory(routeclient, projectclient, kc, o.WatchEndpoints)
factory.LabelSelector = o.LabelSelector
factory.FieldSelector = o.FieldSelector
factory.Namespace = o.Namespace
Expand Down
97 changes: 97 additions & 0 deletions pkg/router/controller/endpointsubset/sort_address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package endpointsubset

import (
"bytes"
"net"
"sort"
"strings"

kapi "k8s.io/api/core/v1"
)

type EndpointAddressCmpFunc func(x, y *kapi.EndpointAddress) int
type EndpointAddressLessFunc func(x, y *kapi.EndpointAddress) bool

type endpointAddressMultiSorter struct {
addresses []kapi.EndpointAddress
less []EndpointAddressLessFunc
}

var (
EndpointAddressHostnameCmpFn = func(x, y *kapi.EndpointAddress) int {
return strings.Compare(x.Hostname, y.Hostname)
}

EndpointAddressIPCmpFn = func(x, y *kapi.EndpointAddress) int {
return bytes.Compare(net.ParseIP(x.IP), net.ParseIP(y.IP))
}

EndpointAddressHostnameLessFn = func(x, y *kapi.EndpointAddress) bool {
return EndpointAddressHostnameCmpFn(x, y) < 0
}

EndpointAddressIPLessFn = func(x, y *kapi.EndpointAddress) bool {
return EndpointAddressIPCmpFn(x, y) < 0
}
)

var _ sort.Interface = &endpointAddressMultiSorter{}

// Sort sorts the argument slice according to the comparator functions
// passed to orderBy.
func (s *endpointAddressMultiSorter) Sort(addresses []kapi.EndpointAddress) {
s.addresses = addresses
sort.Sort(s)
}

// newEndpointAddressOrderBy returns a Sorter that sorts using a number
// of comparator functions.
func newEndpointAddressOrderBy(less ...EndpointAddressLessFunc) *endpointAddressMultiSorter {
return &endpointAddressMultiSorter{
less: less,
}
}

// Len is part of sort.Interface.
func (s *endpointAddressMultiSorter) Len() int {
return len(s.addresses)
}

// Swap is part of sort.Interface.
func (s *endpointAddressMultiSorter) Swap(i, j int) {
s.addresses[i], s.addresses[j] = s.addresses[j], s.addresses[i]
}

// Less is part of sort.Interface.
func (s *endpointAddressMultiSorter) Less(i, j int) bool {
p, q := s.addresses[i], s.addresses[j]

// Try all but the last comparison.
var k int
for k = 0; k < len(s.less)-1; k++ {
less := s.less[k]
switch {
case less(&p, &q):
return true
case less(&q, &p):
return false
}
// p == q; try the next comparison.
}

return s.less[k](&p, &q)
}

func DefaultEndpointAddressOrderByFuncs() []EndpointAddressLessFunc {
return []EndpointAddressLessFunc{
EndpointAddressIPLessFn,
EndpointAddressHostnameLessFn,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good to be prudent, but is there any reason to believe that an endpoint address can be non-unique?

}
}

func SortAddresses(addresses []kapi.EndpointAddress, orderByFuncs ...EndpointAddressLessFunc) {
if len(orderByFuncs) == 0 {
orderByFuncs = DefaultEndpointAddressOrderByFuncs()
}
newEndpointAddressOrderBy(orderByFuncs...).Sort(addresses)
}
104 changes: 104 additions & 0 deletions pkg/router/controller/endpointsubset/sort_port.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package endpointsubset

import (
"sort"
"strings"

kapi "k8s.io/api/core/v1"
)

type EndpointPortCmpFunc func(x, y *kapi.EndpointPort) int
type EndpointPortLessFunc func(x, y *kapi.EndpointPort) bool

type endpointPortMultiSorter struct {
ports []kapi.EndpointPort
less []EndpointPortLessFunc
}

var _ sort.Interface = &endpointPortMultiSorter{}

var (
EndpointPortNameCmpFn = func(x, y *kapi.EndpointPort) int {
return strings.Compare(x.Name, y.Name)
}

EndpointPortNameLessFn = func(x, y *kapi.EndpointPort) bool {
return EndpointPortNameCmpFn(x, y) < 0
}

EndpointPortNumberCmpFn = func(x, y *kapi.EndpointPort) int {
return int(x.Port - y.Port)
}

EndpointPortPortNumberLessFn = func(x, y *kapi.EndpointPort) bool {
return EndpointPortNumberCmpFn(x, y) < 0
}

EndpointPortProtocolCmpFn = func(x, y *kapi.EndpointPort) int {
return strings.Compare(string(x.Protocol), string(y.Protocol))
}

EndpointPortProtocolLessFn = func(x, y *kapi.EndpointPort) bool {
return EndpointPortProtocolCmpFn(x, y) < 0
}
)

// Sort sorts the argument slice according to the comparator functions
// passed to orderBy.
func (s *endpointPortMultiSorter) Sort(ports []kapi.EndpointPort) {
s.ports = ports
sort.Sort(s)
}

// endpointPortOrderBy returns a Sorter that sorts using a number
// of comparator functions.
func endpointPortOrderBy(less ...EndpointPortLessFunc) *endpointPortMultiSorter {
return &endpointPortMultiSorter{
less: less,
}
}

// Len is part of sort.Interface.
func (s *endpointPortMultiSorter) Len() int {
return len(s.ports)
}

// Swap is part of sort.Interface.
func (s *endpointPortMultiSorter) Swap(i, j int) {
s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
}

// Less is part of sort.Interface.
func (s *endpointPortMultiSorter) Less(i, j int) bool {
p, q := s.ports[i], s.ports[j]

// Try all but the last comparison.
var k int
for k = 0; k < len(s.less)-1; k++ {
less := s.less[k]
switch {
case less(&p, &q):
return true
case less(&q, &p):
return false
}
// p == q; try the next comparison.
}

return s.less[k](&p, &q)
}

func DefaultEndpointPortOrderByFuncs() []EndpointPortLessFunc {
return []EndpointPortLessFunc{
EndpointPortPortNumberLessFn,
EndpointPortProtocolLessFn,
EndpointPortNameLessFn,
}
}

func SortPorts(ports []kapi.EndpointPort, orderByFuncs ...EndpointPortLessFunc) {
if len(orderByFuncs) == 0 {
orderByFuncs = DefaultEndpointPortOrderByFuncs()
}
endpointPortOrderBy(orderByFuncs...).Sort(ports)
}