k8s.io/kubernetes@v1.29.3/pkg/controller/servicecidrs/servicecidrs_controller_test.go (about)

     1  /*
     2  Copyright 2023 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 servicecidrs
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/google/go-cmp/cmp/cmpopts"
    26  	v1 "k8s.io/api/core/v1"
    27  	networkingapiv1alpha1 "k8s.io/api/networking/v1alpha1"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/client-go/informers"
    30  	"k8s.io/client-go/kubernetes/fake"
    31  	k8stesting "k8s.io/client-go/testing"
    32  	"k8s.io/client-go/tools/cache"
    33  	"k8s.io/kubernetes/pkg/controller"
    34  	"k8s.io/kubernetes/pkg/controlplane/controller/defaultservicecidr"
    35  	"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
    36  	netutils "k8s.io/utils/net"
    37  	"k8s.io/utils/ptr"
    38  )
    39  
    40  type testController struct {
    41  	*Controller
    42  	servicecidrsStore cache.Store
    43  	ipaddressesStore  cache.Store
    44  }
    45  
    46  func newController(t *testing.T, cidrs []*networkingapiv1alpha1.ServiceCIDR, ips []*networkingapiv1alpha1.IPAddress) (*fake.Clientset, *testController) {
    47  	client := fake.NewSimpleClientset()
    48  
    49  	informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
    50  
    51  	serviceCIDRInformer := informerFactory.Networking().V1alpha1().ServiceCIDRs()
    52  	cidrStore := serviceCIDRInformer.Informer().GetStore()
    53  	for _, obj := range cidrs {
    54  		err := cidrStore.Add(obj)
    55  		if err != nil {
    56  			t.Fatal(err)
    57  		}
    58  	}
    59  	ipAddressInformer := informerFactory.Networking().V1alpha1().IPAddresses()
    60  	ipStore := ipAddressInformer.Informer().GetStore()
    61  	for _, obj := range ips {
    62  		err := ipStore.Add(obj)
    63  		if err != nil {
    64  			t.Fatal(err)
    65  		}
    66  	}
    67  	controller := NewController(
    68  		serviceCIDRInformer,
    69  		ipAddressInformer,
    70  		client)
    71  
    72  	var alwaysReady = func() bool { return true }
    73  	controller.serviceCIDRsSynced = alwaysReady
    74  	controller.ipAddressSynced = alwaysReady
    75  
    76  	return client, &testController{
    77  		controller,
    78  		cidrStore,
    79  		ipStore,
    80  	}
    81  }
    82  
    83  func TestControllerSync(t *testing.T) {
    84  	now := time.Now()
    85  
    86  	// ServiceCIDR that is just being deleted
    87  	deletingServiceCIDR := makeServiceCIDR("deleting-cidr", "192.168.0.0/24", "2001:db2::/64")
    88  	deletingServiceCIDR.Finalizers = []string{ServiceCIDRProtectionFinalizer}
    89  	deletingServiceCIDR.DeletionTimestamp = ptr.To[metav1.Time](metav1.Now())
    90  
    91  	// ServiceCIDR that has been deleted for longer than the deletionGracePeriod
    92  	deletedServiceCIDR := makeServiceCIDR("deleted-cidr", "192.168.0.0/24", "2001:db2::/64")
    93  	deletedServiceCIDR.Finalizers = []string{ServiceCIDRProtectionFinalizer}
    94  	deletedServiceCIDR.DeletionTimestamp = ptr.To[metav1.Time](metav1.NewTime(now.Add(-deletionGracePeriod - 1*time.Second)))
    95  
    96  	testCases := []struct {
    97  		name       string
    98  		cidrs      []*networkingapiv1alpha1.ServiceCIDR
    99  		ips        []*networkingapiv1alpha1.IPAddress
   100  		cidrSynced string
   101  		actions    [][]string // verb and resource and subresource
   102  	}{
   103  		{
   104  			name: "no existing service CIDRs",
   105  		},
   106  		{
   107  			name: "default service CIDR must have finalizer",
   108  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   109  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   110  			},
   111  			cidrSynced: defaultservicecidr.DefaultServiceCIDRName,
   112  			actions:    [][]string{{"patch", "servicecidrs", ""}, {"patch", "servicecidrs", "status"}},
   113  		},
   114  		{
   115  			name: "service CIDR must have finalizer",
   116  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   117  				makeServiceCIDR("no-finalizer", "192.168.0.0/24", "2001:db2::/64"),
   118  			},
   119  			cidrSynced: "no-finalizer",
   120  			actions:    [][]string{{"patch", "servicecidrs", ""}, {"patch", "servicecidrs", "status"}},
   121  		},
   122  		{
   123  			name: "service CIDR being deleted must remove the finalizer",
   124  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   125  				deletedServiceCIDR,
   126  			},
   127  			cidrSynced: deletedServiceCIDR.Name,
   128  			actions:    [][]string{{"patch", "servicecidrs", ""}},
   129  		},
   130  		{
   131  			name: "service CIDR being deleted but within the grace period must be requeued not remove the finalizer", // TODO: assert is actually requeued
   132  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   133  				deletingServiceCIDR,
   134  			},
   135  			cidrSynced: deletingServiceCIDR.Name,
   136  			actions:    [][]string{},
   137  		},
   138  		{
   139  			name: "service CIDR being deleted with IPv4 addresses should update the status",
   140  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   141  				deletedServiceCIDR,
   142  			},
   143  			ips: []*networkingapiv1alpha1.IPAddress{
   144  				makeIPAddress("192.168.0.1"),
   145  			},
   146  			cidrSynced: deletedServiceCIDR.Name,
   147  			actions:    [][]string{{"patch", "servicecidrs", "status"}},
   148  		},
   149  		{
   150  			name: "service CIDR being deleted and overlapping same range and IPv4 addresses should remove the finalizer",
   151  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   152  				deletedServiceCIDR,
   153  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   154  			},
   155  			ips: []*networkingapiv1alpha1.IPAddress{
   156  				makeIPAddress("192.168.0.1"),
   157  			},
   158  			cidrSynced: deletedServiceCIDR.Name,
   159  			actions:    [][]string{{"patch", "servicecidrs", ""}},
   160  		},
   161  		{
   162  			name: "service CIDR being deleted and overlapping and IPv4 addresses should remove the finalizer",
   163  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   164  				deletedServiceCIDR,
   165  				makeServiceCIDR("overlapping", "192.168.0.0/16", "2001:db2::/64"),
   166  			},
   167  			ips: []*networkingapiv1alpha1.IPAddress{
   168  				makeIPAddress("192.168.0.1"),
   169  			},
   170  			cidrSynced: deletedServiceCIDR.Name,
   171  			actions:    [][]string{{"patch", "servicecidrs", ""}},
   172  		},
   173  		{
   174  			name: "service CIDR being deleted and not overlapping and IPv4 addresses should update the status",
   175  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   176  				deletedServiceCIDR,
   177  				makeServiceCIDR("overlapping", "192.168.255.0/26", "2001:db2::/64"),
   178  			},
   179  			ips: []*networkingapiv1alpha1.IPAddress{
   180  				makeIPAddress("192.168.0.1"),
   181  			},
   182  			cidrSynced: deletedServiceCIDR.Name,
   183  			actions:    [][]string{{"patch", "servicecidrs", "status"}},
   184  		},
   185  		{
   186  			name: "service CIDR being deleted with IPv6 addresses should update the status",
   187  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   188  				deletedServiceCIDR,
   189  			},
   190  			ips: []*networkingapiv1alpha1.IPAddress{
   191  				makeIPAddress("2001:db2::1"),
   192  			},
   193  			cidrSynced: deletedServiceCIDR.Name,
   194  			actions:    [][]string{{"patch", "servicecidrs", "status"}},
   195  		},
   196  		{
   197  			name: "service CIDR being deleted and overlapping same range and IPv6 addresses should remove the finalizer",
   198  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   199  				deletedServiceCIDR,
   200  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   201  			},
   202  			ips: []*networkingapiv1alpha1.IPAddress{
   203  				makeIPAddress("2001:db2::1"),
   204  			},
   205  			cidrSynced: deletedServiceCIDR.Name,
   206  			actions:    [][]string{{"patch", "servicecidrs", ""}},
   207  		},
   208  		{
   209  			name: "service CIDR being deleted and overlapping and IPv6 addresses should remove the finalizer",
   210  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   211  				deletedServiceCIDR,
   212  				makeServiceCIDR("overlapping", "192.168.0.0/16", "2001:db2::/48"),
   213  			},
   214  			ips: []*networkingapiv1alpha1.IPAddress{
   215  				makeIPAddress("2001:db2::1"),
   216  			},
   217  			cidrSynced: deletedServiceCIDR.Name,
   218  			actions:    [][]string{{"patch", "servicecidrs", ""}},
   219  		},
   220  		{
   221  			name: "service CIDR being deleted and not overlapping and IPv6 addresses should update the status",
   222  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   223  				deletedServiceCIDR,
   224  				makeServiceCIDR("overlapping", "192.168.255.0/26", "2001:db2:a:b::/64"),
   225  			},
   226  			ips: []*networkingapiv1alpha1.IPAddress{
   227  				makeIPAddress("2001:db2::1"),
   228  			},
   229  			cidrSynced: deletedServiceCIDR.Name,
   230  			actions:    [][]string{{"patch", "servicecidrs", "status"}},
   231  		},
   232  	}
   233  
   234  	for _, tc := range testCases {
   235  		t.Run(tc.name, func(t *testing.T) {
   236  			client, controller := newController(t, tc.cidrs, tc.ips)
   237  			// server side apply does not play well with fake client go
   238  			// so we skup the errors and only assert on the actions
   239  			// https://github.com/kubernetes/kubernetes/issues/99953
   240  			_ = controller.sync(context.Background(), tc.cidrSynced)
   241  			expectAction(t, client.Actions(), tc.actions)
   242  
   243  		})
   244  	}
   245  }
   246  
   247  func makeServiceCIDR(name, primary, secondary string) *networkingapiv1alpha1.ServiceCIDR {
   248  	serviceCIDR := &networkingapiv1alpha1.ServiceCIDR{
   249  		ObjectMeta: metav1.ObjectMeta{
   250  			Name: name,
   251  		},
   252  		Spec: networkingapiv1alpha1.ServiceCIDRSpec{},
   253  	}
   254  	serviceCIDR.Spec.CIDRs = append(serviceCIDR.Spec.CIDRs, primary)
   255  	if secondary != "" {
   256  		serviceCIDR.Spec.CIDRs = append(serviceCIDR.Spec.CIDRs, secondary)
   257  	}
   258  	return serviceCIDR
   259  }
   260  
   261  func makeIPAddress(name string) *networkingapiv1alpha1.IPAddress {
   262  	family := string(v1.IPv4Protocol)
   263  	if netutils.IsIPv6String(name) {
   264  		family = string(v1.IPv6Protocol)
   265  	}
   266  	return &networkingapiv1alpha1.IPAddress{
   267  		ObjectMeta: metav1.ObjectMeta{
   268  			Name: name,
   269  			Labels: map[string]string{
   270  				networkingapiv1alpha1.LabelIPAddressFamily: family,
   271  				networkingapiv1alpha1.LabelManagedBy:       ipallocator.ControllerName,
   272  			},
   273  		},
   274  	}
   275  }
   276  
   277  func expectAction(t *testing.T, actions []k8stesting.Action, expected [][]string) {
   278  	t.Helper()
   279  	if len(actions) != len(expected) {
   280  		t.Fatalf("Expected at least %d actions, got %d \ndiff: %v", len(expected), len(actions), cmp.Diff(expected, actions))
   281  	}
   282  
   283  	for i, action := range actions {
   284  		verb := expected[i][0]
   285  		if action.GetVerb() != verb {
   286  			t.Errorf("Expected action %d verb to be %s, got %s", i, verb, action.GetVerb())
   287  		}
   288  		resource := expected[i][1]
   289  		if action.GetResource().Resource != resource {
   290  			t.Errorf("Expected action %d resource to be %s, got %s", i, resource, action.GetResource().Resource)
   291  		}
   292  		subresource := expected[i][2]
   293  		if action.GetSubresource() != subresource {
   294  			t.Errorf("Expected action %d subresource to be %s, got %s", i, subresource, action.GetSubresource())
   295  		}
   296  	}
   297  }
   298  
   299  func TestController_canDeleteCIDR(t *testing.T) {
   300  	tests := []struct {
   301  		name       string
   302  		cidrs      []*networkingapiv1alpha1.ServiceCIDR
   303  		ips        []*networkingapiv1alpha1.IPAddress
   304  		cidrSynced *networkingapiv1alpha1.ServiceCIDR
   305  		want       bool
   306  	}{
   307  		{
   308  			name:       "empty",
   309  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   310  			want:       true,
   311  		},
   312  		{
   313  			name: "CIDR and no IPs",
   314  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   315  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   316  			},
   317  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   318  			want:       true,
   319  		},
   320  		{
   321  			name: "CIDR with IPs",
   322  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   323  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   324  			},
   325  			ips: []*networkingapiv1alpha1.IPAddress{
   326  				makeIPAddress("192.168.0.24"),
   327  			},
   328  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   329  			want:       false,
   330  		},
   331  		{
   332  			name: "CIDR without IPs",
   333  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   334  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   335  			},
   336  			ips: []*networkingapiv1alpha1.IPAddress{
   337  				makeIPAddress("192.168.1.24"),
   338  			},
   339  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   340  			want:       true,
   341  		},
   342  		{
   343  			name: "CIDR with IPv4 address referencing the subnet address",
   344  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   345  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   346  			},
   347  			ips: []*networkingapiv1alpha1.IPAddress{
   348  				makeIPAddress("192.168.0.0"),
   349  			},
   350  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   351  			want:       true,
   352  		},
   353  		{
   354  			name: "CIDR with IPv4 address referencing the broadcast address",
   355  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   356  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   357  			},
   358  			ips: []*networkingapiv1alpha1.IPAddress{
   359  				makeIPAddress("192.168.0.255"),
   360  			},
   361  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   362  			want:       true,
   363  		},
   364  		{
   365  			name: "CIDR with IPv6 address referencing the broadcast address",
   366  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   367  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   368  			},
   369  			ips: []*networkingapiv1alpha1.IPAddress{
   370  				makeIPAddress("2001:0db2::ffff:ffff:ffff:ffff"),
   371  			},
   372  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   373  			want:       false,
   374  		},
   375  		{
   376  			name: "CIDR with same range overlapping and IPs",
   377  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   378  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   379  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   380  			},
   381  			ips: []*networkingapiv1alpha1.IPAddress{
   382  				makeIPAddress("192.168.0.23"),
   383  			},
   384  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   385  			want:       true,
   386  		},
   387  		{
   388  			name: "CIDR with smaller range overlapping and IPs",
   389  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   390  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   391  				makeServiceCIDR("overlapping", "192.168.0.0/26", "2001:db2::/64"),
   392  			},
   393  			ips: []*networkingapiv1alpha1.IPAddress{
   394  				makeIPAddress("192.168.0.23"),
   395  			},
   396  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   397  			want:       true,
   398  		},
   399  		{
   400  			name: "CIDR with smaller range overlapping but IPs orphan",
   401  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   402  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   403  				makeServiceCIDR("overlapping", "192.168.0.0/28", "2001:db2::/64"),
   404  			},
   405  			ips: []*networkingapiv1alpha1.IPAddress{
   406  				makeIPAddress("192.168.0.23"),
   407  			},
   408  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   409  			want:       false,
   410  		},
   411  		{
   412  			name: "CIDR with larger range overlapping and IPs",
   413  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   414  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   415  				makeServiceCIDR("overlapping", "192.168.0.0/16", "2001:db2::/64"),
   416  			},
   417  			ips: []*networkingapiv1alpha1.IPAddress{
   418  				makeIPAddress("192.168.0.23"),
   419  			},
   420  			cidrSynced: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   421  			want:       true,
   422  		},
   423  	}
   424  	for _, tc := range tests {
   425  		t.Run(tc.name, func(t *testing.T) {
   426  			_, controller := newController(t, tc.cidrs, tc.ips)
   427  			err := controller.syncCIDRs()
   428  			if err != nil {
   429  				t.Fatal(err)
   430  			}
   431  
   432  			got, err := controller.canDeleteCIDR(context.Background(), tc.cidrSynced)
   433  			if err != nil {
   434  				t.Fatal(err)
   435  			}
   436  			if got != tc.want {
   437  				t.Errorf("Controller.canDeleteCIDR() = %v, want %v", got, tc.want)
   438  			}
   439  		})
   440  	}
   441  }
   442  
   443  func TestController_ipToCidrs(t *testing.T) {
   444  	tests := []struct {
   445  		name  string
   446  		cidrs []*networkingapiv1alpha1.ServiceCIDR
   447  		ip    *networkingapiv1alpha1.IPAddress
   448  		want  []string
   449  	}{
   450  		{
   451  			name: "empty",
   452  			ip:   makeIPAddress("192.168.0.23"),
   453  			want: []string{},
   454  		}, {
   455  			name: "one CIDR",
   456  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   457  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   458  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   459  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   460  			},
   461  			ip:   makeIPAddress("192.168.0.23"),
   462  			want: []string{defaultservicecidr.DefaultServiceCIDRName},
   463  		}, {
   464  			name: "two equal CIDR",
   465  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   466  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   467  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/96"),
   468  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   469  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   470  			},
   471  			ip:   makeIPAddress("192.168.0.23"),
   472  			want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping"},
   473  		}, {
   474  			name: "three CIDR - two same and one larger",
   475  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   476  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   477  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   478  				makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
   479  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   480  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   481  			},
   482  			ip:   makeIPAddress("192.168.0.23"),
   483  			want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping", "overlapping2"},
   484  		}, {
   485  			name: "three CIDR - two same and one larger - IPv4 subnet address",
   486  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   487  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   488  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   489  				makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
   490  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   491  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   492  			},
   493  			ip:   makeIPAddress("192.168.0.0"),
   494  			want: []string{},
   495  		}, {
   496  			name: "three CIDR - two same and one larger - IPv4 broadcast address",
   497  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   498  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   499  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   500  				makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
   501  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   502  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   503  			},
   504  			ip:   makeIPAddress("192.168.0.63"), // broadcast for 192.168.0.0/26
   505  			want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping"},
   506  		}, {
   507  			name: "three CIDR - two same and one larger - IPv6 subnet address",
   508  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   509  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   510  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   511  				makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
   512  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   513  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   514  			},
   515  			ip:   makeIPAddress("2001:db2::"),
   516  			want: []string{},
   517  		}, {
   518  			name: "three CIDR - two same and one larger - IPv6 broadcast address",
   519  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   520  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   521  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   522  				makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
   523  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   524  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   525  			},
   526  			ip:   makeIPAddress("2001:0db2::ffff:ffff:ffff:ffff"),
   527  			want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping"},
   528  		}}
   529  	for _, tt := range tests {
   530  		t.Run(tt.name, func(t *testing.T) {
   531  			_, controller := newController(t, tt.cidrs, nil)
   532  			err := controller.syncCIDRs()
   533  			if err != nil {
   534  				t.Fatal(err)
   535  			}
   536  			if got := controller.containingServiceCIDRs(tt.ip); !cmp.Equal(got, tt.want, cmpopts.SortSlices(func(a, b string) bool { return a < b })) {
   537  				t.Errorf("Controller.ipToCidrs() = %v, want %v", got, tt.want)
   538  			}
   539  		})
   540  	}
   541  }
   542  
   543  func TestController_cidrToCidrs(t *testing.T) {
   544  	tests := []struct {
   545  		name  string
   546  		cidrs []*networkingapiv1alpha1.ServiceCIDR
   547  		cidr  *networkingapiv1alpha1.ServiceCIDR
   548  		want  []string
   549  	}{
   550  		{
   551  			name: "empty",
   552  			cidr: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   553  			want: []string{},
   554  		}, {
   555  			name: "one CIDR",
   556  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   557  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   558  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   559  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   560  			},
   561  			cidr: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   562  			want: []string{defaultservicecidr.DefaultServiceCIDRName},
   563  		}, {
   564  			name: "two equal CIDR",
   565  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   566  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   567  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/96"),
   568  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   569  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   570  			},
   571  			cidr: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   572  			want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping"},
   573  		}, {
   574  			name: "three CIDR - two same and one larger",
   575  			cidrs: []*networkingapiv1alpha1.ServiceCIDR{
   576  				makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   577  				makeServiceCIDR("overlapping", "192.168.0.0/24", "2001:db2::/64"),
   578  				makeServiceCIDR("overlapping2", "192.168.0.0/26", "2001:db2::/96"),
   579  				makeServiceCIDR("unrelated", "10.0.0.0/24", ""),
   580  				makeServiceCIDR("unrelated2", "10.0.0.0/16", ""),
   581  			},
   582  			cidr: makeServiceCIDR(defaultservicecidr.DefaultServiceCIDRName, "192.168.0.0/24", "2001:db2::/64"),
   583  			want: []string{defaultservicecidr.DefaultServiceCIDRName, "overlapping", "overlapping2"},
   584  		}}
   585  	for _, tt := range tests {
   586  		t.Run(tt.name, func(t *testing.T) {
   587  			_, controller := newController(t, tt.cidrs, nil)
   588  			err := controller.syncCIDRs()
   589  			if err != nil {
   590  				t.Fatal(err)
   591  			}
   592  			if got := controller.overlappingServiceCIDRs(tt.cidr); !cmp.Equal(got, tt.want, cmpopts.SortSlices(func(a, b string) bool { return a < b })) {
   593  				t.Errorf("Controller.cidrToCidrs() = %v, want %v", got, tt.want)
   594  			}
   595  		})
   596  	}
   597  }