...

Source file src/k8s.io/kubernetes/pkg/controlplane/controller/kubernetesservice/controller_test.go

Documentation: k8s.io/kubernetes/pkg/controlplane/controller/kubernetesservice

     1  /*
     2  Copyright 2014 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 kubernetesservice
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	corev1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/util/intstr"
    27  	v1informers "k8s.io/client-go/informers/core/v1"
    28  	"k8s.io/client-go/kubernetes/fake"
    29  	v1listers "k8s.io/client-go/listers/core/v1"
    30  	core "k8s.io/client-go/testing"
    31  	"k8s.io/client-go/tools/cache"
    32  	netutils "k8s.io/utils/net"
    33  )
    34  
    35  func TestCreateOrUpdateMasterService(t *testing.T) {
    36  	singleStack := corev1.IPFamilyPolicySingleStack
    37  	ns := metav1.NamespaceDefault
    38  	om := func(name string) metav1.ObjectMeta {
    39  		return metav1.ObjectMeta{Namespace: ns, Name: name}
    40  	}
    41  
    42  	createTests := []struct {
    43  		testName     string
    44  		serviceName  string
    45  		servicePorts []corev1.ServicePort
    46  		serviceType  corev1.ServiceType
    47  		expectCreate *corev1.Service // nil means none expected
    48  	}{
    49  		{
    50  			testName:    "service does not exist",
    51  			serviceName: "foo",
    52  			servicePorts: []corev1.ServicePort{
    53  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
    54  			},
    55  			serviceType: corev1.ServiceTypeClusterIP,
    56  			expectCreate: &corev1.Service{
    57  				ObjectMeta: om("foo"),
    58  				Spec: corev1.ServiceSpec{
    59  					Ports: []corev1.ServicePort{
    60  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
    61  					},
    62  					Selector:        nil,
    63  					ClusterIP:       "1.2.3.4",
    64  					IPFamilyPolicy:  &singleStack,
    65  					SessionAffinity: corev1.ServiceAffinityNone,
    66  					Type:            corev1.ServiceTypeClusterIP,
    67  				},
    68  			},
    69  		},
    70  	}
    71  	for _, test := range createTests {
    72  		t.Run(test.testName, func(t *testing.T) {
    73  			master := Controller{}
    74  			fakeClient := fake.NewSimpleClientset()
    75  			serviceStore := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
    76  			master.serviceLister = v1listers.NewServiceLister(serviceStore)
    77  			master.client = fakeClient
    78  			master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, netutils.ParseIPSloppy("1.2.3.4"), test.servicePorts, test.serviceType, false)
    79  			creates := []core.CreateAction{}
    80  			for _, action := range fakeClient.Actions() {
    81  				if action.GetVerb() == "create" {
    82  					creates = append(creates, action.(core.CreateAction))
    83  				}
    84  			}
    85  			if test.expectCreate != nil {
    86  				if len(creates) != 1 {
    87  					t.Errorf("case %q: unexpected creations: %v", test.testName, creates)
    88  				} else {
    89  					obj := creates[0].GetObject()
    90  					if e, a := test.expectCreate.Spec, obj.(*corev1.Service).Spec; !reflect.DeepEqual(e, a) {
    91  						t.Errorf("case %q: expected create:\n%#v\ngot:\n%#v\n", test.testName, e, a)
    92  					}
    93  				}
    94  			}
    95  			if test.expectCreate == nil && len(creates) > 1 {
    96  				t.Errorf("case %q: no create expected, yet saw: %v", test.testName, creates)
    97  			}
    98  		})
    99  	}
   100  
   101  	reconcileTests := []struct {
   102  		testName     string
   103  		serviceName  string
   104  		servicePorts []corev1.ServicePort
   105  		serviceType  corev1.ServiceType
   106  		service      *corev1.Service
   107  		expectUpdate *corev1.Service // nil means none expected
   108  	}{
   109  		{
   110  			testName:    "service definition wrong port",
   111  			serviceName: "foo",
   112  			servicePorts: []corev1.ServicePort{
   113  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   114  			},
   115  			serviceType: corev1.ServiceTypeClusterIP,
   116  			service: &corev1.Service{
   117  				ObjectMeta: om("foo"),
   118  				Spec: corev1.ServiceSpec{
   119  					Ports: []corev1.ServicePort{
   120  						{Name: "foo", Port: 8000, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   121  					},
   122  					Selector:        nil,
   123  					ClusterIP:       "1.2.3.4",
   124  					SessionAffinity: corev1.ServiceAffinityNone,
   125  					Type:            corev1.ServiceTypeClusterIP,
   126  				},
   127  			},
   128  			expectUpdate: &corev1.Service{
   129  				ObjectMeta: om("foo"),
   130  				Spec: corev1.ServiceSpec{
   131  					Ports: []corev1.ServicePort{
   132  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   133  					},
   134  					Selector:        nil,
   135  					ClusterIP:       "1.2.3.4",
   136  					SessionAffinity: corev1.ServiceAffinityNone,
   137  					Type:            corev1.ServiceTypeClusterIP,
   138  				},
   139  			},
   140  		},
   141  		{
   142  			testName:    "service definition missing port",
   143  			serviceName: "foo",
   144  			servicePorts: []corev1.ServicePort{
   145  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   146  				{Name: "baz", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt32(1000)},
   147  			},
   148  			serviceType: corev1.ServiceTypeClusterIP,
   149  			service: &corev1.Service{
   150  				ObjectMeta: om("foo"),
   151  				Spec: corev1.ServiceSpec{
   152  					Ports: []corev1.ServicePort{
   153  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   154  					},
   155  					Selector:        nil,
   156  					ClusterIP:       "1.2.3.4",
   157  					SessionAffinity: corev1.ServiceAffinityNone,
   158  					Type:            corev1.ServiceTypeClusterIP,
   159  				},
   160  			},
   161  			expectUpdate: &corev1.Service{
   162  				ObjectMeta: om("foo"),
   163  				Spec: corev1.ServiceSpec{
   164  					Ports: []corev1.ServicePort{
   165  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   166  						{Name: "baz", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt32(1000)},
   167  					},
   168  					Selector:        nil,
   169  					ClusterIP:       "1.2.3.4",
   170  					SessionAffinity: corev1.ServiceAffinityNone,
   171  					Type:            corev1.ServiceTypeClusterIP,
   172  				},
   173  			},
   174  		},
   175  		{
   176  			testName:    "service definition incorrect port",
   177  			serviceName: "foo",
   178  			servicePorts: []corev1.ServicePort{
   179  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   180  			},
   181  			serviceType: corev1.ServiceTypeClusterIP,
   182  			service: &corev1.Service{
   183  				ObjectMeta: om("foo"),
   184  				Spec: corev1.ServiceSpec{
   185  					Ports: []corev1.ServicePort{
   186  						{Name: "bar", Port: 1000, Protocol: "UDP", TargetPort: intstr.FromInt32(1000)},
   187  					},
   188  					Selector:        nil,
   189  					ClusterIP:       "1.2.3.4",
   190  					SessionAffinity: corev1.ServiceAffinityNone,
   191  					Type:            corev1.ServiceTypeClusterIP,
   192  				},
   193  			},
   194  			expectUpdate: &corev1.Service{
   195  				ObjectMeta: om("foo"),
   196  				Spec: corev1.ServiceSpec{
   197  					Ports: []corev1.ServicePort{
   198  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   199  					},
   200  					Selector:        nil,
   201  					ClusterIP:       "1.2.3.4",
   202  					SessionAffinity: corev1.ServiceAffinityNone,
   203  					Type:            corev1.ServiceTypeClusterIP,
   204  				},
   205  			},
   206  		},
   207  		{
   208  			testName:    "service definition incorrect port name",
   209  			serviceName: "foo",
   210  			servicePorts: []corev1.ServicePort{
   211  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   212  			},
   213  			serviceType: corev1.ServiceTypeClusterIP,
   214  			service: &corev1.Service{
   215  				ObjectMeta: om("foo"),
   216  				Spec: corev1.ServiceSpec{
   217  					Ports: []corev1.ServicePort{
   218  						{Name: "foo", Port: 1000, Protocol: "UDP", TargetPort: intstr.FromInt32(1000)},
   219  					},
   220  					Selector:        nil,
   221  					ClusterIP:       "1.2.3.4",
   222  					SessionAffinity: corev1.ServiceAffinityNone,
   223  					Type:            corev1.ServiceTypeClusterIP,
   224  				},
   225  			},
   226  			expectUpdate: &corev1.Service{
   227  				ObjectMeta: om("foo"),
   228  				Spec: corev1.ServiceSpec{
   229  					Ports: []corev1.ServicePort{
   230  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   231  					},
   232  					Selector:        nil,
   233  					ClusterIP:       "1.2.3.4",
   234  					SessionAffinity: corev1.ServiceAffinityNone,
   235  					Type:            corev1.ServiceTypeClusterIP,
   236  				},
   237  			},
   238  		},
   239  		{
   240  			testName:    "service definition incorrect target port",
   241  			serviceName: "foo",
   242  			servicePorts: []corev1.ServicePort{
   243  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   244  			},
   245  			serviceType: corev1.ServiceTypeClusterIP,
   246  			service: &corev1.Service{
   247  				ObjectMeta: om("foo"),
   248  				Spec: corev1.ServiceSpec{
   249  					Ports: []corev1.ServicePort{
   250  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(1000)},
   251  					},
   252  					Selector:        nil,
   253  					ClusterIP:       "1.2.3.4",
   254  					SessionAffinity: corev1.ServiceAffinityNone,
   255  					Type:            corev1.ServiceTypeClusterIP,
   256  				},
   257  			},
   258  			expectUpdate: &corev1.Service{
   259  				ObjectMeta: om("foo"),
   260  				Spec: corev1.ServiceSpec{
   261  					Ports: []corev1.ServicePort{
   262  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   263  					},
   264  					Selector:        nil,
   265  					ClusterIP:       "1.2.3.4",
   266  					SessionAffinity: corev1.ServiceAffinityNone,
   267  					Type:            corev1.ServiceTypeClusterIP,
   268  				},
   269  			},
   270  		},
   271  		{
   272  			testName:    "service definition incorrect protocol",
   273  			serviceName: "foo",
   274  			servicePorts: []corev1.ServicePort{
   275  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   276  			},
   277  			serviceType: corev1.ServiceTypeClusterIP,
   278  			service: &corev1.Service{
   279  				ObjectMeta: om("foo"),
   280  				Spec: corev1.ServiceSpec{
   281  					Ports: []corev1.ServicePort{
   282  						{Name: "foo", Port: 8080, Protocol: "UDP", TargetPort: intstr.FromInt32(8080)},
   283  					},
   284  					Selector:        nil,
   285  					ClusterIP:       "1.2.3.4",
   286  					SessionAffinity: corev1.ServiceAffinityNone,
   287  					Type:            corev1.ServiceTypeClusterIP,
   288  				},
   289  			},
   290  			expectUpdate: &corev1.Service{
   291  				ObjectMeta: om("foo"),
   292  				Spec: corev1.ServiceSpec{
   293  					Ports: []corev1.ServicePort{
   294  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   295  					},
   296  					Selector:        nil,
   297  					ClusterIP:       "1.2.3.4",
   298  					SessionAffinity: corev1.ServiceAffinityNone,
   299  					Type:            corev1.ServiceTypeClusterIP,
   300  				},
   301  			},
   302  		},
   303  		{
   304  			testName:    "service definition has incorrect type",
   305  			serviceName: "foo",
   306  			servicePorts: []corev1.ServicePort{
   307  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   308  			},
   309  			serviceType: corev1.ServiceTypeClusterIP,
   310  			service: &corev1.Service{
   311  				ObjectMeta: om("foo"),
   312  				Spec: corev1.ServiceSpec{
   313  					Ports: []corev1.ServicePort{
   314  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   315  					},
   316  					Selector:        nil,
   317  					ClusterIP:       "1.2.3.4",
   318  					SessionAffinity: corev1.ServiceAffinityNone,
   319  					Type:            corev1.ServiceTypeNodePort,
   320  				},
   321  			},
   322  			expectUpdate: &corev1.Service{
   323  				ObjectMeta: om("foo"),
   324  				Spec: corev1.ServiceSpec{
   325  					Ports: []corev1.ServicePort{
   326  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   327  					},
   328  					Selector:        nil,
   329  					ClusterIP:       "1.2.3.4",
   330  					SessionAffinity: corev1.ServiceAffinityNone,
   331  					Type:            corev1.ServiceTypeClusterIP,
   332  				},
   333  			},
   334  		},
   335  		{
   336  			testName:    "service definition satisfies",
   337  			serviceName: "foo",
   338  			servicePorts: []corev1.ServicePort{
   339  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   340  			},
   341  			serviceType: corev1.ServiceTypeClusterIP,
   342  			service: &corev1.Service{
   343  				ObjectMeta: om("foo"),
   344  				Spec: corev1.ServiceSpec{
   345  					Ports: []corev1.ServicePort{
   346  						{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   347  					},
   348  					Selector:        nil,
   349  					ClusterIP:       "1.2.3.4",
   350  					SessionAffinity: corev1.ServiceAffinityNone,
   351  					Type:            corev1.ServiceTypeClusterIP,
   352  				},
   353  			},
   354  			expectUpdate: nil,
   355  		},
   356  	}
   357  	for _, test := range reconcileTests {
   358  		t.Run(test.testName, func(t *testing.T) {
   359  			master := Controller{}
   360  			fakeClient := fake.NewSimpleClientset(test.service)
   361  			serviceInformer := v1informers.NewServiceInformer(fakeClient, metav1.NamespaceDefault, 12*time.Hour, cache.Indexers{})
   362  			serviceStore := serviceInformer.GetIndexer()
   363  			err := serviceStore.Add(test.service)
   364  			if err != nil {
   365  				t.Fatalf("unexpected error adding service %v to the store: %v", test.service, err)
   366  			}
   367  			master.serviceLister = v1listers.NewServiceLister(serviceStore)
   368  			master.client = fakeClient
   369  			err = master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, netutils.ParseIPSloppy("1.2.3.4"), test.servicePorts, test.serviceType, true)
   370  			if err != nil {
   371  				t.Errorf("case %q: unexpected error: %v", test.testName, err)
   372  			}
   373  			updates := []core.UpdateAction{}
   374  			for _, action := range fakeClient.Actions() {
   375  				if action.GetVerb() == "update" {
   376  					updates = append(updates, action.(core.UpdateAction))
   377  				}
   378  			}
   379  			if test.expectUpdate != nil {
   380  				if len(updates) != 1 {
   381  					t.Errorf("case %q: unexpected updates: %v", test.testName, updates)
   382  				} else {
   383  					obj := updates[0].GetObject()
   384  					if e, a := test.expectUpdate.Spec, obj.(*corev1.Service).Spec; !reflect.DeepEqual(e, a) {
   385  						t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
   386  					}
   387  				}
   388  			}
   389  			if test.expectUpdate == nil && len(updates) > 0 {
   390  				t.Errorf("case %q: no update expected, yet saw: %v", test.testName, updates)
   391  			}
   392  		})
   393  	}
   394  
   395  	nonReconcileTests := []struct {
   396  		testName     string
   397  		serviceName  string
   398  		servicePorts []corev1.ServicePort
   399  		serviceType  corev1.ServiceType
   400  		service      *corev1.Service
   401  		expectUpdate *corev1.Service // nil means none expected
   402  	}{
   403  		{
   404  			testName:    "service definition wrong port, no expected update",
   405  			serviceName: "foo",
   406  			servicePorts: []corev1.ServicePort{
   407  				{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)},
   408  			},
   409  			serviceType: corev1.ServiceTypeClusterIP,
   410  			service: &corev1.Service{
   411  				ObjectMeta: om("foo"),
   412  				Spec: corev1.ServiceSpec{
   413  					Ports: []corev1.ServicePort{
   414  						{Name: "foo", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt32(1000)},
   415  					},
   416  					Selector:        nil,
   417  					ClusterIP:       "1.2.3.4",
   418  					SessionAffinity: corev1.ServiceAffinityNone,
   419  					Type:            corev1.ServiceTypeClusterIP,
   420  				},
   421  			},
   422  			expectUpdate: nil,
   423  		},
   424  	}
   425  	for _, test := range nonReconcileTests {
   426  		t.Run(test.testName, func(t *testing.T) {
   427  			master := Controller{}
   428  			fakeClient := fake.NewSimpleClientset(test.service)
   429  			master.client = fakeClient
   430  			serviceInformer := v1informers.NewServiceInformer(fakeClient, metav1.NamespaceDefault, 12*time.Hour, cache.Indexers{})
   431  			serviceStore := serviceInformer.GetIndexer()
   432  			err := serviceStore.Add(test.service)
   433  			if err != nil {
   434  				t.Fatalf("unexpected error adding service %v to the store: %v", test.service, err)
   435  			}
   436  			master.serviceLister = v1listers.NewServiceLister(serviceStore)
   437  
   438  			err = master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, netutils.ParseIPSloppy("1.2.3.4"), test.servicePorts, test.serviceType, false)
   439  			if err != nil {
   440  				t.Errorf("case %q: unexpected error: %v", test.testName, err)
   441  			}
   442  			updates := []core.UpdateAction{}
   443  			for _, action := range fakeClient.Actions() {
   444  				if action.GetVerb() == "update" {
   445  					updates = append(updates, action.(core.UpdateAction))
   446  				}
   447  			}
   448  			if test.expectUpdate != nil {
   449  				if len(updates) != 1 {
   450  					t.Errorf("case %q: unexpected updates: %v", test.testName, updates)
   451  				} else {
   452  					obj := updates[0].GetObject()
   453  					if e, a := test.expectUpdate.Spec, obj.(*corev1.Service).Spec; !reflect.DeepEqual(e, a) {
   454  						t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
   455  					}
   456  				}
   457  			}
   458  			if test.expectUpdate == nil && len(updates) > 0 {
   459  				t.Errorf("case %q: no update expected, yet saw: %v", test.testName, updates)
   460  			}
   461  		})
   462  	}
   463  }
   464  

View as plain text