...

Source file src/k8s.io/kubernetes/pkg/proxy/ipvs/graceful_termination_test.go

Documentation: k8s.io/kubernetes/pkg/proxy/ipvs

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5  Copyright 2019 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package ipvs
    21  
    22  import (
    23  	"fmt"
    24  	"reflect"
    25  	"testing"
    26  
    27  	netutils "k8s.io/utils/net"
    28  
    29  	utilipvs "k8s.io/kubernetes/pkg/proxy/ipvs/util"
    30  	utilipvstest "k8s.io/kubernetes/pkg/proxy/ipvs/util/testing"
    31  )
    32  
    33  func Test_GracefulDeleteRS(t *testing.T) {
    34  	tests := []struct {
    35  		name         string
    36  		vs           *utilipvs.VirtualServer
    37  		rs           *utilipvs.RealServer
    38  		existingIPVS *utilipvstest.FakeIPVS
    39  		expectedIPVS *utilipvstest.FakeIPVS
    40  		err          error
    41  	}{
    42  		{
    43  			name: "graceful delete, no connections results in deleting the real server immediatetly",
    44  			vs: &utilipvs.VirtualServer{
    45  				Address:  netutils.ParseIPSloppy("1.1.1.1"),
    46  				Protocol: "tcp",
    47  				Port:     uint16(80),
    48  			},
    49  			rs: &utilipvs.RealServer{
    50  				Address:      netutils.ParseIPSloppy("10.0.0.1"),
    51  				Port:         uint16(80),
    52  				Weight:       100,
    53  				ActiveConn:   0,
    54  				InactiveConn: 0,
    55  			},
    56  			existingIPVS: &utilipvstest.FakeIPVS{
    57  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
    58  					{
    59  						IP:       "1.1.1.1",
    60  						Port:     80,
    61  						Protocol: "tcp",
    62  					}: {
    63  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
    64  						Protocol: "tcp",
    65  						Port:     uint16(80),
    66  					},
    67  				},
    68  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
    69  					{
    70  						IP:       "1.1.1.1",
    71  						Port:     80,
    72  						Protocol: "tcp",
    73  					}: {
    74  						{
    75  							Address:      netutils.ParseIPSloppy("10.0.0.1"),
    76  							Port:         uint16(80),
    77  							Weight:       100,
    78  							ActiveConn:   0,
    79  							InactiveConn: 0,
    80  						},
    81  					},
    82  				},
    83  			},
    84  			expectedIPVS: &utilipvstest.FakeIPVS{
    85  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
    86  					{
    87  						IP:       "1.1.1.1",
    88  						Port:     80,
    89  						Protocol: "tcp",
    90  					}: {
    91  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
    92  						Protocol: "tcp",
    93  						Port:     uint16(80),
    94  					},
    95  				},
    96  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
    97  					{
    98  						IP:       "1.1.1.1",
    99  						Port:     80,
   100  						Protocol: "tcp",
   101  					}: {},
   102  				},
   103  			},
   104  			err: nil,
   105  		},
   106  		{
   107  			name: "graceful delete, real server has active connections, weight should be 0 but don't delete",
   108  			vs: &utilipvs.VirtualServer{
   109  				Address:  netutils.ParseIPSloppy("1.1.1.1"),
   110  				Protocol: "tcp",
   111  				Port:     uint16(80),
   112  			},
   113  			rs: &utilipvs.RealServer{
   114  				Address:      netutils.ParseIPSloppy("10.0.0.1"),
   115  				Port:         uint16(80),
   116  				Weight:       100,
   117  				ActiveConn:   10,
   118  				InactiveConn: 0,
   119  			},
   120  			existingIPVS: &utilipvstest.FakeIPVS{
   121  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
   122  					{
   123  						IP:       "1.1.1.1",
   124  						Port:     80,
   125  						Protocol: "tcp",
   126  					}: {
   127  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
   128  						Protocol: "tcp",
   129  						Port:     uint16(80),
   130  					},
   131  				},
   132  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
   133  					{
   134  						IP:       "1.1.1.1",
   135  						Port:     80,
   136  						Protocol: "tcp",
   137  					}: {
   138  						{
   139  							Address:      netutils.ParseIPSloppy("10.0.0.1"),
   140  							Port:         uint16(80),
   141  							Weight:       100,
   142  							ActiveConn:   10,
   143  							InactiveConn: 0,
   144  						},
   145  					},
   146  				},
   147  			},
   148  			expectedIPVS: &utilipvstest.FakeIPVS{
   149  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
   150  					{
   151  						IP:       "1.1.1.1",
   152  						Port:     80,
   153  						Protocol: "tcp",
   154  					}: {
   155  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
   156  						Protocol: "tcp",
   157  						Port:     uint16(80),
   158  					},
   159  				},
   160  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
   161  					{
   162  						IP:       "1.1.1.1",
   163  						Port:     80,
   164  						Protocol: "tcp",
   165  					}: {
   166  						{
   167  							Address:      netutils.ParseIPSloppy("10.0.0.1"),
   168  							Port:         uint16(80),
   169  							Weight:       0,
   170  							ActiveConn:   10,
   171  							InactiveConn: 0,
   172  						},
   173  					},
   174  				},
   175  			},
   176  			err: nil,
   177  		},
   178  		{
   179  			name: "graceful delete, real server has in-active connections, weight should be 0 but don't delete",
   180  			vs: &utilipvs.VirtualServer{
   181  				Address:  netutils.ParseIPSloppy("1.1.1.1"),
   182  				Protocol: "tcp",
   183  				Port:     uint16(80),
   184  			},
   185  			rs: &utilipvs.RealServer{
   186  				Address:      netutils.ParseIPSloppy("10.0.0.1"),
   187  				Port:         uint16(80),
   188  				Weight:       100,
   189  				ActiveConn:   0,
   190  				InactiveConn: 10,
   191  			},
   192  			existingIPVS: &utilipvstest.FakeIPVS{
   193  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
   194  					{
   195  						IP:       "1.1.1.1",
   196  						Port:     80,
   197  						Protocol: "tcp",
   198  					}: {
   199  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
   200  						Protocol: "tcp",
   201  						Port:     uint16(80),
   202  					},
   203  				},
   204  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
   205  					{
   206  						IP:       "1.1.1.1",
   207  						Port:     80,
   208  						Protocol: "tcp",
   209  					}: {
   210  						{
   211  							Address:      netutils.ParseIPSloppy("10.0.0.1"),
   212  							Port:         uint16(80),
   213  							Weight:       100,
   214  							ActiveConn:   0,
   215  							InactiveConn: 10,
   216  						},
   217  					},
   218  				},
   219  			},
   220  			expectedIPVS: &utilipvstest.FakeIPVS{
   221  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
   222  					{
   223  						IP:       "1.1.1.1",
   224  						Port:     80,
   225  						Protocol: "tcp",
   226  					}: {
   227  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
   228  						Protocol: "tcp",
   229  						Port:     uint16(80),
   230  					},
   231  				},
   232  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
   233  					{
   234  						IP:       "1.1.1.1",
   235  						Port:     80,
   236  						Protocol: "tcp",
   237  					}: {
   238  						{
   239  							Address:      netutils.ParseIPSloppy("10.0.0.1"),
   240  							Port:         uint16(80),
   241  							Weight:       0,
   242  							ActiveConn:   0,
   243  							InactiveConn: 10,
   244  						},
   245  					},
   246  				},
   247  			},
   248  			err: nil,
   249  		},
   250  		{
   251  			name: "graceful delete, real server has connections, but udp connections are deleted immediately",
   252  			vs: &utilipvs.VirtualServer{
   253  				Address:  netutils.ParseIPSloppy("1.1.1.1"),
   254  				Protocol: "udp",
   255  				Port:     uint16(80),
   256  			},
   257  			rs: &utilipvs.RealServer{
   258  				Address:      netutils.ParseIPSloppy("10.0.0.1"),
   259  				Port:         uint16(80),
   260  				Weight:       100,
   261  				ActiveConn:   10,
   262  				InactiveConn: 10,
   263  			},
   264  			existingIPVS: &utilipvstest.FakeIPVS{
   265  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
   266  					{
   267  						IP:       "1.1.1.1",
   268  						Port:     80,
   269  						Protocol: "udp",
   270  					}: {
   271  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
   272  						Protocol: "udp",
   273  						Port:     uint16(80),
   274  					},
   275  				},
   276  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
   277  					{
   278  						IP:       "1.1.1.1",
   279  						Port:     80,
   280  						Protocol: "udp",
   281  					}: {
   282  						{
   283  							Address:      netutils.ParseIPSloppy("10.0.0.1"),
   284  							Port:         uint16(80),
   285  							Weight:       100,
   286  							ActiveConn:   10,
   287  							InactiveConn: 10,
   288  						},
   289  					},
   290  				},
   291  			},
   292  			expectedIPVS: &utilipvstest.FakeIPVS{
   293  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
   294  					{
   295  						IP:       "1.1.1.1",
   296  						Port:     80,
   297  						Protocol: "udp",
   298  					}: {
   299  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
   300  						Protocol: "udp",
   301  						Port:     uint16(80),
   302  					},
   303  				},
   304  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
   305  					{
   306  						IP:       "1.1.1.1",
   307  						Port:     80,
   308  						Protocol: "udp",
   309  					}: {}, // udp real server deleted immediately
   310  				},
   311  			},
   312  			err: nil,
   313  		},
   314  		{
   315  			name: "graceful delete, real server mismatch should be no-op",
   316  			vs: &utilipvs.VirtualServer{
   317  				Address:  netutils.ParseIPSloppy("1.1.1.1"),
   318  				Protocol: "tcp",
   319  				Port:     uint16(80),
   320  			},
   321  			rs: &utilipvs.RealServer{
   322  				Address:      netutils.ParseIPSloppy("10.0.0.1"),
   323  				Port:         uint16(81), // port mismatched
   324  				Weight:       100,
   325  				ActiveConn:   0,
   326  				InactiveConn: 10,
   327  			},
   328  			existingIPVS: &utilipvstest.FakeIPVS{
   329  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
   330  					{
   331  						IP:       "1.1.1.1",
   332  						Port:     80,
   333  						Protocol: "tcp",
   334  					}: {
   335  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
   336  						Protocol: "tcp",
   337  						Port:     uint16(80),
   338  					},
   339  				},
   340  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
   341  					{
   342  						IP:       "1.1.1.1",
   343  						Port:     80,
   344  						Protocol: "tcp",
   345  					}: {
   346  						{
   347  							Address:      netutils.ParseIPSloppy("10.0.0.1"),
   348  							Port:         uint16(80),
   349  							Weight:       100,
   350  							ActiveConn:   0,
   351  							InactiveConn: 10,
   352  						},
   353  					},
   354  				},
   355  			},
   356  			expectedIPVS: &utilipvstest.FakeIPVS{
   357  				Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{
   358  					{
   359  						IP:       "1.1.1.1",
   360  						Port:     80,
   361  						Protocol: "tcp",
   362  					}: {
   363  						Address:  netutils.ParseIPSloppy("1.1.1.1"),
   364  						Protocol: "tcp",
   365  						Port:     uint16(80),
   366  					},
   367  				},
   368  				Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{
   369  					{
   370  						IP:       "1.1.1.1",
   371  						Port:     80,
   372  						Protocol: "tcp",
   373  					}: {
   374  						{
   375  							Address:      netutils.ParseIPSloppy("10.0.0.1"),
   376  							Port:         uint16(80),
   377  							Weight:       100,
   378  							ActiveConn:   0,
   379  							InactiveConn: 10,
   380  						},
   381  					},
   382  				},
   383  			},
   384  			err: nil,
   385  		},
   386  	}
   387  
   388  	for _, test := range tests {
   389  		t.Run(test.name, func(t *testing.T) {
   390  			ipvs := test.existingIPVS
   391  			gracefulTerminationManager := NewGracefulTerminationManager(ipvs)
   392  
   393  			err := gracefulTerminationManager.GracefulDeleteRS(test.vs, test.rs)
   394  			if err != test.err {
   395  				t.Logf("actual err: %v", err)
   396  				t.Logf("expected err: %v", test.err)
   397  				t.Errorf("unexpected error")
   398  			}
   399  
   400  			if !reflect.DeepEqual(ipvs, test.expectedIPVS) {
   401  				t.Logf("actual: %+v", ipvs)
   402  				t.Logf("expected : %+v", test.expectedIPVS)
   403  				t.Errorf("unexpected IPVS servers")
   404  			}
   405  		})
   406  	}
   407  }
   408  
   409  func Test_RaceTerminateRSList(t *testing.T) {
   410  	ipvs := utilipvstest.NewFake()
   411  	gracefulTerminationManager := NewGracefulTerminationManager(ipvs)
   412  
   413  	// run in parallel to cause the race
   414  	go func() {
   415  		for i := 1; i <= 10; i++ {
   416  			for j := 1; j <= 100; j++ {
   417  				item := makeListItem(i, j)
   418  				gracefulTerminationManager.rsList.add(item)
   419  			}
   420  		}
   421  	}()
   422  
   423  	// wait until the list has some elements
   424  	for gracefulTerminationManager.rsList.len() < 20 {
   425  	}
   426  
   427  	// fake the handler to avoid the check against the IPVS virtual servers
   428  	fakeHandler := func(rsToDelete *listItem) (bool, error) {
   429  		return true, nil
   430  	}
   431  	if !gracefulTerminationManager.rsList.flushList(fakeHandler) {
   432  		t.Error("failed to flush entries")
   433  	}
   434  }
   435  
   436  func makeListItem(i, j int) *listItem {
   437  	vs := fmt.Sprintf("%d.%d.%d.%d", 1, 1, i, i)
   438  	rs := fmt.Sprintf("%d.%d.%d.%d", 1, 1, i, j)
   439  	return &listItem{
   440  		VirtualServer: &utilipvs.VirtualServer{
   441  			Address:  netutils.ParseIPSloppy(vs),
   442  			Protocol: "tcp",
   443  			Port:     uint16(80),
   444  		},
   445  		RealServer: &utilipvs.RealServer{
   446  			Address: netutils.ParseIPSloppy(rs),
   447  			Port:    uint16(80),
   448  		},
   449  	}
   450  }
   451  

View as plain text