
- Increase the global level for broadcaster's logging to 3 so that users can ignore event messages by lowering the logging level. It reduces information noise. - Making sure the context is properly injected into the broadcaster, this will allow the -v flag value to be used also in that broadcaster, rather than the above global value. - test: use cancellation from ktesting - golangci-hints: checked error return value
604 lines
22 KiB
Go
604 lines
22 KiB
Go
/*
|
|
Copyright 2023 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package servicecidrs
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
v1 "k8s.io/api/core/v1"
|
|
networkingapiv1alpha1 "k8s.io/api/networking/v1alpha1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/informers"
|
|
"k8s.io/client-go/kubernetes/fake"
|
|
k8stesting "k8s.io/client-go/testing"
|
|
"k8s.io/client-go/tools/cache"
|
|
"k8s.io/kubernetes/pkg/controller"
|
|
"k8s.io/kubernetes/pkg/controlplane/controller/defaultservicecidr"
|
|
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
|
"k8s.io/kubernetes/test/utils/ktesting"
|
|
netutils "k8s.io/utils/net"
|
|
"k8s.io/utils/ptr"
|
|
)
|
|
|
|
type testController struct {
|
|
*Controller
|
|
servicecidrsStore cache.Store
|
|
ipaddressesStore cache.Store
|
|
}
|
|
|
|
func newController(ctx context.Context, t *testing.T, cidrs []*networkingapiv1alpha1.ServiceCIDR, ips []*networkingapiv1alpha1.IPAddress) (*fake.Clientset, *testController) {
|
|
client := fake.NewSimpleClientset()
|
|
|
|
informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
|
|
|
|
serviceCIDRInformer := informerFactory.Networking().V1alpha1().ServiceCIDRs()
|
|
cidrStore := serviceCIDRInformer.Informer().GetStore()
|
|
for _, obj := range cidrs {
|
|
err := cidrStore.Add(obj)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
ipAddressInformer := informerFactory.Networking().V1alpha1().IPAddresses()
|
|
ipStore := ipAddressInformer.Informer().GetStore()
|
|
for _, obj := range ips {
|
|
err := ipStore.Add(obj)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
controller := NewController(
|
|
ctx,
|
|
serviceCIDRInformer,
|
|
ipAddressInformer,
|
|
client)
|
|
|
|
var alwaysReady = func() bool { return true }
|
|
controller.serviceCIDRsSynced = alwaysReady
|
|
controller.ipAddressSynced = alwaysReady
|
|
|
|
return client, &testController{
|
|
controller,
|
|
cidrStore,
|
|
ipStore,
|
|
}
|
|
}
|
|
|
|
func TestControllerSync(t *testing.T) {
|
|
now := time.Now()
|
|
|
|
// ServiceCIDR that is just being deleted
|
|
deletingServiceCIDR := makeServiceCIDR("deleting-cidr", "192.168.0.0/24", "2001:db2::/64")
|
|
deletingServiceCIDR.Finalizers = []string{ServiceCIDRProtectionFinalizer}
|
|
deletingServiceCIDR.DeletionTimestamp = ptr.To[metav1.Time](metav1.Now())
|
|
|
|
// ServiceCIDR that has been deleted for longer than the deletionGracePeriod
|
|
deletedServiceCIDR := makeServiceCIDR("deleted-cidr", "192.168.0.0/24", "2001:db2::/64")
|
|
deletedServiceCIDR.Finalizers = []string{ServiceCIDRProtectionFinalizer}
|
|
deletedServiceCIDR.DeletionTimestamp = ptr.To[metav1.Time](metav1.NewTime(now.Add(-deletionGracePeriod - 1*time.Second)))
|
|
|
|
testCases := []struct {
|
|
name string
|
|
cidrs []*networkingapiv1alpha1.ServiceCIDR
|
|
ips []*networkingapiv1alpha1.IPAddress
|
|
cidrSynced string
|
|
actions [][]string // verb and resource and subresource
|
|
}{
|
|
{
|
|
name: "no existing service CIDRs",
|
|
},
|
|
{
|
|
name: "default service CIDR must have finalizer",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
cidrSynced: defaultservicecidr.DefaultServiceCIDRName,
|
|
actions: [][]string{{"patch", "servicecidrs", ""}, {"patch", "servicecidrs", "status"}},
|
|
},
|
|
{
|
|
name: "service CIDR must have finalizer",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR("no-finalizer", "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
cidrSynced: "no-finalizer",
|
|
actions: [][]string{{"patch", "servicecidrs", ""}, {"patch", "servicecidrs", "status"}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted must remove the finalizer",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", ""}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted but within the grace period must be requeued not remove the finalizer", // TODO: assert is actually requeued
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletingServiceCIDR,
|
|
},
|
|
cidrSynced: deletingServiceCIDR.Name,
|
|
actions: [][]string{},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted with IPv4 addresses should update the status",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.1"),
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", "status"}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted and overlapping same range and IPv4 addresses should remove the finalizer",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.1"),
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", ""}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted and overlapping and IPv4 addresses should remove the finalizer",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
makeServiceCIDR("overlapping", "192.168.0.0/16", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.1"),
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", ""}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted and not overlapping and IPv4 addresses should update the status",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
makeServiceCIDR("overlapping", "192.168.255.0/26", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.1"),
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", "status"}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted with IPv6 addresses should update the status",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("2001:db2::1"),
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", "status"}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted and overlapping same range and IPv6 addresses should remove the finalizer",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("2001:db2::1"),
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", ""}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted and overlapping and IPv6 addresses should remove the finalizer",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
makeServiceCIDR("overlapping", "192.168.0.0/16", "2001:db2::/48"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("2001:db2::1"),
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", ""}},
|
|
},
|
|
{
|
|
name: "service CIDR being deleted and not overlapping and IPv6 addresses should update the status",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
deletedServiceCIDR,
|
|
makeServiceCIDR("overlapping", "192.168.255.0/26", "2001:db2:a:b::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("2001:db2::1"),
|
|
},
|
|
cidrSynced: deletedServiceCIDR.Name,
|
|
actions: [][]string{{"patch", "servicecidrs", "status"}},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tCtx := ktesting.Init(t)
|
|
client, controller := newController(tCtx, t, tc.cidrs, tc.ips)
|
|
// server side apply does not play well with fake client go
|
|
// so we skup the errors and only assert on the actions
|
|
// https://github.com/kubernetes/kubernetes/issues/99953
|
|
_ = controller.sync(tCtx, tc.cidrSynced)
|
|
expectAction(t, client.Actions(), tc.actions)
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func makeServiceCIDR(name, primary, secondary string) *networkingapiv1alpha1.ServiceCIDR {
|
|
serviceCIDR := &networkingapiv1alpha1.ServiceCIDR{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
},
|
|
Spec: networkingapiv1alpha1.ServiceCIDRSpec{},
|
|
}
|
|
serviceCIDR.Spec.CIDRs = append(serviceCIDR.Spec.CIDRs, primary)
|
|
if secondary != "" {
|
|
serviceCIDR.Spec.CIDRs = append(serviceCIDR.Spec.CIDRs, secondary)
|
|
}
|
|
return serviceCIDR
|
|
}
|
|
|
|
func makeIPAddress(name string) *networkingapiv1alpha1.IPAddress {
|
|
family := string(v1.IPv4Protocol)
|
|
if netutils.IsIPv6String(name) {
|
|
family = string(v1.IPv6Protocol)
|
|
}
|
|
return &networkingapiv1alpha1.IPAddress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Labels: map[string]string{
|
|
networkingapiv1alpha1.LabelIPAddressFamily: family,
|
|
networkingapiv1alpha1.LabelManagedBy: ipallocator.ControllerName,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func expectAction(t *testing.T, actions []k8stesting.Action, expected [][]string) {
|
|
t.Helper()
|
|
if len(actions) != len(expected) {
|
|
t.Fatalf("Expected at least %d actions, got %d \ndiff: %v", len(expected), len(actions), cmp.Diff(expected, actions))
|
|
}
|
|
|
|
for i, action := range actions {
|
|
verb := expected[i][0]
|
|
if action.GetVerb() != verb {
|
|
t.Errorf("Expected action %d verb to be %s, got %s", i, verb, action.GetVerb())
|
|
}
|
|
resource := expected[i][1]
|
|
if action.GetResource().Resource != resource {
|
|
t.Errorf("Expected action %d resource to be %s, got %s", i, resource, action.GetResource().Resource)
|
|
}
|
|
subresource := expected[i][2]
|
|
if action.GetSubresource() != subresource {
|
|
t.Errorf("Expected action %d subresource to be %s, got %s", i, subresource, action.GetSubresource())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestController_canDeleteCIDR(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cidrs []*networkingapiv1alpha1.ServiceCIDR
|
|
ips []*networkingapiv1alpha1.IPAddress
|
|
cidrSynced *networkingapiv1alpha1.ServiceCIDR
|
|
want bool
|
|
}{
|
|
{
|
|
name: "empty",
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "CIDR and no IPs",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "CIDR with IPs",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.24"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "CIDR without IPs",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.1.24"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "CIDR with IPv4 address referencing the subnet address",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.0"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "CIDR with IPv4 address referencing the broadcast address",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.255"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "CIDR with IPv6 address referencing the broadcast address",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("2001:0db2::ffff:ffff:ffff:ffff"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "CIDR with same range overlapping and IPs",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.23"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "CIDR with smaller range overlapping and IPs",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/26", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.23"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "CIDR with smaller range overlapping but IPs orphan",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/28", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.23"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "CIDR with larger range overlapping and IPs",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/16", "2001:db2::/64"),
|
|
},
|
|
ips: []*networkingapiv1alpha1.IPAddress{
|
|
makeIPAddress("192.168.0.23"),
|
|
},
|
|
cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: true,
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tCtx := ktesting.Init(t)
|
|
_, controller := newController(tCtx, t, tc.cidrs, tc.ips)
|
|
err := controller.syncCIDRs()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := controller.canDeleteCIDR(tCtx, tc.cidrSynced)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("Controller.canDeleteCIDR() = %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestController_ipToCidrs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cidrs []*networkingapiv1alpha1.ServiceCIDR
|
|
ip *networkingapiv1alpha1.IPAddress
|
|
want []string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
ip: makeIPAddress("192.168.0.23"),
|
|
want: []string{},
|
|
}, {
|
|
name: "one CIDR",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
ip: makeIPAddress("192.168.0.23"),
|
|
want: []string{defaultservicecidr.DefaultServiceCIDRName},
|
|
}, {
|
|
name: "two equal CIDR",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/96"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
ip: makeIPAddress("192.168.0.23"),
|
|
want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping"},
|
|
}, {
|
|
name: "three CIDR - two same and one larger",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
ip: makeIPAddress("192.168.0.23"),
|
|
want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping", "overlapping2"},
|
|
}, {
|
|
name: "three CIDR - two same and one larger - IPv4 subnet address",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
ip: makeIPAddress("192.168.0.0"),
|
|
want: []string{},
|
|
}, {
|
|
name: "three CIDR - two same and one larger - IPv4 broadcast address",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
ip: makeIPAddress("192.168.0.63"), // broadcast for 192.168.0.0/26
|
|
want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping"},
|
|
}, {
|
|
name: "three CIDR - two same and one larger - IPv6 subnet address",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
ip: makeIPAddress("2001:db2::"),
|
|
want: []string{},
|
|
}, {
|
|
name: "three CIDR - two same and one larger - IPv6 broadcast address",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
ip: makeIPAddress("2001:0db2::ffff:ffff:ffff:ffff"),
|
|
want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping"},
|
|
}}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tCtx := ktesting.Init(t)
|
|
_, controller := newController(tCtx, t, tt.cidrs, nil)
|
|
err := controller.syncCIDRs()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := controller.containingServiceCIDRs(tt.ip); !cmp.Equal(got, tt.want, cmpopts.SortSlices(func(a, b string) bool { return a < b })) {
|
|
t.Errorf("Controller.ipToCidrs() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestController_cidrToCidrs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cidrs []*networkingapiv1alpha1.ServiceCIDR
|
|
cidr *networkingapiv1alpha1.ServiceCIDR
|
|
want []string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
cidr: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: []string{},
|
|
}, {
|
|
name: "one CIDR",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
cidr: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: []string{defaultservicecidr.DefaultServiceCIDRName},
|
|
}, {
|
|
name: "two equal CIDR",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/96"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
cidr: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping"},
|
|
}, {
|
|
name: "three CIDR - two same and one larger",
|
|
cidrs: []*networkingapiv1alpha1.ServiceCIDR{
|
|
makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
|
|
makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
|
|
makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
|
|
makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
|
|
},
|
|
cidr: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
|
|
want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping", "overlapping2"},
|
|
}}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tCtx := ktesting.Init(t)
|
|
_, controller := newController(tCtx, t, tt.cidrs, nil)
|
|
err := controller.syncCIDRs()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := controller.overlappingServiceCIDRs(tt.cidr); !cmp.Equal(got, tt.want, cmpopts.SortSlices(func(a, b string) bool { return a < b })) {
|
|
t.Errorf("Controller.cidrToCidrs() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|